/* ==========================================================================
   迪粉社区 DiFansClub · 视觉主题层 v6「小艺 Work 官固风格」
   --------------------------------------------------------------------------
   定位：纯覆盖层。不改任何 HTML 结构与 class 名，只在 app.css / archive.css
        之后重定义 token 与组件视觉；整文件删除即可回滚到「工业档案室」。
   加载顺序：app.css → archive.css → admin-next.css → mobile-app.css → theme-xiaoyi.css

   方向（Direction Lock，提取自 xiaoyi.huawei.com/work）
     · 主色：华为纯蓝 #111111（ColorAccent-1），辅 #111111 / #5291FF
     · 大面积白底 + 浅灰区块 #f5f5f5，层次靠「面 + 柔和阴影」而非「线」
     · 胶囊按钮（border-radius:999px）+ 大圆角卡片（16/24px）
     · 玻璃拟态：白底半透明 + backdrop-blur + 内高光（--glass-shadow）
     · harmony 多彩渐变图标（蓝 / 紫粉 / 金橙 / 青绿）
     · 顶部吸顶玻璃导航 + 底部黑色星空页脚（深浅反差）
     · 字体：HarmonyOS Sans / 鸿蒙黑体（回退 PingFang / 微软雅黑）
   ========================================================================== */

/* ==========================================================================
   X1. Tokens（覆盖 archive.css A1）
   ========================================================================== */
:root {
  /* —— 字体：鸿蒙黑体优先 —— */
  --font-display: "HarmonyOS Sans SC", "HarmonyHeiTi", "PingFang SC", "Microsoft YaHei", "Noto Sans SC", sans-serif;
  --font-body: "HarmonyOS Sans SC", "HarmonyHeiTi", "PingFang SC", "Microsoft YaHei", "Noto Sans SC", sans-serif;
  --font-mono: "HarmonyOS Sans SC", "JetBrains Mono", "IBM Plex Mono", Consolas, "Courier New", monospace;
  --mono: var(--font-mono);

  /* —— 中性色：黑字三级 + 白灰面 —— */
  --ink: #111111;        /* 近黑主文字（black 90） */
  --ink-2: #4b4b4b;      /* 次文字（black 60） */
  --ink-3: #666666;      /* 弱文字（black 40） */
  --ink-4: #b0b0b0;      /* 仅装饰 */

  --paper: #ffffff;      /* 页面底色 */
  --paper-2: #f5f5f5;    /* 次级面（ColorGray-3） */
  --paper-3: var(--gray-wash);    /* 三级面，与全站灰底统一 */
  --gray-wash: #f5f5f5;  /* 全站灰底 / 未选中项 */
  --select-wash: #e8e8e8; /* 全站选中 / 悬浮底色 */
  --seg-bg: #ffffff;      /* 分段 / Tab / chips 槽底（B′ 白底槽） */
  --seg-hover: #efefef;   /* 槽内项悬停：比槽底加深一档 */
  --page-gap: 16px;       /* 页面内块间距（分组/工具条与相邻内容的上下间距） */

  --rule: rgba(0, 0, 0, .08);
  --rule-2: rgba(0, 0, 0, .12);
  --rule-3: rgba(0, 0, 0, .2);

  /* —— 品牌：华为蓝 —— */
  --brand: #111111;
  --select-solid: #111111;
  --select-solid-hover: #2a2a2a;
  --select-solid-ink: #ffffff;
  --brand-ink: #000000;
  --btn-ink: #ffffff;
  --btn-danger-bg: #c62828;
  --brand-wash: var(--select-wash);
  --brand-blue: #111111;
  --brand-blue-wash: var(--select-wash);

  --blue: var(--brand);
  --blue-ink: var(--brand-ink);
  --blue-wash: var(--brand-wash);

  --amber: #b45309;
  --amber-wash: #fdf4e7;
  --green: #157f3d;
  --green-wash: #e9f7ee;
  --red: #c62828;
  --red-wash: #fdecec;

  /* 兼容旧变量名 */
  --acc: var(--blue);
  --acc-h: var(--blue-ink);
  --acc-2: #6a2bf0;
  --accent: var(--blue);
  --text: var(--ink);
  --dim: var(--ink-2);
  --faint: var(--ink-3);
  --text-dim: var(--ink-2);
  --bg: var(--paper);
  --panel: #ffffff;
  --panel-2: var(--paper);
  --panel-3: var(--paper-2);
  --line: var(--rule);
  --line-2: var(--rule-2);
  --border: var(--rule);
  --ok: var(--green);
  --warn: var(--amber);
  --err: var(--red);
  --success: var(--green);
  --warning: var(--amber);
  --danger: var(--red);

  /* —— 渐变：蓝→紫品牌渐变 + 多彩点缀 —— */
  --grad: linear-gradient(135deg, #111111, #3a3a3a);
  --grad-deep: linear-gradient(135deg, #111111 10%, #6a2bf0 95%);
  /* 缩略图 / 功能块用的色阶（2026-10-04 升级为三段渐变）。
     旧值是「同色系两个近似色」（如蓝 #3a3a3a→#63aaff，色差仅 6%），
     肉眼看过去几乎是纯色，缺少高级感。
     新值规律：同色相、饱和度与明度拉开（左上更深更艳 → 右下更亮），
     135° 斜向，正好呼应卡片左上角到右下角的光感。 */
  --grad-blue: linear-gradient(135deg, #1f6feb 0%, #4a9bff 55%, #7cc4ff 100%);
  --grad-violet: linear-gradient(135deg, #7c3aed 0%, #a855f7 55%, #d18bff 100%);
  --grad-pink: linear-gradient(135deg, #db2777 0%, #f472b6 55%, #ffa8d4 100%);
  --grad-gold: linear-gradient(135deg, #f59e0b 0%, #fbbf24 55%, #fde68a 100%);
  --grad-teal: linear-gradient(135deg, #0d9488 0%, #14b8a6 55%, #5eead4 100%);

  /* —— 圆角：卡片化 + 胶囊 —— */
  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-pill: 999px;

  /* —— 阴影：玻璃拟态（内高光）+ 柔和三级 —— */
  --glass-shadow: 0 8px 24px rgba(0, 0, 0, .08), inset 0 1px 0 hsla(0, 0%, 100%, .7);
  --shadow: 0 2px 8px rgba(17, 17, 17, .06);
  --shadow-md: 0 8px 28px rgba(17, 17, 17, .12);
  --shadow-lg: 0 24px 64px rgba(17, 17, 17, .18);

  /* —— 栅格节奏 —— */
  --gutter: 20px;
  --measure: 1200px;
  --shell-pad: 28px;
}

/* —— 深色主题 —— */
[data-theme="dark"] {
  --ink: #f5f5f5;
  --ink-2: #b8b8b8;
  --ink-3: #a3a3a3;
  --ink-4: #8a8a8a;

  --paper: #0b0b0c;
  --paper-2: #1e1e1e;
  --paper-3: #242424;
  --gray-wash: #1e1e1e;
  --select-wash: #333333;
  --seg-bg: #242424;
  --seg-hover: #2e2e2e;

  --rule: rgba(255, 255, 255, .08);
  --rule-2: rgba(255, 255, 255, .14);
  --rule-3: rgba(255, 255, 255, .24);

  --brand: #f5f5f5;
  --select-solid: #f5f5f5;
  --select-solid-hover: #e5e5e5;
  --select-solid-ink: #0b0b0c;
  --brand-ink: #cfcfcf;
  --btn-ink: #0b0b0c;
  --btn-danger-bg: #b91c1c;
  --brand-wash: var(--select-wash);
  --brand-blue: #f5f5f5;
  --brand-blue-wash: var(--select-wash);

  --panel: #1e1e1e;
  --panel-2: #0b0b0c;
  --panel-3: #242424;
  --bg: #0b0b0c;

  --green: #5fc98a;
  --green-wash: #0f2117;
  --amber: #e0a458;
  --amber-wash: #241b0e;
  --red: #f08080;
  --red-wash: #2a1212;

  --acc: var(--blue);
  --accent: var(--blue);
  --shadow: 0 2px 8px rgba(0, 0, 0, .35);
  --shadow-md: 0 8px 28px rgba(0, 0, 0, .45);
  --shadow-lg: 0 24px 64px rgba(0, 0, 0, .55);
  --glass-shadow: 0 8px 24px rgba(0, 0, 0, .4), inset 0 1px 0 rgba(255, 255, 255, .08);
}

/* ==========================================================================
   X2. Base：底色 / 字体 / 氛围光晕
   ========================================================================== */
/* 全局禁止横向滚动：首页通栏用 50vw 突破容器，vw 含滚动条宽度会溢出十几像素 */
/* scrollbar-gutter: stable —— 始终为滚动条预留位置，页面宽度不随内容长短变化。
   否则刷新时滚动条出现/消失会让居中内容（含固定顶栏右侧的登录按钮）左右跳动。 */
html { overflow-x: hidden; scrollbar-gutter: stable; }
/* 2026-10-04 背景重写：html/body 背景。
   ⚠️ 这里**不能**简单设成transparent —— 2026-10-04 一次改错导致：
   光场 .bgflow 用 z-index:0，而 body 背景会传播到根画布，
   二者叠加后光场在认证页正常、在内容页把 body 底色一起带走，
   页面出现"没有底色"的空洞。
   现在改为：body 保留**纯色底**（var(--paper)）作为所有页面的兜底，
   光场在其上叠加（z-index:0 在 body 背景之上），
   不显示光场的页面（社区/固件/协议…）就是干净的纯色底。 */
html { background: var(--paper); }
body {
  overflow-x: hidden; padding-right: var(--sbw, 0px);
  background: var(--paper);
}
/* 全局兜底：任何带 hidden 属性的元素都必须真正隐藏
   （.btn 等类选择器设了 display，会覆盖 UA 的 [hidden]{display:none}） */
[hidden] { display: none !important; }

body {
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.7;
  color: var(--ink);
  background: var(--paper);
  /* 旧的两层 radial-gradient 顶部冷蓝光已删除（2026-10-04）——
     改由 .bgflow 的五团流动光+ 基底渐变统一承担，避免两套背景叠加发灰。 */
}
/* 2026-10-04 背景重写：body 背景已透明化（原 dark 主题的两层 radial-gradient
   顶部蓝光一并删除），暗色底色改由 .bgflow 的 [data-theme="dark"] 变体承担。 */

h1, h2, h3, h4, h5, .display {
  font-family: var(--font-display);
  letter-spacing: -.02em;
  line-height: 1.2;
}

/* 无障碍「跳转主内容」链接：默认藏到屏幕外，仅键件聚焦时滑入。
   此规则原先由已移除的 archive.css 提供，theme-xiaoyi 成为唯一主题后需自带。 */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--brand); color: #fff; padding: 10px 16px;
  font-size: 13px;
  border-radius: var(--r-ctl);
}
.skip-link:focus { left: 0; }

/* ==========================================================================
   X3. 报头 Masthead —— 方案 B：实心白卡 + 居中导航轨道
   --------------------------------------------------------------------------
   结构：Logo（左） │ 浅灰胶囊轨道（正中，白色药丸选中） │ 用户区（右）
   两侧等宽占位保证轨道真正居中；顶栏纯白，与页脚渐变条形成「白—蓝」呼应。
   移动端下拉面板适配见文件末尾 X18 段。
   ========================================================================== */
#masthead {
  position: fixed;
  top: 0; left: 0; right: 0;
  display: flex; align-items: center; justify-content: space-between;
  height: 64px;
  /* 左右留白：右侧 34px —— scrollbar-gutter 已为滚动条预留位置，再多留 10px 安全间距，
     避免登录按钮/用户卡紧贴滚动条（视觉上像被压住）。
     var(--sbw, 0px) 由 app.js 在浏览器不支持 scrollbar-gutter 时注入。 */
  padding: 0 calc(34px + var(--sbw, 0px)) 0 24px;
  z-index: 90;
  /* 2026-10-19 「白玻璃」：白度由 .45 提到 .82 —— 字压在接近纯白的面上，对比度不再
     随背后的彩色 hero 漂移（最坏情况仍有 10:1 以上）；同时保留 blur 与内高光，
     滚动时仍能隐约看到内容从栏下穿过的那层"玻璃"手感。 */
  background: rgba(255, 255, 255, .82);
  backdrop-filter: saturate(180%) blur(20px) brightness(1.02);
  -webkit-backdrop-filter: saturate(180%) blur(20px) brightness(1.02);
  border-bottom: 1px solid rgba(0, 0, 0, .07);
  /* 内高光模拟玻璃边缘折射（inset 写在 box-shadow 最前） */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .9),
    inset 0 -1px 0 rgba(255, 255, 255, .4),
    0 1px 2px rgba(16, 24, 40, .04),
    0 6px 18px -10px rgba(16, 24, 40, .16);
}
#masthead::after { content: none; }   /* 不需要底部高光线 */
[data-theme="dark"] #masthead {
  background: rgba(13, 16, 20, .78);  /* 深色同步提到 .78，保持同样的「白玻璃」逻辑 */
  backdrop-filter: saturate(180%) blur(20px) brightness(1.04);
  -webkit-backdrop-filter: saturate(180%) blur(20px) brightness(1.04);
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  /* 深色下内高光用低透明度白，否则会过亮 */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), 0 6px 18px -10px rgba(0, 0, 0, .5);
}
#masthead > * { pointer-events: auto; }

/* ---------- 左：Logo ---------- */
.masthead-brand {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 0; background: transparent; border: 0;
  flex: 1 1 0;          /* 与右侧等宽 → 轨道真正居中 */
  min-width: 0;
}
/* 顶栏 Logo：favicon 图标 + 品牌蓝描边 */
.brand-mark {
  width: 34px; height: 34px; flex: 0 0 34px;
  border-radius: var(--r-ctl);
  background: var(--brand-wash);
  box-shadow: inset 0 0 0 1px rgba(17, 17, 17, .14);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
.brand-mark img { width: 100%; height: 100%; object-fit: cover; display: block; }
.brand-text { display: flex; flex-direction: column; line-height: 1.1; min-width: 0; }
.brand-name {
  font-family: var(--font-display); font-size: 17px; font-weight: 700;
  color: var(--ink); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}

/* ---------- 中：浅灰胶囊轨道 ---------- */
.masthead-nav {
  display: flex; align-items: center; justify-content: center;
  flex: 0 0 auto;        /* 轨道宽度随内容，不被两侧挤压 */
  min-width: 0;
}
.nav-panel {
  display: flex; align-items: center; gap: 2px;
  /* 「白玻璃」下轨道不能再是纯白（会和顶栏糊成一片），改为极淡的冷灰薄片，
     半透明保留一点通透，面积小所以不影响顶栏的玻璃感。 */
  background: rgba(240, 243, 248, .72);
  border: 0;
  border-radius: var(--radius-pill);
  padding: 3px;
}
.nav-panel > a {
  border: 0;
  padding: 8px 16px; border-radius: var(--radius-pill);
  /* 2026-10-19：14.5px/500 → 15px/600。原字号与字重在浅底上笔画偏细，
     是"看着累"的主因；加粗半档后不用再压深颜色就有分量。 */
  font-family: var(--font-body); font-size: 15px; font-weight: 600;
  color: #1a2233;
  background: transparent;
  letter-spacing: 0; white-space: nowrap;
  transition: background .2s ease, color .2s ease, box-shadow .2s ease;
}
.nav-panel > a:last-child { border-right: 0; }
.nav-panel > a:hover { color: var(--brand-ink); background: rgba(17, 17, 17, .07); }
/* 选中项：品牌蓝实心药丸 + 白字（比白药丸强得多，一眼能定位当前页） */
.nav-panel > a.active {
  color: #fff; background: var(--brand); font-weight: 600;
  box-shadow: 0 2px 8px rgba(17, 17, 17, .28);
}
.nav-panel > a.active::after { display: none; }
.nav-sep { width: 1px; height: 18px; background: var(--rule-2); margin: 0 4px; }
.nav-user-text { max-width: 18em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
[data-theme="dark"] .nav-panel { background: rgba(255, 255, 255, .07); }
[data-theme="dark"] .nav-panel > a { color: rgba(237, 240, 244, .84); }
[data-theme="dark"] .nav-panel > a:hover { color: #fff; background: rgba(255, 255, 255, .08); }
[data-theme="dark"] .nav-panel > a.active {
  color: #fff; background: #2f6dff;
  box-shadow: 0 2px 10px rgba(47, 109, 255, .45);
}

/* ---------- 右：用户区（与左侧等宽，视觉平衡） ---------- */
.masthead-actions {
  display: flex; align-items: center; justify-content: flex-end;
  gap: 12px; flex: 1 1 0; min-width: 0; margin-left: 0;
}
/* 已登录用户卡：白底描边 + 头像 + 用户名 */
.masthead-actions .nav-user {
  display: inline-flex; align-items: center; gap: 9px;
  height: 42px; padding: 0 16px 0 6px; border-radius: var(--radius-pill);
  font-size: 14.5px; font-weight: 600; color: var(--ink);
  background: #fff; border: 1px solid var(--rule-2);
  font-family: var(--font-body);
  transition: .2s; white-space: nowrap;
}
.masthead-actions .nav-user:hover { border-color: rgba(17, 17, 17, .3); box-shadow: 0 2px 8px rgba(17, 17, 17, .1); }
.masthead-actions .nav-user[hidden] { display: none; }
/* 关键修复：.btn 的 display:inline-flex 会覆盖 [hidden] 的 display:none，需显式声明 */
.masthead-actions .btn[hidden] { display: none; }
.nav-user-avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  background: var(--grad-blue); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 700; overflow: hidden;
}
.nav-user-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.nav-user-text { max-width: 12em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 登录区首屏可见性：由 index.html <head> 的内联脚本打的 data-auth 标记决定，
   在 body 渲染前就生效，避免「登录按钮先闪一下再变用户卡」。
   app.js 的 renderUserArea() 随后会再校正一次（数据加载完成后填头像/用户名）。 */
html[data-auth="in"]  #navJoin { display: none !important; }
html[data-auth="in"]  #navUser { display: inline-flex !important; }
html[data-auth="out"] #navUser { display: none !important; }
html[data-auth="out"] #navJoin { display: inline-flex !important; }

/* 登录按钮与登录后的用户卡：固定同宽同高，切换时右侧容器宽度不变，因此不产生位移 */
.masthead-actions .masthead-cta,
.masthead-actions .nav-user {
  width: 126px; height: 42px; flex: none;
  justify-content: center; box-sizing: border-box;
}
.masthead-actions .nav-user { padding: 0 10px 0 5px; gap: 7px; }
.masthead-actions .nav-user-avatar { width: 28px; height: 28px; font-size: 12.5px; }
/* 用户名过长时省略号，不撑破固定宽度。
   2026-10-06：原 max-width:62px 把文字二次收窄（126px 胶囊减去头像 28 + padding 15 + gap 7
   只剩 76px，再卡 62px 导致「迪粉社」都显示不全）。
   改为 flex:1 + min-width:0，让文字吃满剩余空间 —— 6 字以内完整显示，超长才省略，
   胶囊仍固定 126px 与「登录 / 注册」按钮同宽，登录前后顶栏不位移。 */
.masthead-actions .nav-user-text {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 超长昵称加 title，悬停可看全名 */
.masthead-actions .nav-user[title] { cursor: pointer; }
/* 未登录态：品牌蓝主按钮（白底顶栏上，蓝色按钮最自然） */
.masthead-actions .masthead-cta {
  font-size: 14px; letter-spacing: 0;
}

/* ==========================================================================
   X4.（原「状态条 / 更新与同步」已整体移除）
   ========================================================================== */

/* 汉堡按钮（白底顶栏 →浅灰底 + 深色横线） */
.nav-toggle {
  display: none; width: 42px; height: 42px;
  flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  background: var(--paper-2); border: 1px solid var(--rule-2);
  border-radius: var(--r-card);
}
.nav-toggle-bar { background: var(--ink-2); }

/* ==========================================================================
   X5. 主区（吸顶导航补偿）
   ========================================================================== */
/* ---------- 全站统一底部留白 ----------
   所有页面内容到 footer 的距离统一由 #app 的 padding-bottom + footer margin-top 决定。
   各页面容器不再各自设置 padding-bottom，避免叠加后深浅不一。 */
#app {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 96px 28px 40px;
  width: 100%; flex: 1;
}
body.admin-mode #app { padding: 0 !important; max-width: none !important; }

/* ==========================================================================
   X6. 页脚 —— 黑色星空（仿小艺 footer-bg）
   ========================================================================== */
footer {
  position: relative;
  background: #000;
  color: rgba(255, 255, 255, .5);
  border-top: 0;
  padding: 56px 28px 40px;
  font-family: var(--font-body);
  font-size: 12.5px;
  letter-spacing: .01em;
  text-align: center;
  overflow: hidden;
  margin-top: 32px;
}
footer::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(1px 1px at 8% 22%, #fff 50%, transparent 50%),
    radial-gradient(1.5px 1.5px at 22% 58%, #fff 50%, transparent 50%),
    radial-gradient(1px 1px at 36% 30%, #fff 50%, transparent 50%),
    radial-gradient(1.5px 1.5px at 52% 16%, #fff 50%, transparent 50%),
    radial-gradient(2px 2px at 66% 40%, #fff 50%, transparent 50%),
    radial-gradient(1px 1px at 80% 20%, #fff 50%, transparent 50%),
    radial-gradient(1.5px 1.5px at 90% 46%, #fff 50%, transparent 50%),
    radial-gradient(1px 1px at 14% 70%, #fff 50%, transparent 50%),
    radial-gradient(1px 1px at 46% 62%, #fff 50%, transparent 50%),
    radial-gradient(1.5px 1.5px at 74% 68%, #fff 50%, transparent 50%);
  background-size: 100% 100%;
  opacity: .55;
}
footer::after {
  content: ""; position: absolute; left: 50%; top: 30%;
  transform: translateX(-50%);
  width: 1400px; height: 1400px;
  border-radius: 50%;
  pointer-events: none;
  background: conic-gradient(from 200deg at 50% 50%,
    transparent 0deg, rgba(82, 145, 255, .32) 42deg, rgba(146, 102, 248, .22) 70deg, transparent 105deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  padding: 1px;
}
footer a { color: rgba(255, 255, 255, .7); }
footer a:hover { color: #fff; }
.foot-sep { color: rgba(255, 255, 255, .25); margin: 0 6px; }
#footerText { position: relative; z-index: 1; max-width: var(--measure); margin: 0 auto; }

/* ==========================================================================
   X7. 按钮 —— 胶囊化
   ========================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  border-radius: var(--radius-pill);
  border: 0;
  background: #fff;
  color: var(--ink);
  font-family: var(--font-body); font-size: 13.5px; font-weight: 600;
  padding: 9px 18px; line-height: 1.2;
  cursor: pointer; text-decoration: none;
  transition: transform .15s, box-shadow .15s, background .15s, border-color .15s, color .15s;
}
.btn:hover { transform: translateY(-1px); border-color: var(--brand); color: var(--brand); }
.btn:active { transform: none; }
.btn.primary {
  background: var(--brand); border-color: var(--brand); color: var(--btn-ink);
  box-shadow: 0 6px 16px rgba(17, 17, 17, .28);
}
.btn.primary:hover { background: var(--brand-ink); border-color: var(--brand-ink); color: var(--btn-ink); box-shadow: 0 10px 22px rgba(17, 17, 17, .34); }
.btn.danger { background: var(--btn-danger-bg); border-color: transparent; color: #fff; }
.btn.danger:hover { background: #a51d1d; border-color: #a51d1d; color: #fff; }
.btn.ghost { background: transparent; border-color: transparent; color: var(--brand); }
.btn.ghost:hover { background: var(--brand-wash); border-color: transparent; color: var(--brand); }
.btn.sm { padding: 5px 13px; font-size: 12px; }
.btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* ==========================================================================
   X8. 通用卡片 / 输入框
   ========================================================================== */
.card {
  background: #fff; border: 1px solid var(--rule); border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}
[data-theme="dark"] .card { background: var(--panel); }

input[type="text"], input[type="search"], input[type="password"], input[type="email"],
input[type="number"], input[type="tel"], input[type="url"], textarea, select,
.search-input {
  border: 0;
  border-radius: var(--radius);
  padding: 9px 14px;
  font-family: var(--font-body); font-size: 14px; color: var(--ink);
  background: var(--gray-wash);
  transition: border-color .15s, box-shadow .15s;
}
input:focus, textarea:focus, select:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(17, 17, 17, .12);
}

/* ==========================================================================
   X9. 首页 —— Hero / 入口 / 档案卡 / 动态
   ========================================================================== */
.sect-head { margin-bottom: 20px; }
.sect-head .sect-idx {
  display: inline-block; font-family: var(--font-mono); font-size: 11px; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--brand);
  margin-bottom: 8px;
}
.sect-head h2 { font-size: 26px; font-weight: 800; color: var(--ink); margin: 0; }
.sect-head .sect-desc { font-size: 13px; color: var(--ink-3); }

/* Hero：居中大标题 + 光晕 */
.landing-hero {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 0;
  border: 0; border-top: 0;
  background: transparent;
  padding: 24px 0 20px;
  margin-bottom: 20px;
  position: relative;
}
.landing-hero::before {
  content: ""; position: absolute; left: 50%; top: -96px; transform: translateX(-50%);
  width: 720px; height: 480px; pointer-events: none;
  background: radial-gradient(closest-side, rgba(95, 151, 255, .28), rgba(185, 213, 255, .1), transparent);
  filter: blur(30px);
}
.landing-hero-main {
  padding: 0; border-right: 0; min-width: 0; max-width: 760px;
  position: relative; z-index: 1;
}
.landing-eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-body); font-size: 13px; font-weight: 600;
  letter-spacing: .02em; text-transform: none; color: var(--ink-2);
  margin-bottom: 18px;
  padding: 7px 16px; border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, .75); border: 1px solid var(--rule);
  box-shadow: var(--glass-shadow);
}
.landing-eyebrow::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--brand);
}
.landing-hero h1 {
  margin: 0 0 18px;
  font-size: 44px; font-weight: 800; line-height: 1.28;
  letter-spacing: -.02em; color: var(--ink);
}
.landing-hero h1 em { font-style: normal; color: var(--brand); }
.landing-lead {
  margin: 0 auto 26px; font-size: 16px; line-height: 1.75;
  color: var(--ink-2); max-width: 560px;
}
.landing-cta { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; justify-content: center; }
.landing-cta .btn { padding: 11px 24px; font-size: 14px; }

/* Hero 搜索框 */
.hero-search {
  display: flex; align-items: center; gap: 10px;
  max-width: 560px; margin: 0 auto 24px;
  background: #fff; border: 1px solid var(--rule);
  border-radius: var(--radius-pill); padding: 6px 6px 6px 20px;
  box-shadow: var(--shadow-md);
}
.hero-search .icon { width: 18px; height: 18px; color: var(--ink-3); flex: none; }
.hero-search input {
  flex: 1; border: 0; background: transparent; padding: 8px 0;
  font-size: 15px; color: var(--ink); min-width: 0;
}
.hero-search input:focus { box-shadow: none; }
.hero-search .btn { flex: none; }

/* Hero 数据面板 → 横排统计条 */
.landing-hero-side {
  display: flex; flex-wrap: wrap; align-items: stretch; justify-content: center;
  gap: 12px; background: transparent; padding: 0; margin-top: 12px;
  width: 100%; max-width: 860px; position: relative; z-index: 1;
}
.hero-stat {
  background: rgba(255, 255, 255, .82); border: 1px solid var(--rule);
  border-radius: var(--radius-lg); box-shadow: var(--glass-shadow);
  padding: 16px 28px; min-width: 160px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  backdrop-filter: blur(8px);
}
[data-theme="dark"] .hero-stat { background: rgba(22, 25, 30, .8); }
.hero-stat .label {
  font-family: var(--font-body); font-size: 12px; font-weight: 500;
  letter-spacing: .02em; text-transform: none; color: var(--ink-3);
}
.hero-stat .label .dot { display: inline-block; width: 6px; height: 6px; min-width: 6px; flex: 0 0 6px; border-radius: 50%; background: var(--brand); }
.hero-stat .label .dot.ok { background: var(--ok); }
.hero-stat .value {
  font-family: var(--font-display); font-size: 26px; font-weight: 800;
  color: var(--ink); letter-spacing: -.02em; font-variant-numeric: tabular-nums;
}
.hero-stat.num .value { font-size: 28px; }
.hero-stat.time .value { font-size: 18px; font-weight: 700; }
.hero-stat .sub { font-size: 12px; color: var(--ink-3); }
.hero-stat.time .live { color: var(--ok); }
.hero-stat .sync-rel { color: var(--ok); }

/* 两栏布局 */
.home-split { display: grid; grid-template-columns: 2fr 1fr; gap: 22px; align-items: start; }

/* 功能入口矩阵 → 玻璃卡片 */
.entry-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 14px; background: transparent; border: 0;
}
.entry {
  position: relative; display: flex; flex-direction: column; gap: 10px;
  background: rgba(255, 255, 255, .9); border: 1px solid var(--rule);
  border-radius: var(--radius-lg); box-shadow: var(--shadow);
  padding: 22px 22px 20px; min-height: 150px;
  transition: transform .2s, box-shadow .2s, border-color .2s;
  backdrop-filter: blur(8px);
}
[data-theme="dark"] .entry { background: var(--panel); }
.entry:hover { background: #fff; border-color: rgba(17, 17, 17, .3); transform: translateY(-4px); box-shadow: var(--shadow-md); }
.entry:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.entry.span-3 { grid-column: span 3; }
.entry.span-4 { grid-column: span 4; }
.entry.span-5 { grid-column: span 5; }
.entry.span-6 { grid-column: span 6; }
.entry.span-7 { grid-column: span 7; }
.entry.span-row { grid-row: span 2; }

.entry-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.entry-idx {
  font-family: var(--font-mono); font-size: 11px; font-weight: 700;
  letter-spacing: .08em; color: var(--brand);
}
.entry-icon {
  width: 44px; height: 44px; border-radius: 13px; border: 0;
  display: flex; align-items: center; justify-content: center; color: #fff;
  position: relative; overflow: hidden;
}
.entry-icon::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(160deg, hsla(0, 0%, 100%, .4), transparent 48%);
}
.entry-icon .icon { width: 22px; height: 22px; position: relative; z-index: 1; }
/* harmony 多彩：按入口顺序给不同渐变 */
.entry:nth-child(1) .entry-icon { background: var(--grad-blue); }
.entry:nth-child(2) .entry-icon { background: var(--grad-violet); }
.entry:nth-child(3) .entry-icon { background: var(--grad-teal); }
.entry:nth-child(4) .entry-icon { background: var(--grad-pink); }
.entry:nth-child(5) .entry-icon { background: var(--grad-gold); }
.entry:hover .entry-icon { border-color: transparent; color: #fff; }
.entry-name {
  font-family: var(--font-display); font-size: 16.5px; font-weight: 700;
  color: var(--ink); letter-spacing: -.01em; margin-top: auto;
}
.entry.span-5 .entry-name, .entry.span-6 .entry-name, .entry.span-7 .entry-name { font-size: 19px; }
.entry-note { font-size: 12.5px; line-height: 1.6; color: var(--ink-2); }
.entry-meta {
  font-family: var(--font-body); font-size: 11.5px; letter-spacing: .01em;
  color: var(--ink-3); display: flex; align-items: center; gap: 6px;
}
.entry-meta::before { content: ""; width: 14px; height: 2px; border-radius: 2px; background: var(--grad-blue); }

/* 个人档案卡 → 玻璃卡片 */
.id-card {
  border: 1px solid var(--rule); border-left: 0;
  border-radius: var(--radius-lg);
  background: rgba(255, 255, 255, .9); box-shadow: var(--shadow);
  padding: 22px; display: flex; flex-direction: column; align-items: stretch; gap: 16px;
  backdrop-filter: blur(8px);
}
[data-theme="dark"] .id-card { background: var(--panel); }
.id-card-guest { align-items: flex-start; }
.id-card-avatar {
  width: 56px; height: 56px; flex: 0 0 56px;
  border: 0; border-radius: var(--r-panel);
  background: var(--grad-blue); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-size: 22px; font-weight: 700;
  overflow: hidden; box-shadow: var(--shadow);
}
.id-card-main { flex: 1 1 auto; min-width: 0; }
.id-card-name { font-family: var(--font-display); font-size: 17px; font-weight: 700; color: var(--ink); }
.id-card-sub { font-family: var(--font-body); font-size: 12px; color: var(--ink-3); }
.id-card-stats { display: flex; gap: 0; border-left: 0; }
.id-stat { background: var(--paper-2); border-radius: var(--radius); padding: 10px 16px; }
.id-stat b { font-size: 18px; font-weight: 800; color: var(--ink); }
.id-card-perks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.id-card-perks li { display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--ink-2); }
.id-card-perks .icon { width: 16px; height: 16px; color: var(--brand); }
.id-card-actions { display: flex; flex-wrap: wrap; gap: 8px; }

/* 最新同步文件 */
.upd-list { display: flex; flex-direction: column; gap: 8px; }
.upd-item {
  display: flex; align-items: center; gap: 14px;
  background: rgba(255, 255, 255, .9); border: 1px solid var(--rule);
  border-radius: var(--radius); box-shadow: var(--shadow-sm, 0 1px 3px rgba(0,0,0,.04));
  padding: 13px 16px; transition: transform .15s, box-shadow .15s;
}
[data-theme="dark"] .upd-item { background: var(--panel); }
.upd-item:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.upd-kind { font-family: var(--font-body); font-size: 11px; font-weight: 600; color: var(--brand); background: var(--brand-wash); padding: 3px 10px; border-radius: var(--radius-pill); flex: none; display: inline-flex; align-items: center; gap: 5px; }
.upd-kind .icon { width: 13px; height: 13px; }
.upd-title { font-size: 14px; font-weight: 600; color: var(--ink); flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.upd-meta { flex: 1 1 auto; min-width: 0; font-size: 12px; color: var(--ink-3); overflow: hidden; }
.upd-size { font-size: 12px; color: var(--ink-3); font-variant-numeric: tabular-nums; flex: none; }
.upd-when { font-size: 12px; color: var(--ink-3); flex: none; }
.upd-act .btn { flex: none; }

/* 加载骨架 */
.loading-row { display: flex; align-items: center; gap: 10px; color: var(--ink-3); padding: 16px; }
.spinner { border: 2px solid var(--rule-2); border-top-color: var(--brand); border-radius: 50%; width: 16px; height: 16px; animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ==========================================================================
   X10. 其它前台页面通用（page-head / 空态 / 徽章）
   ========================================================================== */
.page-head { margin-bottom: 20px; }
.page-title { font-size: 26px; font-weight: 800; letter-spacing: -.02em; color: var(--ink); margin: 0 0 6px; }
.page-desc { font-size: 14px; color: var(--ink-2); margin: 0; }
.back-home {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-body); font-size: 12.5px; font-weight: 500;
  letter-spacing: .01em; color: var(--ink-2);
  border: 1px solid var(--rule-2); border-radius: var(--radius-pill);
  padding: 6px 14px; background: #fff;
}
.back-home:hover { border-color: var(--brand); color: var(--brand); }

.empty-state { text-align: center; padding: 48px 20px; color: var(--ink-3); }
.empty-state.lg { border: 1px dashed var(--rule-2); border-radius: var(--radius-xl); background: rgba(255,255,255,.6); }
.empty-icon { color: var(--ink-3); }
.empty-title { font-size: 17px; font-weight: 700; color: var(--ink); margin: 12px 0 6px; }
.empty-actions { display: flex; gap: 10px; justify-content: center; margin-top: 18px; }

.arch-tag {
  display: inline-block; font-family: var(--font-body); font-size: 11.5px; font-weight: 600;
  padding: 3px 11px; border-radius: var(--radius-pill);
  background: var(--paper-2); color: var(--ink-2); border: 1px solid var(--rule);
}

/* 模态 / toast 圆角统一 */
.modal { border-radius: var(--radius-xl); box-shadow: var(--shadow-lg); }
.modal-mask { background: rgba(10, 16, 28, .4); backdrop-filter: blur(4px); }
.toast { border-radius: var(--radius); box-shadow: var(--shadow-md); }

/* ==========================================================================
   X11. 响应式微调（桌面为主，窄屏配合 mobile-app.css）
   ========================================================================== */
@media (max-width: 900px) {
  .landing-hero h1 { font-size: 34px; }
  .home-split { grid-template-columns: 1fr; }
  .entry-grid { grid-template-columns: 1fr 1fr; }
  .entry.span-3, .entry.span-4, .entry.span-5, .entry.span-6, .entry.span-7 { grid-column: span 1; }
  .hero-stat { min-width: 140px; }
}
@media (max-width: 640px) {
  #app { padding: 84px 16px 32px; }
  #masthead { height: 60px; padding: 0 20px 0 16px; }
  .landing-hero h1 { font-size: 28px; }
  .landing-lead { font-size: 14.5px; }
  .hero-search { padding: 5px 5px 5px 16px; }
  .entry-grid { grid-template-columns: 1fr; }
  .hero-stat { min-width: 0; flex: 1 1 44%; }
  footer::after { width: 900px; height: 900px; }
}

/* ==========================================================================
   X12. 首页渲染图布局组件（home.js 新结构）
   ========================================================================== */
/* Hero 热词 */
.hot-words { display: flex; justify-content: center; gap: 10px; margin-top: 22px; flex-wrap: wrap; }
.hot-words a {
  font-size: 13px; color: var(--ink-2); background: #fff; border: 1px solid var(--rule);
  padding: 7px 16px; border-radius: var(--radius-pill); font-weight: 500;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .03); transition: .2s;
}
.hot-words a:hover { color: var(--brand); border-color: rgba(17, 17, 17, .2); background: var(--brand-wash); }

/* Hero 统计 */
.stats { display: flex; justify-content: center; gap: 64px; margin-top: 44px; flex-wrap: wrap; }
.stat { text-align: center; }
.stat .num { font-size: 30px; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.stat .num.small { font-size: 17px; font-weight: 700; line-height: 1.9; }
.stat .lab { font-size: 13px; color: var(--ink-3); margin-top: 2px; }

/* 三大功能卡 */
.features { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.feature {
  background: #fff; border: 1px solid var(--rule); border-radius: var(--radius-xl);
  padding: 32px 28px; transition: .25s; box-shadow: var(--shadow);
  display: flex; flex-direction: column; position: relative; overflow: hidden;
}
[data-theme="dark"] .feature { background: var(--panel); }
.feature:hover { transform: translateY(-5px); box-shadow: var(--shadow-md); border-color: rgba(17, 17, 17, .25); }
.feature .ico {
  width: 56px; height: 56px; border-radius: var(--r-panel); display: grid; place-items: center;
  color: #fff; margin-bottom: 22px; position: relative; overflow: hidden;
}
.feature .ico::after { content: ""; position: absolute; inset: 0; background: linear-gradient(160deg, hsla(0, 0%, 100%, .45), transparent 45%); }
.feature .ico .icon { width: 26px; height: 26px; position: relative; z-index: 1; }
.f-blue .ico { background: var(--grad-blue); }
.f-violet .ico { background: var(--grad-violet); }
.f-teal .ico { background: var(--grad-teal); }
.f-gold .ico { background: var(--grad-gold); }
.feature h3 { font-size: 19px; font-weight: 700; margin: 0 0 10px; color: var(--ink); }
.feature p { font-size: 14px; color: var(--ink-2); line-height: 1.7; margin: 0 0 18px; }
.feature .link { display: inline-flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 600; color: var(--brand); margin-top: auto; }
.feature .link .icon { width: 15px; height: 15px; transition: .2s; }
.feature:hover .link .icon { transform: translateX(3px); }

/* 热门资源卡片 */
.res-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
.res-card {
  background: #fff; border: 1px solid var(--rule); border-radius: var(--radius-lg);
  overflow: hidden; transition: .25s; box-shadow: var(--shadow); display: flex; flex-direction: column;
}
[data-theme="dark"] .res-card { background: var(--panel); }
.res-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-md); }
.res-card .thumb { height: 128px; display: grid; place-items: center; color: #fff; position: relative; }
.res-card .thumb::after { content: ""; position: absolute; inset: 0; background: linear-gradient(160deg, hsla(0, 0%, 100%, .28), transparent 50%); }
.res-card .thumb .icon { width: 40px; height: 40px; position: relative; z-index: 1; opacity: .95; }
.th-blue { background: var(--grad-blue); }
.th-violet { background: var(--grad-violet); }
.th-teal { background: var(--grad-teal); }
.th-gold { background: var(--grad-gold); }
.res-card .body { padding: 16px 16px 14px; }
.res-card h4 {
  font-size: 14.5px; font-weight: 700; line-height: 1.45; margin: 0 0 10px; color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.res-card .meta { display: flex; justify-content: space-between; align-items: center; font-size: 12px; color: var(--ink-3); }
.res-card .dl { display: inline-flex; align-items: center; gap: 4px; color: var(--brand); font-weight: 600; }
.res-card .dl .icon { width: 13px; height: 13px; }

/* 精选攻略 */
.guide-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
.guide {
  display: flex; gap: 20px; background: #fff; border: 1px solid var(--rule);
  border-radius: var(--radius-lg); padding: 24px; transition: .25s; box-shadow: var(--shadow);
}
[data-theme="dark"] .guide { background: var(--panel); }
.guide:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
.guide .rank { font-size: 34px; font-weight: 800; line-height: 1; color: var(--brand); flex: none; opacity: .9; }
.guide h4 { font-size: 16px; font-weight: 700; margin: 0 0 8px; color: var(--ink); }
.guide p { font-size: 13.5px; color: var(--ink-2); line-height: 1.6; margin: 0 0 12px; }
.chips { display: flex; gap: 8px; flex-wrap: wrap; }
.chip { font-size: 12px; font-weight: 500; color: var(--ink-2); background: var(--paper-2); padding: 3px 11px; border-radius: var(--radius-pill); }

/* 社区动态 */
.posts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.post {
  background: #fff; border: 1px solid var(--rule); border-radius: var(--radius-lg);
  padding: 22px; transition: .25s; box-shadow: var(--shadow); display: flex; flex-direction: column;
}
[data-theme="dark"] .post { background: var(--panel); }
.post:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); }
.post .user { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
/* 头像：v2 起统一用 /assets/avatars/ 的 10 个矢量 SVG（见 /js/avatar.js） */
.post .avatar { width: 42px; height: 42px; border-radius: 50%; overflow: hidden; flex: none; background: var(--grad-blue); }
.post .avatar img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 50%; }
.post .name { font-size: 14px; font-weight: 700; color: var(--ink); }
.post .time { font-size: 12px; color: var(--ink-3); }
.post .text {
  font-size: 14px; line-height: 1.7; color: var(--ink-2); margin: 0 0 16px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.post .reacts { display: flex; gap: 18px; font-size: 13px; color: var(--ink-3); margin-top: auto; }
.post .reacts span { display: inline-flex; align-items: center; gap: 5px; }
.post .reacts .icon { width: 15px; height: 15px; }

/* CTA */
@media (max-width: 900px) {
  .features { grid-template-columns: 1fr; }
  .res-grid { grid-template-columns: 1fr 1fr; }
  .guide-list { grid-template-columns: 1fr; }
  .stats { gap: 40px; }
}
/* 社区动态两行 6 条：桌面 3 列 / 平板 2 列 / 手机 1 列
   （放在 max-width:900px 之后，确保平板 2 列不被上面的规则覆盖） */
@media (min-width: 901px) { .posts { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 561px) and (max-width: 900px) { .posts { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .posts { grid-template-columns: 1fr; } }
@media (max-width: 640px) {
  .res-grid { grid-template-columns: 1fr 1fr; gap: 12px; }
  .res-card .thumb { height: 100px; }
  .stats { gap: 24px; }
  .stat .num { font-size: 24px; }
  .feature { padding: 26px 22px; }
  .cta { padding: 44px 22px; border-radius: var(--r-panel); }
  .cta h2 { font-size: 24px; }
}

/* ==========================================================================
   X13. 首页 —— 一比一复刻渲染图 difan-community-render.html（最高优先级）
   覆盖上方 X9/X12 的近似样式，class 名与 CSS 值均与渲染图逐项一致。
   ========================================================================== */
:root {
  --accent: var(--brand);
  --accent-soft: var(--brand-wash);
  --accent-soft-2: rgba(17, 17, 17, .14);
  --line: var(--rule);
  --line-soft: rgba(0, 0, 0, .05);
  --bg-gray: var(--paper-2);
  --card: #ffffff;
  --r-btn: 999px;
  --r-card: 14px;
  --r-micro: 6px;
  --r-ctl: 10px;
  --r-panel: 20px;
  --r-pill: 999px;
  --r-ico: 16px;
  --shadow-card: 0 2px 8px rgba(0, 0, 0, .04), 0 12px 32px rgba(0, 0, 0, .06);
  --shadow-float: 0 16px 48px rgba(17, 17, 17, .16);
}

/* 首页全宽突破 #app 容器（顶部负 margin 抵消固定导航留白） */
.home { margin: -32px calc(50% - 50vw) 0; }
/* 首页通栏容器：宽度铺满整屏（内容区仍留边距，避免贴边） */
.wrap { max-width: none; margin: 0 auto; padding: 0 clamp(24px, 5vw, 80px); }

/* Hero */
/* Hero：高度撑满首屏（顶栏之下），内容垂直居中 */
/* padding 上下统一为 64px，与第 2~5 区块一致：
   5 个区块内部都靠 align-items:center 做垂直居中，padding 只作为「内容不贴边」的下限；
   上下留白相同 → 各块内容高度不同时也不会出现「这块上宽下窄、那块上窄下宽」的错位感。 */
/* 2026-10-04 背景重写：hero 自带的白底与 .glow 光晕已删除，
   首屏背景由全局流动光场 .bgflow（见文件末尾 X195 段）承担 —— hero 透明即可透出。 */
.hero {
  position: relative;
  /* 2026-10-19：高度只由视口决定，不再叠 --home-maxh。
     原先叠的是「5 块里最高那块」的自然高度（第 3 屏 886px），
     视口矮于 886 时每块都被撑高，flex 居中就落到区块中点（y=475）
     而不是视口中点（1366×768 时为 416）→ 首屏整体下沉 59px、底部被裁。 */
  min-height: calc(100vh - 64px);
  display: flex;
  /* 先写 center 兜底：不支持 safe 关键字的浏览器会丢弃第二条声明 */
  align-items: center;
  align-items: safe center;
  justify-content: center;
  padding: 64px 0;
  text-align: center;
}
.hero .wrap { position: relative; z-index: 1; }
.badge { display: inline-flex; align-items: center; gap: 8px; padding: 7px 16px; border-radius: var(--r-btn); background: rgba(255,255,255,.75); border: 1px solid var(--line); font-size: 13px; color: var(--ink-2); font-weight: 500; box-shadow: var(--glass-shadow); }
.badge .dot { display: block; width: 7px; height: 7px; min-width: 7px; min-height: 7px; flex: 0 0 7px; align-self: center; border-radius: 50%; background: var(--accent); }
/* margin-top 0：原本是给顶部徽标预留的位置，徽标已删除 */
.hero h1 { font-size: clamp(38px, 4.2vw, 64px); line-height: 1.2; font-weight: 800; letter-spacing: -.5px; color: var(--ink); margin: 0 auto 18px; max-width: 1000px; }
.hero h1 em { font-style: normal; color: var(--accent); }
.hero .sub { font-size: clamp(15px, 1.2vw, 19px); color: var(--ink-2); max-width: 720px; margin: 0 auto; line-height: 1.75; }

/* ==========================================================================
   X2b. 首屏左右分栏（2026-10-19，方案 B）
   --------------------------------------------------------------------------
   原来的居中构图撑不起「标题 + 搜索 + 数据」三层信息：标题被 <br> 切成
   「6 字黑 + 7 字蓝 + 5 字」三段，搜索卡两行、圆钮悬在右下角，三个数字散在
   底下一排 —— 视线找不到落点。
   改法：左栏（eyebrow → 标题 → 副标题 → 数据）左对齐成一根阅读轴，右栏一张
   纵向搜索卡（输入 → 分段 → 按钮），背景从左往右由干净的白渐变到彩色光场。
   DOM 侧配合：home.js 的 .hero > .wrap 改为 .hero-split，内部拆 .hero-left /
   .hero-right（搜索表单与统计的 id 全部保留，交互 JS 未改）。
   ========================================================================== */
/* 左半压白：把 tech.css 旧层的 .hero::before 彩色 radial 一并盖掉（同一伪元素，
   本文件在后面，直接覆盖），只留从左到右逐渐透明的一层白。 */
.hero::before {
  content: "";
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(100deg,
    rgba(255, 255, 255, .95) 0%,
    rgba(255, 255, 255, .9) 30%,
    rgba(255, 255, 255, .5) 54%,
    rgba(255, 255, 255, 0) 74%);
}
[data-theme="dark"] .hero::before {
  background: linear-gradient(100deg,
    rgba(13, 16, 20, .92) 0%,
    rgba(13, 16, 20, .84) 32%,
    rgba(13, 16, 20, .42) 56%,
    rgba(13, 16, 20, 0) 76%);
}

.hero-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 400px;
  align-items: center;
  gap: 64px;
  /* .hero 是 flex 容器：.wrap 作为 flex item 若不给 width，宽度会退到 max-content
     （实测只有 934px，右侧留出一大片空），这里显式撑满再由 max-width 收口。 */
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  text-align: left;
}
.hero-eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  margin: 0 0 14px; font-size: 12px; font-weight: 600;
  letter-spacing: .14em; color: #5b6675;   /* 原 var(--ink-3) 在此底色上只有 3.4:1，压深到 5.7:1 */
}
.hero-eyebrow i { display: block; width: 18px; height: 1px; background: var(--rule-3); }

.hero-split h1 {
  margin: 0; max-width: none;
  font-size: clamp(34px, 3.8vw, 52px); line-height: 1.24; letter-spacing: -.03em;
}
.hero-split .sub { margin: 16px 0 0; max-width: 470px; font-size: 15.5px; line-height: 1.8; }
/* 数据条：左对齐 + 竖线分隔，不再是三个散开的居中数字 */
.hero-split .stats { justify-content: flex-start; gap: 0; margin-top: 30px; }
.hero-split .stat { text-align: left; padding-right: 26px; margin-right: 26px; border-right: 1px solid var(--rule-2); }
.hero-split .stat:last-child { padding-right: 0; margin-right: 0; border-right: 0; }
.hero-split .stat .num { font-size: 26px; }
.hero-split .stat .lab { font-size: 12.5px; color: #5b6675; margin-top: 3px; }

/* 右栏：纵向搜索卡（输入 → 分段 → 按钮） */
.hero-right { min-width: 0; }
.hero-right .search-card {
  margin: 0; max-width: none; padding: 22px; border-radius: var(--r-panel);
  box-shadow: 0 18px 50px -12px rgba(16, 24, 40, .22), 0 0 0 1px rgba(16, 24, 40, .04);
}
.hero-right .search-top { padding: 0 0 14px; border-bottom: 1px solid var(--rule); }
.hero-right .search-top .icon { width: 19px; height: 19px; }
.hero-right .search-top input { height: 30px; font-size: 14.5px; }
.hero-right .search-bar { display: block; padding: 16px 0 0; }
.hero-right .seg { display: flex; width: 100%; padding: 5px; background: #f2f5f9; backdrop-filter: none; -webkit-backdrop-filter: none; }
.hero-right .seg-btn { flex: 1; text-align: center; padding: 9px 0; font-size: 12.5px; border-radius: var(--r-ctl); }
/* 白药丸滑块 + 蓝字：在浅灰槽上比「蓝底白字」更轻，不会和下方的蓝色按钮抢 */
.hero-right .seg-thumb { background: #fff; box-shadow: 0 1px 4px rgba(16, 24, 40, .12); }
.hero-right .seg-btn.is-on { color: var(--brand); }
.hero-right .search-go { width: 100%; height: 44px; border-radius: var(--r-card); margin-top: 14px; box-shadow: 0 6px 16px rgba(17, 17, 17, .28); }
.hero-right .search-go svg { display: none; }
.hero-right .search-go::after { content: "搜索"; font-size: 14px; font-weight: 600; }
.hero-right .hot-words { justify-content: flex-start; margin-top: 16px; }

[data-theme="dark"] .hero-right .seg { background: rgba(255, 255, 255, .07); }
[data-theme="dark"] .hero-right .seg-thumb { background: rgba(255, 255, 255, .15); box-shadow: none; }
[data-theme="dark"] .hero-right .seg-btn.is-on { color: #cfcfcf; }
[data-theme="dark"] .hero-split .stat .lab { color: rgba(237, 240, 244, .66); }

/* 窄屏：单列堆叠，左对齐保持不变 */
@media (max-width: 1024px) {
  .hero-split { grid-template-columns: 1fr; gap: 30px; max-width: 560px; }
  .hero-split h1 { font-size: clamp(30px, 6vw, 38px); }
  .hero-split .sub { max-width: none; font-size: 15px; }
  .hero-split .stats { margin-top: 24px; }
  .hero::before {
    background: linear-gradient(180deg,
      rgba(255, 255, 255, .95) 0%,
      rgba(255, 255, 255, .86) 46%,
      rgba(255, 255, 255, .6) 74%,
      rgba(255, 255, 255, .45) 100%);
  }
  [data-theme="dark"] .hero::before {
    background: linear-gradient(180deg,
      rgba(13, 16, 20, .93) 0%,
      rgba(13, 16, 20, .82) 48%,
      rgba(13, 16, 20, .55) 76%,
      rgba(13, 16, 20, .4) 100%);
  }
}

/* 搜索大卡片 */
/* 毛玻璃：与 .hero-stat / .entry / .id-card 同一配方（半透明白 + blur 8px），
   让搜索卡与首页光晕融为一体，而不是一块死白卡片。
   -webkit- 前缀是Safari 兼容，站内其他毛玻璃处也这么写，保持一致。 */
.search-card {
  width: 100%; max-width: 860px; margin: 38px auto 0;
  background: rgba(255, 255, 255, .82);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, .7);
  border-radius: 28px; box-shadow: 0 12px 40px rgba(0,0,0,.1);
  overflow: hidden; text-align: left;
}
[data-theme="dark"] .search-card { background: rgba(22, 25, 30, .8); }
/* padding-bottom 12px：与 .search-bar 的 10px 配合，两处留白对称 */
.search-top { display: flex; align-items: center; gap: 12px; padding: 24px 24px 12px; }
.search-top .icon { width: 22px; height: 22px; color: var(--ink-3); flex: none; }
.search-top input { flex: 1; border: none; outline: none; font-size: 17px; color: var(--ink); background: transparent; height: 34px; font-family: inherit; }
.search-top input::placeholder { color: var(--ink-3); }
/* margin-bottom 归零：app.css 的 18px 是给「上下分栏搜索框」用的，
   在这张卡片内它会让分段控件下方多出一截空白。
   上下留白对称：下方 10px，上方 .search-top 的 padding-bottom 12px。 */
.search-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 0 14px 10px 22px; margin-bottom: 0;
}
/* 搜索范围：iOS 式分段控件 —— 灰底槽 + 蓝底白字滑块，选中态一目了然。
   槽底色用半透明灰，让下方毛玻璃能透上来（纯色会在玻璃上显得闷、割裂）。 */
.seg {
  position: relative; display: inline-flex; align-items: center; gap: 2px;
  background: rgba(15, 23, 42, .05);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  border-radius: 999px; padding: 5px;
  min-width: 0; max-width: 100%; overflow: hidden;
}
.seg-thumb {
  position: absolute; top: 5px; left: 5px; bottom: 5px;
  width: 0; border-radius: 999px; background: var(--accent);
  box-shadow: 0 2px 8px rgba(17, 17, 17, .28);
  transition: transform .28s cubic-bezier(.4, 0, .2, 1), width .28s cubic-bezier(.4, 0, .2, 1);
  pointer-events: none; z-index: 0;
}
.seg-btn {
  position: relative; z-index: 1;
  font-size: 13.5px; line-height: 1; font-weight: 600; font-family: inherit;
  color: var(--ink-2); background: none; border: 0; cursor: pointer;
  padding: 11px 20px; border-radius: 999px; white-space: nowrap;
  transition: color .2s ease;
}
.seg-btn:hover { color: var(--ink); }
.seg-btn.is-on { color: #fff; }
/* 圆形发送键：尺寸与模板一致（40px） */
.search-go { width: 44px; height: 44px; flex: none; align-self: center; border-radius: 50%; background: var(--accent); display: grid; place-items: center; color: #fff; box-shadow: 0 4px 12px rgba(17,17,17,.3); border: none; cursor: pointer; padding: 0; }
.search-go svg { width: 19px; height: 19px; }

/* 热词 + 统计 */
.hot-words { display: flex; justify-content: center; gap: 10px; margin-top: 22px; flex-wrap: wrap; }
/* 热词胶囊：底色改半透明，让下方 .search-card 的毛玻璃能透出来。
   原来纯白 #fff 会在半透明卡片上显得"浮在雾上的一排白块"，失去整体感。 */
.hot-words a {
  display: inline-flex; align-items: center; gap: 7px; font-size: 13.5px; color: var(--ink-2);
  background: rgba(255, 255, 255, .6);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  border: 1px solid rgba(255, 255, 255, .8);
  padding: 8px 16px; border-radius: var(--r-btn); font-weight: 500;
  box-shadow: 0 2px 8px rgba(0,0,0,.03); transition: .2s;
}
.hot-words a:hover { color: var(--accent); border-color: var(--accent-soft-2); background: var(--accent-soft); }
/* 热搜词类型标签：固件 / 社区 / 攻略 */
.hw-type { font-size: 11px; font-weight: 600; line-height: 1; padding: 3px 7px; border-radius: var(--r-micro); flex: none; }
.hw-type.t-disk { background: rgba(17, 17, 17, .1); color: #111111; }
.hw-type.t-community { background: rgba(146, 102, 248, .14); color: #7c3aed; }
.hw-type.t-tips { background: rgba(255, 137, 23, .14); color: #e67e00; }
.stats { display: flex; justify-content: center; gap: 72px; margin-top: 52px; }
.stat .num { font-size: 30px; font-weight: 800; color: var(--ink); }
.stat .lab { font-size: 13.5px; color: var(--ink-3); margin-top: 4px; }

/* 区块 */
.home section { padding: 72px 0; }
.home section.alt { background: var(--bg-gray); }

/* 第2 区块（.home section:nth-of-type(2) =「你要的，这儿都有」三大功能入口）：
   与第 1 区块（.hero）采用同一套「一屏高减去导航栏 + 内容垂直居中」策略。
   实现方式与 .hero 一致：min-height 而非 height —— 内容更高时向下撑开，绝不截断。
   flex 居中让标题与卡片组在可用空间里垂直居中；padding 只留水平方向（由 .wrap 控制），
   垂直方向交给 align-items:center，避免 min-height 与 padding 叠加出多余空白。 */
.home section:nth-of-type(2) {
  min-height: calc(100vh - 64px);
  display: flex;
  align-items: center;
  align-items: safe center;
  justify-content: center;
  padding: 72px 0;
}
.home section:nth-of-type(2) > .wrap { width: 100%; }

/* 第 3 区块（nth-of-type(3) =「固件资源 · 大家都在下载」）：
   同样采用「一屏高减去导航栏 + 内容垂直居中」。
   注意：本区块的资源卡类名是 .card（不是 .res-card，那是攻略区的类）。
   布局：4 列 × 1 行 = 每页 4 张，共 8 个数据（2 页），自动轮播。
   ⚠ 本区块内容天然最高（标题 + 4 张 266px 卡 + 翻页圆点 ≈ 723px），
     其它 4 块内容都在 421~571px 之间。区块若高达 835px，滚动时就会「高低不平」。
     所以这里把缩略图与正文区各压 12px，让内容降到 ~699px，
     区块高度与其它 4 块精确一致（同为 741px），视觉节奏才统一。 */
.home section:nth-of-type(3) {
  min-height: calc(100vh - 64px);
  display: flex;
  align-items: center;
  align-items: safe center;
  justify-content: center;
  /* padding 与其它 4 块统一为 64px，消除块与块之间的留白差异 */
  padding: 64px 0;
}
.home section:nth-of-type(3) > .wrap { width: 100%; }
/* 标题与卡片组的间距收紧（44px → 14px） */
.home section:nth-of-type(3) .sec-head { margin: 0 0 14px; }
/* 缩略图压低（152px → 118px） */
.home section:nth-of-type(3) .thumb { height: 118px; }
/* 四卡等高：正文区改用 height 而非 min-height ——
   min-height 下「文件名一行」的卡会比「文件名两行」的卡矮 10px，破坏四卡底部对齐。
   .meta 已用 align-self:end 吸底，多余空间不会挤压标题。

   2026-10-04 卡片改两行后，为让本区块上下留白与第 5 区块一致（141/125），
   正文区由 98px 提到 112px（卡高 222 → 236，上留白 127 → 141）。 */
.home section:nth-of-type(3) .card .body { height: 112px; min-height: 0; }
/* 底部信息行压缩（44px → 36px） */
.home section:nth-of-type(3) .card .meta { height: 36px; }
/* 翻页圆点与卡片的间距收紧（22px → 14px） */
.home section:nth-of-type(3) .hot-dl-dots { margin-top: 14px; }


/* 第 4、5 区块：同样是「一屏高减去导航栏 + 内容垂直居中」。
   实测这两块的内容天然比一屏矮（桌面 1440×900 下分别约 602px / 670px，一屏 741px），
   所以不需要像第 3 区块那样压缩内容，直接靠 min-height + flex 居中把空间填满即可。
   移动端两者都是单列、内容远超一屏（1002px / 1438px），由 min-height 兜底自然撑开。 */
.home section:nth-of-type(4),
.home section:nth-of-type(5) {
  /* 末位区块保持「一屏高 + flex 垂直居中」，与前4 屏完全一致（用户要求：区块都撑满屏）。
     底部留白改由下面的负 margin 单独压缩，不动区块自身高度。 */
  min-height: calc(100vh - 64px);
  display: flex;
  align-items: center;
  align-items: safe center;
  justify-content: center;
  padding: 64px 0;
  /* 末位区块不加负 margin：区块高由 min-height 兜底，内容垂直居中，
     到底部的距离与前 4 屏一致（见 E:\difansclub 参考版，本就无此规则）。 */
}
.home section:nth-of-type(4) > .wrap,
.home section:nth-of-type(5) > .wrap { width: 100%; }

/* 首页页脚间距与协议页一致（协议页为 16px） */
#app:has(> .home) + footer { margin-top: 16px; }

/* --------------------------------------------------------------------------
   第 4 区块（迪粉分享）卡片加高 —— 对齐第 5 区块的上下留白
   --------------------------------------------------------------------------
   用户反馈（2026-10-04）：迪粉分享区的卡片偏矮，导致该区块上下留白比
   第 5 区块（迪粉社区）明显更多，两屏视觉不平衡。

   实测（1440×900，容器均836px）：
     第 4 区块：内容 488px（卡片列表 365px）→ 上留白 158 / 下留白 190
     第 5 区块：内容 539px（卡片列表 416px）→ 上留白 141 / 下留白 157
     差值约 51px。

   做法：把 .guide 的 padding 从 24px 提到 48px（上下各 +24px，共 +48px），
   配合卡片内部 gap 微调，总高+51px，留白即与第 5 区块一致。
   用 padding 而非固定 height：卡片内文字长短不一时不会溢出裁切。

   ⚠️ 两条都带 `html.page-snap` 前缀（原选择器是 `.home > section...`，
   特异性 (0,3,0) 低于文件后面的 `html.page-snap .home section:nth-of-type(4) .guide`
   (0,5,0)，会被移动端压缩规则压掉，实测加高不生效）。 */
html.page-snap .home section:nth-of-type(4) .guide { padding: 34px 32px; }
html.page-snap .home section:nth-of-type(4) .guide p { margin-bottom: 22px; }
/* 非吸附态（移动端等）同样生效，用同样的特异性写法 */
.home section:nth-of-type(4) .guide { padding: 34px 32px; }
.home section:nth-of-type(4) .guide p { margin-bottom: 22px; }

/* 末位区块（社区动态）到页脚的距离：
   由三处自然留白共同承担：区块 padding-bottom 64px + #app padding-bottom 40px
   + footer margin-top 16px ≈ 120px，与其它区块的上下节奏一致。 */

/* --------------------------------------------------------------------------
   桌面端：第 5 区块与页脚间距压缩「一个底栏高度」
   --------------------------------------------------------------------------
   用户反馈（2026-10-04）：桌面端下滑到底时，第 5 区块与底栏（页脚）之间
   空白太大 —— 要「减少一个底栏的高度」，让第 5 区块下滑时**直接出现底栏**。

   本处只改 #app 的底部 padding 与区块 padding；
   footer 的 margin-top 压缩放在文件后面的 X14 段之后（那里有footer{margin-top:80px}
   会覆盖本处声明）。

   压缩量 = 一个底栏高度（TAB 高 66px，桌面取 64px）：
     · #app padding-bottom  40px → 8px（减 32）
     · 区块 padding-bottom  64px → 48px（减 16）
     · footer margin-top    80px → 16px（在 X14 段后处理，减 64）
   合计 120px → 56px。

   ⚠️ 必须用 min-width:901px 限定：移动端末尾是 #tabbar（高 66px）不是页脚，
   移动端靠 #app 的 padding-bottom 96px 顶开底栏，
   若不加限定，移动端末区块到 TAB 的间距会被压掉（用户明确要求不能影响）。 */
@media (min-width: 901px) {
  body:has(.home) #app { padding-bottom: 8px; }
  .home > section:nth-of-type(5) { padding-bottom: 48px; }
}

/* ==========================================================================
   全屏滚动吸附（scroll-snap）—— 首页 5 区块整屏切换
   --------------------------------------------------------------------------
   需求：滑动时从当前区块「整屏跳到」下一屏，区块顶部对齐视口顶部。

   为什么用 body 而不是某个内层容器做滚动容器：
     页面本身由 body 滚动（#app 只是 flex 子元素）。若给某个内层加 overflow-y:auto
     会切出独立的滚动上下文，导致固定导航（position:fixed）失效、且需处理双滚动条，
     得不偿失。所以直接在 body 上开 snap-type。

   三个关键设计（都是上一版被撤销时暴露的问题）：
     1. scroll-padding-top = 导航高度 64px：
        导航是 position:fixed，snap 停靠默认对齐 scrollport 顶部（视口顶端），
        不加 scroll-padding 的话第 2~5 区块会「藏」在导航栏后面 64px。
     2. snap-align: start 而不是 center：
        每区块 min-height 恰好 = 一屏，所以 start 与 center 等价；
        但 start 在「内容高于一屏的移动端」时表现更稳（不会过度回弹）。
     3. 用 html.page-snap 开关而非直接写死：
        非首页路由、后台模式、以及内容溢出需自由滚动的场景，
        由 JS 打 / 去掉这个 class，保证其它页面不被牵连。
   ========================================================================== */
/* 吸附用 100dvh 而非 100vh：移动端浏览器地址栏收起时 100vh 不变、dvh 会跟随，
   避免区块高度比可视区高、snap 停靠时出现空白。不支持 dvh 的浏览器回落到 100vh。

   5 个区块全部保持「一屏高」（用户要求：每个区块都撑满屏）。
   末位区块底部留白过大另由 .home section:nth-of-type(5) 的负 margin 处理。 */
@supports (height: 100dvh) {
  html.page-snap .home section,
  html.page-snap .home .hero { min-height: calc(100dvh - 64px); }
}
@supports not (height: 100dvh) {
  html.page-snap .home section { min-height: calc(100vh - 64px); }
}

/* 开启吸附。
   ⚠ 关键1：scroll-snap-type 必须加在 html（根元素）上，不能加在 body！
   body 是 display:flex + min-height:100vh，实际高度被内容撑到与 scrollHeight 相等，
   body 自己并不可滚动（实测 bodyCanScroll:false，bodyClientH===bodyScrollH）。
   真正滚动的是根元素 html。overflow 会从 body 传播到 viewport，
   但 scroll-snap-type **不会传播** —— 写在 body 上会被浏览器完全忽略，
   表现就是「一点一点往下滑、不吸附」。

   ⚠ 关键2：导航让位用 html 的 scroll-padding-top，而不是 section 的 scroll-margin-top。
   实测在 scroll-snap-type:mandatory 下，section 上的 scroll-margin-top:64px
   不会被浏览器结算（滚到 1041 也不被拉回吸附点）。
   而 scroll-padding-top 挂在真正的滚动容器 html 上则完全可靠：
   区块停靠时其顶部恰好停在「视口顶 + 64px」= 导航栏下沿。 */
html.page-snap {
  scroll-snap-type: y mandatory;
  /* 触摸设备加回弹阻尼，手感更接近原生分页 */
  overscroll-behavior-y: none;
  /* 为固定导航预留 64px：区块顶部停在导航栏下沿，而不是被导航遮住 */
  scroll-padding-top: 64px;
}
/* 参与吸附的区块：顶部对齐、必须占满一屏才停靠。
   不设 scroll-margin-top —— 见上方「关键2」，导航让位由 html 的 scroll-padding-top 负责。 */
html.page-snap .home > section {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
/* 页脚作为吸附终点（end）：让 mandatory 吸附能「停在页脚」，否则浏览器
   只会把滚动强制拉回最后一个区块，导致永远滑不到页脚。
   配合 snap.js 末屏下滚放行（不加阈值），滚轮越过末屏即自然落向页脚。 */
html.page-snap body > footer { scroll-snap-align: end; }

/* ==========================================================================
   X20b. 顶栏毛玻璃恢复 —— Hero 顶边延伸到 y=0（2026-10-04，仅 PC ≥901px）
   --------------------------------------------------------------------------
   病因（用户反馈「顶栏在顶部时没有毛玻璃效果，往下滑动才有」）：
     #masthead 是 fixed 毛玻璃（blur 24px），毛玻璃效果 = 模糊它**背后**的内容。
     原 .home 只上移 -32px（抵消 #app 96px 顶距中的 32px）→ Hero 顶边正好压在
     y=64（顶栏底缘），加上 .hero overflow:hidden 把光晕裁在 y=64 以下 ——
     页面停在顶部时顶栏背后只有 body 白底，无物可糊；下滑后内容滚入顶栏
     背后，毛玻璃才"出现"。
   修复：.home 上移 -96px（抵消全部 #app 顶距）→ Hero 顶边到 y=0，
     顶栏背后就是 Hero（含光晕）；同时 Hero 高度补回 64px、顶部 padding
     64→128px，内容几何位置、下方区块、吸附测量（--home-maxh）全部不变。
   移动端（≤900px）导航 60px 且布局独立，维持原样不受影响。
   配套：glow.js G9 把 g1 圆心约束在上部锚定区，保证顶栏背后恒定有光晕。
   ========================================================================== */
@media (min-width: 901px) {
  .home { margin-top: -96px; }
  /* ⚠️ 用 .home .hero（0,2,0）而不是 .hero（0,1,0）：
     .home section { padding: 72px 0 } 的特异性 (0,1,1) 更高，会压住单类选择器，
     实测 padding 失效导致内容整体上移 32px（flex 居中点多算 64px 差值的一半）。

     ⚠️ 高度必须是 **100vh 满屏**，不能是 calc(100vh - 64px)：
     上面 .home 上移了 96px（顶栏 64 + 需求15 的 32），hero 顶边已到 y=0，
     若高度再减 64px，hero 底部就比视口矮 64px → 首屏底部露出下方区块，
     正是用户反馈的「第一个区域没有撑满」。
     其它区块（非hero）仍用 calc(100vh - 64px)，与 E:\difansclub 参考版一致。 */
  .home .hero {
    min-height: 100vh;
    padding: 128px 0 64px;
  }
}
@supports (height: 100dvh) {
  @media (min-width: 901px) {
    html.page-snap .home .hero { min-height: 100dvh; }
  }
}

/* 移动端导航高 60px，吸附偏移与区块高度同步切换 */
@media (max-width: 900px) {
  html.page-snap .home section,
  html.page-snap .home .hero { min-height: calc(100dvh - 64px); }
  /* 移动端导航 60px：同步收紧 scroll-padding-top */
  html.page-snap { scroll-padding-top: 60px; }

  /* ---------- 移动端整屏吸附的内容压缩 ----------
     scroll-snap mandatory 的前提是「吸附元素高度 ≤ 吸附区间高度」，
     否则浏览器无法结算停靠点，表现为滚一点就卡住或停在两屏之间。
     实测一屏 = 784px，各区块原高度与超出量：
       1 Hero 784(0) / 2 三大功能 1317(+533) / 3 热门下载 846(+62)
       4 攻略 1023(+239) / 5 社区动态 1467(+683)
     因此在移动端 +吸附开启时，逐块收紧内边距与卡片尺寸，让 5 屏都装进 784px。 */
  html.page-snap .home section { padding: 40px 0; }
  html.page-snap .home section .sec-head { margin: 0 0 20px; }
  html.page-snap .home section .sec-head h2 { font-size: 22px; margin-bottom: 8px; }
  html.page-snap .home section .sec-head p { font-size: 13.5px; }

  /* 第 2 块：4 张功能卡由 4 列改 2 列会更高，这里保持 1 列但压缩卡片内边距与图标 */
  html.page-snap .home section:nth-of-type(2) .features { gap: 12px; }
  html.page-snap .home section:nth-of-type(2) .feature { padding: 16px 18px; }
  html.page-snap .home section:nth-of-type(2) .feature .ico {
    width: 40px; height: 40px; border-radius: var(--r-card); margin-bottom: 12px;
  }
  html.page-snap .home section:nth-of-type(2) .feature .ico .icon { width: 20px; height: 20px; }
  html.page-snap .home section:nth-of-type(2) .feature h3 { font-size: 16px; margin-bottom: 6px; }
  html.page-snap .home section:nth-of-type(2) .feature p { font-size: 13px; line-height: 1.6; margin-bottom: 10px; }

  /* 第 3 块：4 张资源卡（2 列 × 2 排）
     卡宽仅 169px，长固件名（如 IDCC-B10_UR_OTA_…_Encrypt_Beta.zip）需要 3 行才放得下，
     实测 2 行 clamp 会把第 3 行裁掉。这里正文区给到 120px（3×17.7=53 + meta 30 + 内边距 18= 101，留 19px 余量），
     缩略图相应压到 88px，两者合计仍为208px，不破坏五块等高。 */
  html.page-snap .home section:nth-of-type(3) .thumb { height: 88px; }
  html.page-snap .home section:nth-of-type(3) .card .body { height: 120px; padding: 10px 12px 8px; }
  html.page-snap .home section:nth-of-type(3) .card h4 {
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
    overflow: hidden; word-break: break-all;
  }
  html.page-snap .home section:nth-of-type(3) .card h4 { font-size: 13px; margin-bottom: 6px; }
  html.page-snap .home section:nth-of-type(3) .card .meta { height: 30px; }
  html.page-snap .home section:nth-of-type(3) .hot-dl-dots { margin-top: 14px; }

  /* 第 4 块：4 张攻略卡（1 列 × 4）*/
  html.page-snap .home section:nth-of-type(4) .guide-list { gap: 12px; }
  html.page-snap .home section:nth-of-type(4) .guide { padding: 14px 16px; gap: 14px; }
  html.page-snap .home section:nth-of-type(4) .guide .rank { font-size: 22px; }
  html.page-snap .home section:nth-of-type(4) .guide h4 { font-size: 14.5px; margin-bottom: 5px; }
  html.page-snap .home section:nth-of-type(4) .guide p { font-size: 12.5px; line-height: 1.6; }

  /* 第 5 块：6 张社区帖（1 列 × 6，超出最多，压得最狠） */
  html.page-snap .home section:nth-of-type(5) .posts { gap: 12px; }
  html.page-snap .home section:nth-of-type(5) .post { padding: 16px; }
  html.page-snap .home section:nth-of-type(5) .post .avatar { width: 34px; height: 34px; }
  html.page-snap .home section:nth-of-type(5) .post .text {
    font-size: 13px; line-height: 1.6; margin-bottom: 12px;
  }
  html.page-snap .home section:nth-of-type(5) .post .reacts { font-size: 12px; }
}
/* 触摸设备已在 html.page-snap 上设过 overscroll-behavior-y，这里不再重复。 */

/* 区块标题（.sec-head）
   margin/margin-bottom 的显式声明不是为了好看，而是为了修一个真实的对齐 bug：
   h2 继承了全局 h1~h6 的 margin-top: .88em（34px × 0.83 ≈ 28.22px）。
   原本这个上边距会通过 margin 折叠「悬在」.wrap 外面（不占内容高度），
   但.sec-head 自身带 margin-bottom，父级 .wrap 是 flex 子项 —— 折叠条件不成立，
   h2 的 28px 就实打实把标题往下推，结果是：
     区块盒子用 flex align-items:center 居中的是 .wrap（含那 28px 空档），
     而人眼看到的是标题文字与卡片 → 视觉上「上留白比下留白多 28~29px」。
   实测五块都偏 28~29px（第2块 222/194、第3块 120/91、第4块 200/171、第5块 150/122）。
   修法：h2 上边距显式归零、.sec-head 自身不带上边距，
   让 .sec-head 的盒高 = 真实内容高，居中才与视觉一致。 */
.sec-head { text-align: center; margin: 0 0 44px; }
.sec-head h2 { font-size: 34px; font-weight: 800; letter-spacing: -.5px; margin: 0 0 12px; color: var(--ink); }
.sec-head p { font-size: 15.5px; color: var(--ink-2); margin: 0; }

/* 功能卡（第 2 区块「你要的，这儿都有」）
   4 列布局，卡片尺寸保持小艺主题的基准值：内边距 34px 30px、图标 56px、标题 19px。
   区块本身是「一屏高减去导航栏 + 内容垂直居中」，卡片不刻意放大——
   高度由 --home-maxh 统一，卡片保持紧凑才不会在 4 列窄格里显得臃肿。 */
.features { display: grid; grid-template-columns: repeat(4, 1fr); gap: 22px; }
.feature {
  background: rgba(255,255,255,.85); border: 1px solid var(--line-soft); border-radius: var(--r-card);
  padding: 34px 30px; transition: .25s; box-shadow: var(--shadow-card);
}
.feature:hover { transform: translateY(-5px); box-shadow: var(--shadow-float); }
/* 图标块 */
.feature .ico { width: 56px; height: 56px; border-radius: var(--r-panel); margin-bottom: 22px; }
.feature .ico .icon { width: 26px; height: 26px; }
/* 链接吸底 */
.feature h3 { font-size: 19px; margin: 0 0 10px; }
.feature p { font-size: 14px; line-height: 1.7; margin: 0 0 18px; }
.feature .link { font-size: 13px; gap: 5px; margin-top: auto; }
.feature .link .icon { width: 15px; height: 15px; }
.ico { width: 56px; height: 56px; border-radius: var(--r-ico); display: grid; place-items: center; color: #fff; margin-bottom: 22px; position: relative; overflow: hidden; }
.ico::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: linear-gradient(160deg, hsla(0,0%,100%,.45), transparent 45%); }
.ico .icon { width: 26px; height: 26px; position: relative; z-index: 1; }
.f-blue .ico { background: var(--grad-blue); }
.f-violet .ico { background: var(--grad-violet); }
.f-teal .ico { background: var(--grad-teal); }
.f-gold .ico { background: var(--grad-gold); }
.feature h3 { font-size: 19px; font-weight: 700; margin-bottom: 10px; }
.feature p { font-size: 14.5px; color: var(--ink-2); line-height: 1.75; }
.feature .link { display: inline-flex; align-items: center; gap: 5px; margin-top: 18px; font-size: 14px; font-weight: 600; color: var(--accent); }
.feature .link svg { width: 15px; height: 15px; transition: .2s; }
.feature:hover .link svg { transform: translateX(3px); }

/* 资源卡片 */
.grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; align-items: stretch; }
.card { background: #fff; border: 1px solid var(--line-soft); border-radius: var(--r-card); overflow: hidden; transition: .25s; box-shadow: var(--shadow-card); cursor: pointer; display: flex; flex-direction: column; height: 100%; }
/* 四卡等高：缩略图 152px + 正文区固定高度（文件名最多两行 + 底部信息 44px） */
.card .body { min-height: 112px; }
.card:hover { transform: translateY(-5px); box-shadow: var(--shadow-float); }
/* ---------- 本周热门下载轮播 ---------- */
.hot-dl { position: relative; }
/* 切换页时的淡入动效（不用 both，避免 headless/快速切换时卡在起始帧） */
.hot-dl .grid { animation: hotDlFade .4s ease; }
@keyframes hotDlFade { from { opacity: .25; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.hot-dl-dots { display: flex; justify-content: center; align-items: center; gap: 7px; margin-top: 22px; min-height: 10px; }
.hot-dl-dot {
  width: 7px; height: 7px; padding: 0; border: 0; border-radius: 50%;
  background: var(--rule-2); cursor: pointer; transition: .25s;
}
.hot-dl-dot:hover { background: var(--ink-3); }
.hot-dl-dot.active { width: 22px; border-radius: 999px; background: var(--accent); }


/* 缩略图容器：图标用绝对定位强制居中，避免 flex/grid 布局受其他元素（如左上角标签）影响产生偏移 */
.thumb { height: 152px; flex: none; position: relative; display: block; color: #fff; overflow: hidden; }
/* 两层高光叠加，做出玻璃/釉面质感：
   ① ::before 右上角冷光（模拟环境反射）—— 静态白纱+ 极淡蓝调；
   ② ::after 顶部到底部的柔光渐变（原有逻辑，保留）。
   注意：两个伪元素都只是**覆盖层**，不改变底色渐变本身。 */
.thumb::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(120% 90% at 82% 6%, hsla(0, 0%, 100%, .30) 0%, hsla(0, 0%, 100%, 0) 55%),
    linear-gradient(160deg, hsla(0, 0%, 100%, .14), transparent 42%);
}
.thumb::after { content: ""; position: absolute; inset: 0; z-index: 0; background: linear-gradient(180deg, hsla(0,0%,100%,.16), hsla(0,0%,100%,.04) 50%, transparent 85%); }
.thumb svg { position: absolute; top: 46%; left: 50%; transform: translate(-50%, -50%); width: 46px; height: 46px; opacity: .95; z-index: 1; }

/* 车型配置标签：缩略图右上角，与左上角的类型标签同一行。
   两个标签都用绝对定位（.card .tag 是 top/left，这里是 top/right），
   这样它们各自贴边、内容长短不影响对方，行内对齐由相同的 top 值保证。
   max-width 用 calc 给类型标签留出空间：类型标签约 60px 宽 + 左右各 12px 内边距，
   车型标签最多占剩余宽度，超长省略号截断。 */
.card .car-model {
  /* 2026-10-04 用户要求：去掉文件类型标签（压缩包/文档），
     车型标签保留并移到**左上角**（原在右上角 right:12px）。
     max-width 改为留出右侧空间，避免长车型名压到卡片右缘。 */
  position: absolute; top: 12px; left: 12px;
  z-index: 2; max-width: calc(100% - 24px);
  background: rgba(255,255,255,.94); color: var(--ink);
  font-size: 12px; font-weight: 600; line-height: 1;
  padding: 0 12px; height: 24px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-btn);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.th1 { background: var(--grad-blue); }
.th2 { background: var(--grad-violet); }
.th3 { background: var(--grad-teal); }
.th4 { background: var(--grad-gold); }
.th5 { background: linear-gradient(135deg, #5b6b7f 0%, #8494a6 55%, #aab8c6 100%); }

/* 固件列表：按文件类型的图标配色（与首页卡片同一套 tone） */
.row-icon.file { display: inline-flex; align-items: center; justify-content: center; flex: none; }
.row-icon.file svg { width: 17px; height: 17px; display: block; }
.row-icon.file.k-blue { color: var(--accent); }
.row-icon.file.k-violet { color: #7c5cf0; }
.row-icon.file.k-teal { color: #0e9aa7; }
.row-icon.file.k-gold { color: #d98407; }
.row-icon.file.k-gray { color: var(--ink-3); }
/* 资源卡类型标签：文字在胶囊内水平/垂直居中。
   需屏蔽 app.css 的 .tag{gap:5px} 与 ::before 小圆点，否则会多出 10px 左侧偏移。 */
.card .tag {
  position: absolute; top: 12px; left: 12px; z-index: 2;
  /* 清掉 app.css 的 .tag{margin-top:8px}：它是给文档流里的标签用的，
     在绝对定位下会叠加到 top 上（实测 12+8=20px），
     导致类型标签与右上角的车型标签差 8px、不在同一行。 */
  margin-top: 0;
  background: rgba(255,255,255,.92); color: var(--ink);
  font-size: 12px; font-weight: 600; line-height: 1;
  padding: 0 12px; height: 24px; border-radius: var(--r-btn);
  white-space: nowrap; display: inline-flex;
  align-items: center; justify-content: center;
  gap: 0;
}
.card .tag::before { display: none; content: none; }
/* 正文区：grid 三行 —— 文件名自适应 / 弹性空隙 / 底部信息固定，保证一行或两行文件名时底部信息都在同一水平线 */
.card .body {
  padding: 12px 16px 0; display: grid;
  grid-template-rows: auto 1fr auto; row-gap: 0;
}
/* 文件名限两行省略；不加 min-height，避免文字被行盒推离缩略图 */
.card h4 {
  font-size: 14.5px; font-weight: 600; line-height: 1.45; margin: 0 0 8px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; word-break: break-all;
}
/* 底部信息：固定高度吸底（无分隔线），跨卡片底部对齐 */
.card .meta {
  font-size: 12.5px; color: var(--ink-3);
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  height: 44px; align-self: end;
}
.card .meta .size { white-space: nowrap; }
.card .dl { display: inline-flex; align-items: center; gap: 4px; color: var(--accent); font-weight: 600; white-space: nowrap; }
.card .dl svg { width: 13px; height: 13px; }

/* 攻略 */
.guide-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; }
.guide { display: flex; gap: 20px; background: #fff; border: 1px solid var(--line-soft); border-radius: var(--r-card); padding: 26px; transition: .25s; box-shadow: var(--shadow-card); cursor: pointer; }
.guide:hover { transform: translateY(-4px); box-shadow: var(--shadow-float); }
.guide .rank { font-size: 36px; font-weight: 800; line-height: 1.1; color: var(--accent); flex: none; opacity: .9; }
.guide h4 { font-size: 16.5px; font-weight: 700; margin-bottom: 8px; }
.guide p { font-size: 14px; color: var(--ink-2); line-height: 1.65; margin-bottom: 12px; }
.chips { display: flex; gap: 8px; flex-wrap: wrap; }
.chip { font-size: 12px; font-weight: 500; color: var(--ink-2); background: var(--bg-gray); padding: 4px 12px; border-radius: var(--r-btn); }

/* 社区动态 */
.posts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.post { background: #fff; border: 1px solid var(--line-soft); border-radius: var(--r-card); padding: 24px; transition: .25s; box-shadow: var(--shadow-card); cursor: pointer; }
.post:hover { transform: translateY(-4px); box-shadow: var(--shadow-float); }
.post .user { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.avatar { width: 42px; height: 42px; border-radius: 50%; overflow: hidden; color: #fff; display: grid; place-items: center; font-weight: 700; font-size: 15px; }
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 50%; }
.post .name { font-size: 14.5px; font-weight: 700; }
.post .time { font-size: 12px; color: var(--ink-3); }
.post .text { font-size: 14.5px; line-height: 1.75; color: var(--ink-2); margin-bottom: 16px; }
.post .reacts { display: flex; gap: 20px; font-size: 13px; color: var(--ink-3); }
.post .reacts span { display: inline-flex; align-items: center; gap: 5px; }
.post .reacts svg { width: 15px; height: 15px; }

/* CTA —— 浅色玻璃卡片（渲染图原样） */
.cta { background: rgba(255,255,255,.8); border: 1px solid var(--line-soft); border-radius: 32px; padding: 64px 48px; text-align: center; box-shadow: var(--shadow-card); position: relative; overflow: hidden; }
.cg1 { width: 420px; height: 280px; left: 50%; top: -160px; transform: translateX(-50%); background: radial-gradient(closest-side, rgba(95,151,255,.35), transparent); }
.cg2 { width: 300px; height: 220px; left: -80px; bottom: -120px; background: radial-gradient(closest-side, rgba(255,213,154,.35), transparent); }
.cg3 { width: 300px; height: 220px; right: -80px; bottom: -120px; background: radial-gradient(closest-side, rgba(190,86,232,.2), transparent); }
.cta .inner { position: relative; z-index: 1; }
.cta h2 { font-size: 34px; font-weight: 800; letter-spacing: -.5px; margin-bottom: 12px; color: var(--ink); }
.cta p { font-size: 15.5px; color: var(--ink-2); margin-bottom: 30px; }

/* 渲染图按钮类名兼容 */
.btn.btn-primary { background: var(--accent); color: #fff; border: none; box-shadow: 0 6px 16px rgba(17,17,17,.28); }
.btn.btn-primary:hover { background: #000000; transform: translateY(-1px); }

/* —— 响应式（对齐渲染图） —— */
@media (max-width: 1180px) {
  .features { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 900px) {
  .home .wrap { padding: 0 20px; }
  .hero { min-height: calc(100vh - 60px); padding: 60px 0 56px; }
  /* 第 2 区块同步：移动端导航栏 60px */
  .home section:nth-of-type(2) { min-height: calc(100vh - 60px); padding: 60px 0 56px; }
  /* 第 3 区块同步：移动端卡片 2 列、8 张自然撑开不裁切，仅对齐导航栏高度 */
  .home section:nth-of-type(3) { min-height: calc(100vh - 60px); padding: 48px 0; }
  .home section:nth-of-type(3) .sec-head { margin: 0 0 24px; }
  /* 第 4、5 区块同步：移动端均为单列、内容远超一屏，由 min-height 兜底自然撑开 */
  .home section:nth-of-type(4),
  .home section:nth-of-type(5) { min-height: calc(100vh - 64px); padding: 52px 0; }
  .features { grid-template-columns: 1fr; }
  .grid { grid-template-columns: 1fr 1fr; }
  .posts { grid-template-columns: 1fr; }
  .guide-list { grid-template-columns: 1fr; }
  .hero h1 { font-size: 38px; }
  .stats { gap: 32px; }
  .stat .num { font-size: 24px; }
  /* 顶栏窄屏：登录态胶囊仅留头像，隐藏用户名（底部 TAB 已有入口） */
  .masthead-actions .nav-user { padding: 0 6px; }
  .masthead-actions .nav-user-text { display: none; }
  .masthead-cta { height: 38px; padding: 0 18px; font-size: 14px; }
}
@media (max-width: 640px) {
  .hero { padding: 60px 0 56px; }
  .hero h1 { font-size: 30px; letter-spacing: -.3px; margin-top: 20px; }
  .hero .sub { font-size: 15px; }
  .badge { font-size: 12px; }
  .search-card { border-radius: var(--r-panel); margin-top: 30px; }
  .search-top { padding: 18px 16px 12px; }
  .search-top input { font-size: 15px; }
  .search-bar { padding: 0 10px 10px 16px; }
  .seg { flex: 1; }
  .seg-btn { flex: 1 1 0; min-width: 0; font-size: 13px; padding: 9px 8px; text-align: center; }
  .hot-words { gap: 8px; margin-top: 18px; }
  .hot-words a { font-size: 12.5px; padding: 7px 14px; }
  .stats { gap: 20px; flex-wrap: wrap; justify-content: center; margin-top: 40px; }
  .stat { min-width: 88px; }
  .stat .num { font-size: 22px; }
  .stat .lab { font-size: 12.5px; }
  .home section { padding: 52px 0; }
  /* 末位区块不再额外加 padding-bottom（见桌面端同处注释），底部距离由 min-height 自然产生 */
  .sec-head { margin: 0 0 32px; }
  .sec-head h2 { font-size: 26px; }
  .sec-head p { font-size: 14.5px; }
  .grid { grid-template-columns: 1fr 1fr; gap: 12px; }
  .thumb { height: 108px; }
  .thumb svg { width: 36px; height: 36px; }
  .card .body { padding: 14px 12px 12px; }
  .card h4 { font-size: 13.5px; }
  .card .meta { font-size: 11px; gap: 6px; }
  .feature { padding: 28px 22px; }
  .feature h3 { font-size: 18px; }
  .ico { width: 52px; height: 52px; }
  .guide { padding: 20px; gap: 14px; }
  .guide .rank { font-size: 28px; }
  .guide h4 { font-size: 15.5px; }
  .post { padding: 20px; }
  .cta { padding: 44px 22px; border-radius: var(--r-panel); }
  .cta h2 { font-size: 26px; }
  .cta p { font-size: 14.5px; }
}

/* 搜索跳转提示条（社区/攻略页顶部） */
.search-hint {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--brand-wash); border: 1px solid rgba(17, 17, 17, .18);
  border-radius: var(--radius); padding: 10px 16px; margin-bottom: 16px;
  font-size: 13.5px; color: var(--ink-2);
}
.search-hint a { color: var(--brand); font-weight: 600; flex: none; }
.search-hint a:hover { text-decoration: underline; }

/* ==========================================================================
   X14. 页脚多列（渲染图 foot-grid，覆盖 X6 单行样式）
   ========================================================================== */
footer { padding: 56px 0 56px; margin-top: 80px; text-align: left; }
/* --------------------------------------------------------------------------
   首页第 5 区块与底栏的间距压缩（桌面端专属）
   --------------------------------------------------------------------------
   用户反馈（2026-10-04）：桌面端下滑到底时，第 5 区块与底栏之间空白太大，
   要「减少一个底栏的高度」，让第 5 区块下滑时**直接出现底栏**，
   而不是先看到一片空白、再滑一下才见底栏。

   放在这里（而不是上面的间距注释处）是因为本段`footer{margin-top:80px}`
   位置更靠后、特异性相同会覆盖前面的声明。

   压缩量 = 一个底栏高度（TAB 高 66px，桌面取 64px）：
     · footer margin-top  80px  → 16px（减 64）—— 主力
     · #app padding-bottom 保持 40px 不动（避免连带影响其它页面）
   合计 120px → 56px。

   ⚠️ 严格限定 min-width:901px：移动端末尾是 #tabbar（高 66px）不是页脚，
   移动端靠 #app 的 padding-bottom 96px 把内容顶开底栏，
   若不加限定会压掉移动端末区块到 TAB 的间距（用户明确要求不能影响）。 */
@media (min-width: 901px) {
  /* ⚠️ 两个必须点：
   *1) !important —— app.css:201 的 `footer{margin-top:auto}` 是 flex 自动外边距
     （把页脚推到底部、吃掉全部剩余空间），普通 px 声明**覆盖不了 auto**。
     这正是「底部空白过大」的根因。
   * 2) 选择器**不能**用 `#app + footer` —— 实测 footer 的上一个兄弟是
     `<div id="boot">`（首屏加载层），不是 #app，相邻兄弟选择器永不匹配。
     故直接用 `body:has(.home) footer`（后代选择器）。 */
  body:has(.home) footer { margin-top: 16px !important; }
}
.foot-grid {
  max-width: 1080px; margin: 0 auto; padding: 0 36px;
  display: grid; grid-template-columns: 1fr auto; gap: 24px 32px;
  align-items: center;
  position: relative; z-index: 1;
}
.foot-col h5 { font-size: 14.5px; font-weight: 700; margin-bottom: 18px; color: rgba(255,255,255,.9); }
.foot-col a { display: block; font-size: 13.5px; color: rgba(255,255,255,.5); margin-bottom: 12px; transition: .2s; }
.foot-col a:hover { color: #fff; }
/* 协议链接：横向紧凑排列（无分组标题） */
.foot-links { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 22px; }
.foot-links a { font-size: 13.5px; color: rgba(255,255,255,.5); transition: .2s; }
.foot-links a:hover { color: #fff; }
.foot-brand { display: flex; align-items: center; }
.foot-brand .logo { color: #fff; font-weight: 700; font-size: 18px; display: flex; align-items: center; gap: 10px; }
.foot-brand .logo .mark { width: 30px; height: 30px; border-radius: var(--r-ctl); background: transparent; display: grid; place-items: center; overflow: hidden; }
.foot-brand .logo .mark img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* 右栏：协议链接 + 版权信息，上下两行右对齐 */
.foot-aside { display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }
.foot-aside .copyright { margin: 0; padding: 0; border: 0; font-size: 12.5px; color: rgba(255,255,255,.4); text-align: right; }
#footerText { max-width: none; margin: 0; }
@media (max-width: 900px) {
  .foot-grid { grid-template-columns: 1fr auto; gap: 24px; }
  .foot-aside { align-items: flex-start; }
  .foot-aside .copyright { text-align: left; }
}
@media (max-width: 640px) {
  .foot-grid { grid-template-columns: 1fr; gap: 24px; }
  .foot-brand p { max-width: 100%; }
}

/* ==========================================================================
   X16. 页脚方案 C —— 品牌蓝渐变 · 单行条
   --------------------------------------------------------------------------
   覆盖 X6（黑色星空）与 X14（黑色多列），改为一条品牌蓝紫渐变横条：
   高度压缩、左右分栏单行排列、顶部大圆角，呼应首页品牌蓝。
   ========================================================================== */
footer {
  position: relative;
  margin-top: 80px;
  padding: 0;
  background:
    radial-gradient(120% 160% at 8% 120%, rgba(255, 255, 255, .22), transparent 55%),
    linear-gradient(100deg, #111111 0%, #2f7bf8 38%, #5a63f3 68%, #6a2bf0 100%);
  color: rgba(255, 255, 255, .72);
  border-top: 0;
  border-radius: 28px 28px 0 0;
  box-shadow: 0 -18px 44px rgba(17, 17, 17, .22);
  overflow: hidden;
  text-align: left;
  isolation: isolate;
}
/* 细高光条，强化玻璃质感 */
footer::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .55), transparent);
  opacity: 1; pointer-events: none; z-index: 2;
}
/* 斜向光带，替代原星点 */
footer::after {
  content: ""; position: absolute; z-index: 0; pointer-events: none;
  left: -10%; top: -180%; width: 60%; height: 460%;
  transform: rotate(18deg);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .16), transparent);
  opacity: 1;
}
/* ---------- 单行条：Logo · 协议链接 · 版权 全部同一基线 ---------- */
.foot-grid {
  position: relative; z-index: 1;
  max-width: 1280px; margin: 0 auto; padding: 0 36px;
  min-height: 76px;
  display: flex; flex-direction: row; align-items: center; justify-content: space-between;
  gap: 24px; flex-wrap: nowrap;      /* 桌面端强制单行，不换行 */
}
.foot-brand { display: flex; align-items: center; flex: 0 1 auto; min-width: 0; }
.foot-brand .logo {
  color: #fff; font-weight: 700; font-size: 17px; letter-spacing: .01em;
  display: flex; align-items: center; gap: 10px;
  white-space: nowrap;
}
.foot-brand .logo .mark {
  flex: none;
  width: 30px; height: 30px; border-radius: var(--r-ctl); background: rgba(255, 255, 255, .18);
  display: grid; place-items: center; overflow: hidden;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .45);
}
.foot-brand .logo .mark img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* 右侧：协议链接 + 版权，同一行内并排 */
.foot-aside {
  display: flex; flex-direction: row; align-items: center; justify-content: flex-end;
  gap: 16px; flex-wrap: nowrap; flex: 0 1 auto; min-width: 0;
}
.foot-links { display: flex; align-items: center; flex-wrap: nowrap; gap: 20px; }
.foot-links a {
  position: relative; white-space: nowrap;
  font-size: 13.5px; font-weight: 500;
  color: rgba(255, 255, 255, .82);
  transition: color .2s ease;
}
.foot-links a::after {
  content: ""; position: absolute; left: 50%; right: 50%; bottom: -3px; height: 1.5px;
  background: #fff; border-radius: 2px;
  transition: left .26s cubic-bezier(.22, 1, .36, 1), right .26s cubic-bezier(.22, 1, .36, 1);
}
.foot-links a:hover { color: #fff; }
.foot-links a:hover::after { left: 0; right: 0; }
.foot-aside .copyright {
  margin: 0; padding: 0 0 0 16px; border: 0;
  border-left: 1px solid rgba(255, 255, 255, .28);
  font-size: 12.5px; color: rgba(255, 255, 255, .6);
  text-align: right; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
#footerText { max-width: none; margin: 0; }

footer a { color: rgba(255, 255, 255, .82); }
footer a:hover { color: #fff; }
.foot-sep { color: rgba(255, 255, 255, .3); margin: 0 6px; }

/* 深色模式：渐变压暗一档，与深色页面衔接 */
[data-theme="dark"] footer {
  background:
    radial-gradient(120% 160% at 8% 120%, rgba(255, 255, 255, .12), transparent 55%),
    linear-gradient(100deg, #062a86 0%, #123a9c 40%, #2a2f8f 70%, #341a72 100%);
  box-shadow: 0 -16px 40px rgba(0, 0, 0, .5);
}

@media (max-width: 1180px) {
  .foot-grid { padding: 0 28px; gap: 18px; }
  .foot-links { gap: 16px; }
  .foot-aside .copyright { padding-left: 12px; }
}
/* 窄屏放不下时版权先省略号截断，仍保持一行 */
@media (max-width: 980px) {
  .foot-aside .copyright { display: none; }
}
@media (max-width: 700px) {
  .foot-grid { min-height: 68px; padding: 12px 20px; gap: 14px; }
  .foot-brand .logo { font-size: 15px; }
  .foot-brand .logo .mark { width: 26px; height: 26px; border-radius: var(--r-ctl); }
  /* 链接允许内部换行，宁可折行也不丢链接 */
  .foot-links { flex-wrap: wrap; justify-content: flex-end; row-gap: 2px; column-gap: 12px; }
  .foot-links a { font-size: 12.5px; }
}
@media (max-width: 480px) {
  footer { border-radius: var(--r-panel) 22px 0 0; margin-top: 56px; }
  .foot-grid { flex-direction: column; align-items: flex-start; gap: 8px; }
  .foot-aside { width: 100%; justify-content: flex-start; }
  .foot-links { justify-content: flex-start; }
}

/* ==========================================================================
   X17. 协议 / 政策页（用户协议 · 隐私政策 · 免责声明）
   方案 B · 沉浸阅读：720 正文 + 208 目录；黑白令牌；零边框零阴影
   ========================================================================== */
.ag-page {
  --ag-card: #ffffff;
  --ag-wash: #f5f5f5;
  --ag-elev: #ffffff;
  --ag-ink: #111111;
  --ag-ink-2: #4b4b4b;
  --ag-ink-3: #666666;
  --ag-hover-card: #efefef;
  --ag-hover-wash: #e5e5e5;
  --ag-press: #d9d9d9;
  --ag-selected: #e8e8e8;
  --ag-selected-hover: #dddddd;
  --ag-solid: #111111;
  --ag-solid-hover: #2a2a2a;
  --ag-solid-ink: #ffffff;

  display: flex;
  flex-direction: column;
  gap: var(--page-gap);
  max-width: none;
  margin: 0;
  padding: 0;
  color: var(--ag-ink);
}
:root[data-theme="dark"] .ag-page {
  --ag-card: #161616;
  --ag-wash: #1e1e1e;
  --ag-elev: #242424;
  --ag-ink: #f5f5f5;
  --ag-ink-2: #b8b8b8;
  --ag-ink-3: #a3a3a3;
  --ag-hover-card: #242424;
  --ag-hover-wash: #2c2c2c;
  --ag-press: #383838;
  --ag-selected: #333333;
  --ag-selected-hover: #3d3d3d;
  --ag-solid: #f5f5f5;
  --ag-solid-hover: #e5e5e5;
  --ag-solid-ink: #0b0b0c;
}
.ag-page + footer { margin-top: 16px; }

/* 后台协议预览仍复用这四条基础类，保持原有取值（前台由 .ag-page 作用域覆盖） */
.ag-p { margin: 0 0 12px; font-size: 14.5px; line-height: 1.95; color: var(--ink-2); }
.ag-ch { margin-bottom: 30px; }
.ag-check {
  display: flex; gap: 10px; align-items: flex-start;
  list-style: none; margin: 0 0 9px; font-size: 14.5px; line-height: 1.85; color: var(--ink-2);
}
.ag-check-box {
  width: 19px; height: 19px; border-radius: var(--r-micro); flex: none; margin-top: 4px;
  background: rgba(17, 17, 17, .1);
  display: grid; place-items: center;
}

/* ---------- 头部卡片：与固件资源页 / 意见反馈页同款 ---------- */
.ag-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap;
  padding: 16px 20px;
  border: 0; border-radius: var(--r-card);
  background: var(--ag-card);
}
.ag-head__main { min-width: 0; }
.ag-head__kicker {
  display: block; color: var(--ag-ink-3);
  font-size: 11px; font-weight: 600; line-height: 1.4;
  letter-spacing: .08em; text-transform: uppercase;
}
.ag-head__title {
  margin: 4px 0 8px; color: var(--ag-ink);
  font-size: 22px; font-weight: 700; line-height: 1.3; letter-spacing: .01em;
}
.ag-head__lead { margin: 0; color: var(--ag-ink-2); font-size: 13px; line-height: 1.55; }
.ag-head__lead b { color: var(--ag-ink); font-weight: 600; }
.ag-head__stats { display: grid; grid-template-columns: repeat(2, 96px); gap: 8px; flex: none; }
.ag-stat {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 0; padding: 12px 16px; border: 0;
  border-radius: var(--r-ctl); background: var(--ag-wash); text-align: center;
}
.ag-stat b {
  color: var(--ag-ink); font-size: 18px; font-weight: 600; line-height: 1.2;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.ag-stat span { color: var(--ag-ink-2); font-size: 12px; line-height: 1.4; }
.ag-switch {
  display: inline-flex; align-items: center; gap: 2px;
  align-self: flex-start;
  max-width: 100%; margin: 0; padding: 3px;
  border-radius: calc(var(--r-ctl) + 2px); background: var(--seg-bg);
  overflow-x: auto; scrollbar-width: none;
}
.ag-switch::-webkit-scrollbar { width: 0; height: 0; }
.ag-switch-item {
  display: inline-flex; align-items: center; justify-content: center;
  height: 30px; padding: 0 12px;
  border: 0; border-radius: var(--r-ctl);
  background: transparent; color: var(--ag-ink-2);
  font-family: inherit; font-size: 12.5px; line-height: 1.4; font-weight: 400;
  text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: background-color .12s, color .12s;
}
.ag-switch-item:hover { background: var(--seg-hover); color: var(--ag-ink); }
.ag-switch-item.is-on,
.ag-switch-item.is-on:hover {
  background: var(--ag-solid); color: var(--ag-solid-ink); font-weight: 600;
}
.ag-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 0 auto; }
.ag-meta-item {
  padding: 4px 8px; border-radius: var(--r-pill);
  background: var(--ag-wash); color: var(--ag-ink-2);
  font-size: 12px; line-height: 1.5;
}

/* ---------- 阅读栅格：正文 + 272 目录，铺满内容区（四边内距对齐首页 25px） ---------- */
.ag-read {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(272px, max-content);
  grid-template-areas: "doc toc";
  gap: 16px;
  justify-content: stretch;
  align-items: start;
  width: 100%;
}
.ag-doc {
  grid-area: doc; min-width: 0; padding: 20px 22px;
  border: 0; border-radius: var(--r-card);
  background: var(--ag-card); box-shadow: none;
}

/* ---------- 正文 ---------- */
.ag-lead {
  margin: 0 0 16px; padding: 12px;
  border-radius: var(--r-ctl); background: var(--ag-wash);
  color: var(--ag-ink-2); font-size: 13px; line-height: 1.65;
}
.ag-intro { margin: 0 0 8px; }
.ag-page .ag-p {
  margin: 0 0 12px; font-size: 14px; line-height: 1.75;
  color: var(--ag-ink-2); overflow-wrap: anywhere;
}
.ag-page .ag-p:last-child { margin-bottom: 0; }

.ag-ch { margin: 0 0 24px; scroll-margin-top: 16px; min-width: 0; }
.ag-ch:last-of-type { margin-bottom: 0; }
.ag-ch-h {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 8px; font-size: 15px; font-weight: 600; line-height: 1.3; color: var(--ag-ink);
}
.ag-ch-h::before {
  content: ""; display: block; flex: none;
  width: 4px; height: 14px; border-radius: 2px; background: var(--ag-ink);
}
.ag-ch-toggle {
  display: flex; align-items: center; gap: 8px;
  flex: 1 1 auto; min-width: 0; padding: 0;
  border: 0; background: transparent; color: inherit;
  font-family: inherit; font-size: inherit; font-weight: inherit; line-height: inherit;
  text-align: left; cursor: default;
}
.ag-ch-no { flex: none; font-size: 13px; font-weight: 600; line-height: 1.5; color: var(--ag-ink-3); }
.ag-ch-t { min-width: 0; overflow-wrap: anywhere; }
.ag-ch-body { display: block; }

.ag-checks {
  display: flex; flex-direction: column; gap: 8px;
  list-style: none; margin: 0 0 12px; padding: 0;
}
.ag-page .ag-check {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 0; font-size: 14px; line-height: 1.75; color: var(--ag-ink-2);
}
.ag-page .ag-check-box {
  display: grid; place-items: center; flex: none;
  width: 16px; height: 16px; margin-top: 3px;
  border-radius: var(--r-micro); background: var(--ag-selected); color: var(--ag-ink);
}
.ag-page .ag-check-box svg { width: 11px; height: 11px; stroke-width: 3; }

/* ---------- 风险提示（仅免责声明，不可折叠、在正文之前） ---------- */
.ag-risk {
  margin: 0 0 24px; padding: 12px;
  border: 0; border-radius: var(--r-ctl);
  background: var(--ag-wash); box-shadow: none;
}
.ag-risk-h {
  display: flex; align-items: center; gap: 8px;
  margin: 0; font-size: 14px; font-weight: 600; line-height: 1.3; color: var(--ag-ink);
}
.ag-risk-h::before {
  content: ""; display: block; flex: none;
  width: 4px; height: 14px; border-radius: 2px; background: var(--ag-ink);
}
.ag-risk-badge {
  flex: none; margin-left: auto; padding: 4px 8px;
  border-radius: var(--r-pill); background: var(--ag-solid); color: var(--ag-solid-ink);
  font-size: 12px; font-weight: 600; line-height: 1.5;
}
.ag-risk-p { margin: 8px 0 0; font-size: 13px; line-height: 1.65; color: var(--ag-ink-2); }

/* ---------- 目录卡 ---------- */
.ag-toc {
  grid-area: toc; position: sticky; top: 16px;
  min-width: 0; padding: 16px;
  border: 0; border-radius: var(--r-card);
  background: var(--ag-card); box-shadow: none;
}
.ag-toc-head { display: flex; align-items: center; gap: 8px; margin: 0 0 8px; }
.ag-toc-h {
  display: flex; align-items: center; gap: 8px;
  margin: 0; font-size: 15px; font-weight: 600; line-height: 1.3; color: var(--ag-ink);
}
.ag-toc-h::before {
  content: ""; display: block; flex: none;
  width: 4px; height: 14px; border-radius: 2px; background: var(--ag-ink);
}
.ag-toc-cnt { margin-left: auto; font-size: 12px; line-height: 1.5; color: var(--ag-ink-2); }
.ag-toc-btn {
  display: none; place-items: center; flex: none;
  width: 32px; height: 32px; padding: 0;
  border: 0; border-radius: var(--r-ctl);
  background: var(--ag-wash); color: var(--ag-ink-2); cursor: pointer;
}
.ag-toc-btn:hover { background: var(--ag-hover-wash); color: var(--ag-ink); }
.ag-toc-btn svg { width: 14px; height: 14px; transition: transform .18s; }
.ag-toc-btn[aria-expanded="true"] svg { transform: rotate(90deg); }
.ag-toc-list { display: flex; flex-direction: column; gap: 4px; max-height: 44vh; overflow-y: auto; }
.ag-toc-fold.is-collapsed .ag-toc-list { display: none; }
.ag-toc-link {
  display: flex; align-items: center; gap: 4px; width: 100%; min-height: 32px;
  padding: 8px 8px; border: 0; border-radius: var(--r-ctl);
  background: transparent; color: var(--ag-ink-2);
  font-family: inherit; font-size: 12px; line-height: 1.5; font-weight: 400;
  text-align: left; white-space: nowrap; cursor: pointer;
  transition: background-color .12s, color .12s;
}
.ag-toc-no { flex: none; color: var(--ag-ink-3); font-weight: 600; white-space: nowrap; }
.ag-toc-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ag-toc-link:hover { background: var(--ag-hover-card); color: var(--ag-ink); }
.ag-toc-link.is-on,
.ag-toc-link.is-on:hover {
  background: var(--ag-selected); color: var(--ag-ink); font-weight: 600;
}
.ag-toc-info {
  display: flex; flex-direction: column; gap: 4px;
  margin-top: 16px; font-size: 12px; line-height: 1.5; color: var(--ag-ink-2);
}
.ag-toc-info > div { display: flex; justify-content: space-between; gap: 8px; }
.ag-toc-info b { color: var(--ag-ink); font-weight: 600; }
.ag-print {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; height: 32px; margin-top: 16px; padding: 0 12px;
  border: 0; border-radius: var(--r-ctl); background: var(--ag-wash); color: var(--ag-ink-2);
  font-family: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.ag-print:hover { background: var(--ag-hover-wash); color: var(--ag-ink); }
.ag-print svg { width: 14px; height: 14px; }

/* ---------- 状态与可访问性 ---------- */
.ag-page .ag-note {
  position: static; display: flex !important; align-items: center; gap: 8px;
  margin: 24px auto 0; padding: 12px; overflow: visible;
  border: 0; border-radius: var(--r-ctl); background: var(--ag-wash); box-shadow: none;
  font-size: 12px; line-height: 1.5; color: var(--ag-ink-2);
}
.ag-page .ag-note::before,
.ag-page .ag-note::after { content: none; display: none; }
.ag-page .ag-note svg { width: 14px; height: 14px; flex: none; }
.ag-empty { padding: 24px 0; font-size: 14px; line-height: 1.75; color: var(--ag-ink-2); }
.ag-error {
  display: flex; flex-direction: column; gap: 16px;
  padding: 24px 0; font-size: 14px; line-height: 1.75; color: var(--ag-ink-2);
}
.ag-retry {
  align-self: flex-start; height: 32px; padding: 0 12px;
  border: 0; border-radius: var(--r-ctl);
  background: var(--ag-solid); color: var(--ag-solid-ink);
  font-family: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.ag-retry:hover { background: var(--ag-solid-hover); }
.ag-page :focus-visible { outline: 1.5px solid var(--ag-ink); outline-offset: 2px; }
.ag-page .icon { stroke-width: 1.7; }

/* 正文卡铺满内容区后，卡内文字列限宽居中（守住「阅读行不过长」） */
.ag-doc > * {
  max-width: 688px;
  margin-left: auto;
  margin-right: auto;
}

/* ---------- 单列：≤1023（目录上移并可折叠） ---------- */
@media (max-width: 1023px) {
  .ag-read {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "toc" "doc";
    gap: 16px;
    max-width: 720px;
    width: 100%;
    margin-inline: auto;
  }
  .ag-toc { position: static; }
  .ag-toc-head { min-height: 44px; }
  .ag-toc-btn { display: grid; }
}

/* ---------- 窄屏：章节手风琴（≤768） ---------- */
@media (max-width: 768px) {

  .ag-switch { margin-left: 0; }
  .ag-meta { margin-left: 0; }
  .ag-ch-h { min-height: 44px; margin-bottom: 0; }
  .ag-ch-toggle { cursor: pointer; }
  .ag-ch-body { display: none; }
  .ag-ch.is-open .ag-ch-body { display: block; }
}

/* ---------- 极窄屏：头部统计块撑满（≤560，对齐意见反馈页） ---------- */
@media (max-width: 560px) {
  .ag-head { align-items: flex-start; }
  .ag-head__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; }
}

/* ---------- 打印 ---------- */
@media print {
  /* theme-xiaoyi.css 先于 shell-next.css 加载，外壳解锁必须 !important */
  .shell { height: auto !important; overflow: visible !important; }
  .shell__body { display: block !important; }
  .shell__content { overflow: visible !important; border-radius: 0 !important; }
  #app.shell__main {
    height: auto !important; max-height: none !important;
    overflow: visible !important; padding: 0 !important;
  }
  .topbar, .sidenav, .sitefoot { display: none !important; }

  .ag-page {
    gap: 0;
    --ag-card: #ffffff; --ag-wash: #ffffff; --ag-elev: #ffffff;
    --ag-ink: #111111; --ag-ink-2: #333333; --ag-ink-3: #555555;
    --ag-selected: #eeeeee;
  }
  .ag-head { padding: 0; background: transparent; }
  .ag-head__stats { display: none !important; }
  .ag-switch, .ag-toc { display: none !important; }
  .ag-doc { padding: 0; border-radius: 0; background: transparent; }
  .ag-lead { padding: 0; background: transparent; }
  .ag-page .ag-note { padding: 0; background: transparent; }
  .ag-page .ag-note svg { display: none; }
  .ag-risk { display: block !important; padding: 0; background: transparent; }
  .ag-risk-badge { padding: 0; background: transparent; color: #111111; }
  .ag-title::before, .ag-ch-h::before, .ag-risk-h::before { display: none; }
  .ag-ch-body { display: block !important; }
  .ag-ch { break-inside: avoid; page-break-inside: avoid; margin-bottom: 16px; }
  .ag-ch-h { break-after: avoid; }
  .ag-check-box { background: #ffffff; color: #111111; border: 1px solid #999999; }
}

/* ==========================================================================
   X16. 固件资源页 —— 品牌导航 + 卡片列表
   视觉语言对齐首页（居中大标题 + 胶囊）与协议页（白底大圆角卡片 + 柔和阴影）
   ========================================================================== */
.dk-page { max-width: 1240px; margin: 0 auto; padding: 30px 28px 0; }

/* ---------- 居中大标题区（同协议页 .ag-hero） ---------- */
.dk-hero { text-align: center; margin-bottom: 30px; }
.dk-hero-ico {
  display: inline-grid; place-items: center; width: 60px; height: 60px;
  border-radius: var(--r-panel); color: #fff; margin-bottom: 16px;
  background: var(--grad);
  box-shadow: 0 10px 28px rgba(17, 17, 17, .2);
}
.dk-hero-ico svg { width: 28px; height: 28px; }
.dk-hero h1 {
  font-size: 34px; font-weight: 800; letter-spacing: -.5px;
  color: var(--ink); margin: 0 0 12px;
}
.dk-hero > p {
  font-size: 15.5px; color: var(--ink-2); line-height: 1.75;
  max-width: 780px; margin: 0 auto; text-wrap: balance;
}
.dk-hero-tags { display: flex; justify-content: center; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.dk-tag {
  display: inline-flex; align-items: center; font-size: 12.5px; font-weight: 600;
  color: var(--ink-2); background: var(--paper-2); border-radius: var(--r-btn);
  padding: 5px 14px;
}

/* ---------- 品牌导航卡 ---------- */
.dk-nav {
  background: #fff; border: 1px solid var(--line-soft); border-radius: var(--r-card);
  padding: 18px 22px 16px; margin-bottom: 16px; box-shadow: var(--shadow-card);
}
.dk-nav-row { display: flex; flex-wrap: wrap; gap: 8px; }
.dk-nav-hint { font-size: 12.5px; color: var(--ink-3); margin: 12px 0 0; }
.dk-empty { font-size: 13px; color: var(--ink-3); padding: 6px 0; }

.dk-chip {
  font-family: inherit; font-size: 14px; font-weight: 600; line-height: 1;
  color: var(--ink-2); background: var(--bg-gray); border: 0;
  padding: 11px 20px; border-radius: var(--r-btn); cursor: pointer; transition: .2s;
}
.dk-chip:hover { color: var(--accent); background: var(--accent-soft); }
.dk-chip.on {
  color: #fff; background: var(--grad); border-color: transparent;
  box-shadow: 0 4px 14px rgba(17, 17, 17, .28);
}

.dk-skeleton {
  display: inline-block; width: 76px; height: 38px; border-radius: var(--r-btn);
  background: var(--bg-gray); animation: dkPulse 1.4s ease-in-out infinite;
}
@keyframes dkPulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

/* ---------- 用途分类 tab ---------- */

/* ---------- 当前筛选说明条 ---------- */

/* ---------- 目录树卡（贴合卡片语言） ---------- */
.disk-tree {
  background: #fff; border: 1px solid var(--line-soft); border-radius: var(--r-card);
  box-shadow: var(--shadow-card); overflow: hidden;
}
.disk-tree-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px 12px; border-bottom: 1px solid var(--line-soft);
}
.disk-tree-title { font-size: 14px; font-weight: 700; color: var(--ink); }
.disk-tree-body { max-height: 62vh; overflow-y: auto; padding: 8px; }

/* ---------- 文件行式列表（卡片而非表格线） ---------- */
.dk-list { display: flex; flex-direction: column; gap: 10px; }
.dk-row {
  display: flex; align-items: center; gap: 14px;
  background: #fff; border: 1px solid var(--line-soft); border-radius: var(--r-card);
  padding: 13px 18px 13px 16px; box-shadow: var(--shadow-card);
  transition: transform .2s, box-shadow .2s, border-color .2s;
  text-decoration: none; min-width: 0;
}
.dk-row:hover {
  transform: translateY(-2px); box-shadow: var(--shadow-float);
  border-color: rgba(17, 17, 17, .3);
}
.dk-row-ico {
  display: grid; place-items: center; width: 38px; height: 38px;
  border-radius: var(--r-ctl); flex: none; color: #fff;
}
.dk-row-ico svg { width: 20px; height: 20px; }
.dk-row-ico.k-blue { background: var(--grad); }
.dk-row-ico.k-violet { background: linear-gradient(135deg, #7c5cf0, #a78bfa); }
.dk-row-ico.k-teal { background: linear-gradient(135deg, #0e9aa7, #34c3cf); }
.dk-row-ico.k-gold { background: linear-gradient(135deg, #d98407, #f0a92e); }
.dk-row-ico.k-gray { background: linear-gradient(135deg, #7c8b9e, #9aa8b8); }
.dk-row-dir .dk-row-ico { background: linear-gradient(135deg, #5b8def, #7aa8f5); }

.dk-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.dk-row-name {
  font-size: 14.5px; font-weight: 600; color: var(--ink); line-height: 1.45;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dk-row-sub {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 12px; color: var(--ink-3);
}
.dk-row-kind { font-weight: 600; padding: 2px 7px; border-radius: var(--r-micro); line-height: 1.4; }
.dk-row-kind.k-blue { background: rgba(17, 17, 17, .1); color: #111111; }
.dk-row-kind.k-violet { background: rgba(124, 92, 240, .12); color: #6d4bd8; }
.dk-row-kind.k-teal { background: rgba(14, 154, 167, .12); color: #0b7f89; }
.dk-row-kind.k-gold { background: rgba(217, 132, 7, .13); color: #8a5a00; }
.dk-row-kind.k-gray { background: rgba(124, 139, 158, .14); color: #5f6f80; }
.dk-row-cat { color: var(--ink-3); }
.dk-row-time { color: var(--ink-3); }

.dk-row-end { display: flex; align-items: center; gap: 12px; flex: none; }
.dk-row-meta { font-size: 13px; color: var(--ink-3); min-width: 68px; text-align: right; }
.dk-row-acts { display: flex; gap: 6px; }
.dk-icon-btn {
  display: grid; place-items: center; width: 32px; height: 32px;
  border: none; border-radius: var(--r-ctl); background: var(--bg-gray);
  color: var(--ink-2); cursor: pointer; transition: .18s; padding: 0;
}
.dk-icon-btn svg { width: 16px; height: 16px; }
.dk-icon-btn:hover { background: var(--accent); color: #fff; }
.dk-row-go {
  display: grid; place-items: center; width: 26px; height: 26px;
  border-radius: 50%; background: var(--bg-gray); color: var(--ink-3);
}
.dk-row-go svg { width: 14px; height: 14px; }
.dk-row-dir:hover .dk-row-go { background: var(--accent); color: #fff; }

/* ---------- 响应式 ---------- */
@media (max-width: 1024px) {
  .dk-hero h1 { font-size: 28px; }
  .dk-hero > p { font-size: 14px; }
  .dk-page { padding: 24px 20px 0; }
}
@media (max-width: 700px) {
  .dk-hero-ico { width: 52px; height: 52px; border-radius: 17px; }
  .dk-hero-ico svg { width: 24px; height: 24px; }
  .dk-hero h1 { font-size: 24px; }
  .dk-nav { padding: 15px 16px 13px; }
  .dk-chip { font-size: 13px; padding: 9px 15px; }
  /* 行式列表在窄屏改为「两行式」：名称独占一行，信息与操作在第二行 */
  .dk-row { flex-wrap: wrap; padding: 12px 14px; gap: 10px; }
  .dk-row-main { flex: 1 1 100%; order: 2; }
  .dk-row-ico { order: 1; }
  .dk-row-end { order: 3; flex: 1 1 100%; justify-content: space-between; }
  .dk-row-meta { text-align: left; }
}

/* ---------- 深色模式 ---------- */
[data-theme="dark"] .dk-nav,
[data-theme="dark"] .dk-row,
[data-theme="dark"] .disk-tree { background: var(--panel, #1a1d21); border-color: var(--rule-2); }
[data-theme="dark"] .dk-hero-ico { box-shadow: none; }

/* ---------- 布局容器覆盖（盖掉 archive.css 的表格式外框） ----------
   archive.css 的 .disk-layout 是「一整个带边框的大表格」，与新的卡片语言冲突：
   改为「左侧目录卡 + 右侧内容卡」两个独立卡片，中间留 20px 间距。 */
.disk-layout {
  display: grid; grid-template-columns: 264px minmax(0, 1fr);
  gap: 20px; align-items: start;
  border: none; background: none; min-height: 0;
}
.disk-tree {
  border: 1px solid var(--line-soft); border-right: 1px solid var(--line-soft);
  background: #fff; display: flex; flex-direction: column;
  position: sticky; top: 84px; max-height: calc(100vh - 110px);
}
.disk-main { min-width: 0; display: flex; flex-direction: column; }
/* 工具栏：面包屑 + 筛选 + 排序，卡片式内衬 */
.disk-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 12px;
}
.disk-crumb {
  display: flex; align-items: center; gap: 5px; flex-wrap: wrap;
  font-size: 13px; color: var(--ink-3); min-width: 0;
}
.disk-crumb a { color: var(--ink-2); text-decoration: none; display: inline-flex; align-items: center; gap: 4px; }
.disk-crumb a:hover { color: var(--accent); }
.disk-crumb a svg { width: 14px; height: 14px; }
.disk-crumb .sep { color: var(--ink-3); }
.disk-crumb .cur { color: var(--ink); font-weight: 600; }
.disk-crumb .tree-node-icon { width: 13px; height: 13px; }

@media (max-width: 1024px) {
  .disk-layout { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .disk-tree { position: static; max-height: none; }
  .disk-tree-body { max-height: 300px; }
}

/* ==========================================================================
   X17. 固件页阴影调整
   问题：--shadow-card 是双层阴影（0 2px 8px + 0 12px 32px），用在「分类 tab」
        这类小元素上会显得很脏 —— 3 个并排的 tab 各带一圈厚阴影，视觉噪音大。
   处理：小元素（tab / 排序下拉）改用单层极淡阴影；选中态只保留一层紧阴影。
   ========================================================================== */

/* 分类 tab：一层淡阴影（0 1px 3px），去掉大扩散层 */

/* 品牌胶囊：默认无阴影（靠灰底区分），悬停时才抬起 */
.dk-chip { box-shadow: none; }
.dk-chip:hover { box-shadow: 0 2px 8px rgba(17, 17, 17, .12); }
.dk-chip.on { box-shadow: 0 2px 8px rgba(17, 17, 17, .24); }

/* 大卡片（导航卡 / 目录卡 / 文件行）：双层阴影在留白充足处是加分的，保留 */
.dk-nav,
.disk-tree { box-shadow: var(--shadow-card); }
.dk-row { box-shadow: 0 1px 3px rgba(0, 0, 0, .04), 0 6px 16px rgba(0, 0, 0, .045); }
.dk-row:hover { box-shadow: 0 4px 12px rgba(17, 17, 17, .1), 0 12px 28px rgba(17, 17, 17, .08); }

/* 导航卡头部：「选择车系」标题 + 右侧统计（替代原先重复面包屑的提示行） */
.dk-nav-head {
  display: flex; align-items: baseline; gap: 10px;
  margin-bottom: 12px; flex-wrap: wrap;
}
.dk-nav-label { font-size: 14.5px; font-weight: 700; color: var(--ink); }

/* ==========================================================================
   X18. 固件页移除左侧目录树后的布局调整
   原：.disk-layout 为「目录树 264px + 内容区」双栏
   现：单栏全宽 —— 内容区直接占满，文件行长线可读性更好
   ========================================================================== */
.disk-layout { display: block; border: none; background: none; min-height: 0; }
.disk-main { min-width: 0; display: flex; flex-direction: column; }

/* 目录树已移除，相关样式一并失效；保留 disk-tree 规则供其他页复用（如需恢复） */

/* ==========================================================================
   X19. 固件页排序控件 —— 三段式切换器（名称 / 时间 / 大小）
   与首页搜索框的分段控件（.seg）同一套语言：灰底槽 + 白底选中块 + 方向箭头
   ========================================================================== */
.dk-sortgroup {
  display: inline-flex; align-items: center; gap: 2px;
  background: var(--bg-gray); border-radius: 999px; padding: 3px;
}
.dk-sortbtn {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: inherit; font-size: 13px; font-weight: 500; line-height: 1;
  color: var(--ink-2); background: none; border: 0; cursor: pointer;
  padding: 9px 16px; border-radius: 999px; white-space: nowrap;
  transition: color .18s, background-color .18s;
}
.dk-sortbtn:hover { color: var(--ink); }
.dk-sortbtn.on {
  color: var(--ink); background: #fff; font-weight: 600;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .1);
}
.dk-sortbtn .arw {
  font-size: 11px; line-height: 1; color: var(--accent);
  min-width: 8px; text-align: center;
}
.dk-sortbtn.on .arw { color: var(--accent); }

@media (max-width: 560px) {
  .dk-sortgroup { width: 100%; }
  .dk-sortbtn { flex: 1 1 0; justify-content: center; padding: 9px 8px; }
}

/* 深色模式 */
[data-theme="dark"] .dk-sortbtn.on { background: var(--rule-2, #2a2f36); color: var(--ink); }

/* ==========================================================================
   X20. 固件页 UI/UX 统一（对齐首页 / 协议页）
   改动要点：
   1) 面包屑 + 排序 + 列表原先悬空在灰底上 → 收进一张白底内容卡（同协议页 .ag-body）
   2) 面包屑加图标色与「当前目录」加重，定位感更强
   3) 分类 tab 与内容卡之间建立层级（同卡内分隔）
   4) 文件行加强：类型图标更大、名称更醒目、悬停整行高亮
   ========================================================================== */

/* ---------- 内容卡 ---------- */
.dk-panel {
  background: #fff; border: 1px solid var(--line-soft); border-radius: var(--r-card);
  padding: 18px 22px 20px; box-shadow: var(--shadow-card);
}
.disk-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; padding-bottom: 14px;
  border-bottom: 1px solid var(--line-soft);
}
.disk-crumb {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: 13.5px; color: var(--ink-3); min-width: 0;
}
.disk-crumb a {
  display: inline-flex; align-items: center; gap: 5px;
  color: var(--ink-2); text-decoration: none; transition: .18s;
}
.disk-crumb a:hover { color: var(--accent); }
.disk-crumb a svg { width: 15px; height: 15px; color: var(--ink-3); transition: .18s; }
.disk-crumb a:hover svg { color: var(--accent); }
/* 分隔符：细斜线，比「/」更轻 */
.disk-crumb .sep { color: var(--ink-3); opacity: .7; font-size: 12px; }
/* 当前目录：加重 + 变深，一眼看出「我在哪」 */
.disk-crumb .cur {
  display: inline-flex; align-items: center; gap: 5px;
  color: var(--ink); font-weight: 700; font-size: 14px;
}
.disk-crumb .cur svg { width: 15px; height: 15px; color: var(--accent); }

/* 说明条：卡内顶部提示，与工具栏之间留呼吸 */

/* ---------- 文件行 ---------- */
.dk-list { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }
.dk-row {
  display: flex; align-items: center; gap: 14px;
  background: #fff; border: 1px solid var(--line-soft); border-radius: var(--r-card);
  padding: 13px 16px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .03);
  transition: transform .18s, box-shadow .18s, border-color .18s, background-color .18s;
  text-decoration: none; min-width: 0;
}
.dk-row:hover {
  transform: translateX(2px);            /* 行式列表用右移而非上浮，暗示「进入」 */
  background: var(--paper-2);
  border-color: rgba(17, 17, 17, .28);
  box-shadow: 0 4px 12px rgba(17, 17, 17, .08);
}
.dk-row-ico {
  display: grid; place-items: center; width: 40px; height: 40px;
  border-radius: var(--r-card); flex: none; color: #fff;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .08);
}
.dk-row-ico svg { width: 21px; height: 21px; }
.dk-row-ico.k-blue { background: var(--grad); }
.dk-row-ico.k-violet { background: linear-gradient(135deg, #7c5cf0, #a78bfa); }
.dk-row-ico.k-teal { background: linear-gradient(135deg, #0e9aa7, #34c3cf); }
.dk-row-ico.k-gold { background: linear-gradient(135deg, #d98407, #f0a92e); }
.dk-row-ico.k-gray { background: linear-gradient(135deg, #7c8b9e, #9aa8b8); }
.dk-row-dir .dk-row-ico { background: linear-gradient(135deg, #5b8def, #7aa8f5); }

.dk-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.dk-row-name {
  font-size: 14.5px; font-weight: 600; color: var(--ink); line-height: 1.45;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dk-row:hover .dk-row-name { color: var(--accent); }
.dk-row-sub {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  font-size: 12px; color: var(--ink-3);
}
.dk-row-kind { font-weight: 600; padding: 2px 7px; border-radius: var(--r-micro); line-height: 1.4; }
.dk-row-kind.k-blue { background: rgba(17, 17, 17, .1); color: #111111; }
.dk-row-kind.k-violet { background: rgba(124, 92, 240, .12); color: #6d4bd8; }
.dk-row-kind.k-teal { background: rgba(14, 154, 167, .12); color: #0b7f89; }
.dk-row-kind.k-gold { background: rgba(217, 132, 7, .13); color: #8a5a00; }
.dk-row-kind.k-gray { background: rgba(124, 139, 158, .14); color: #5f6f80; }
.dk-row-time { color: var(--ink-3); }
.dk-row-time::before { content: '·'; margin-right: 7px; opacity: .5; }

.dk-row-end { display: flex; align-items: center; gap: 12px; flex: none; }
.dk-row-meta { font-size: 13px; color: var(--ink-3); min-width: 76px; text-align: right; font-variant-numeric: tabular-nums; }
.dk-row-acts { display: flex; gap: 6px; }
.dk-icon-btn {
  display: grid; place-items: center; width: 32px; height: 32px;
  border: 1px solid transparent; border-radius: var(--r-ctl); background: var(--bg-gray);
  color: var(--ink-2); cursor: pointer; transition: .18s; padding: 0;
}
.dk-icon-btn svg { width: 16px; height: 16px; }
.dk-icon-btn:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
.dk-row-go {
  display: grid; place-items: center; width: 26px; height: 26px;
  border-radius: 50%; background: var(--bg-gray); color: var(--ink-3);
  transition: .18s;
}
.dk-row-go svg { width: 14px; height: 14px; }
.dk-row-dir:hover .dk-row-go { background: var(--accent); color: #fff; }

/* 底部计数：卡内底部的轻提示，不抢视觉 */
.load-more { text-align: center; padding: 16px 0 2px; }
.load-more .stats-line { font-size: 12.5px; color: var(--ink-3); }

/* ---------- 响应式 ---------- */
@media (max-width: 700px) {
  .dk-panel { padding: 14px 15px 16px; border-radius: var(--r-panel); }
  .disk-toolbar { padding-bottom: 12px; }
  .dk-row { flex-wrap: wrap; padding: 12px 13px; gap: 10px; }
  .dk-row:hover { transform: none; }
  .dk-row-main { flex: 1 1 100%; order: 2; }
  .dk-row-ico { order: 1; width: 36px; height: 36px; }
  .dk-row-ico svg { width: 19px; height: 19px; }
  .dk-row-end { order: 3; flex: 1 1 100%; justify-content: space-between; }
  .dk-row-meta { text-align: left; min-width: 0; }
  .dk-row-time::before { content: ''; margin: 0; }
}

/* ---------- 深色模式 ---------- */
[data-theme="dark"] .dk-panel { background: var(--panel, #1a1d21); border-color: var(--rule-2); }
[data-theme="dark"] .dk-row { background: var(--panel, #1a1d21); border-color: var(--rule-2); }
[data-theme="dark"] .dk-row:hover { background: rgba(255, 255, 255, .03); }

/* ---------- X21. 细节收尾：卡内呼吸感与行分隔 ---------- */
/* 底部计数：卡内底部的轻提示，与卡底留出呼吸（原来贴边显得局促） */
.dk-panel .load-more { padding: 18px 0 4px; }
.dk-panel .load-more .stats-line {
  display: inline-block; font-size: 12px; color: var(--ink-3);
  background: var(--bg-gray); border-radius: 999px; padding: 4px 14px;
}
/* 文件行：极淡的底色交替，长列表时行更易分辨（斑马纹），悬停时恢复纯白 */
.dk-row:nth-child(even) { background: var(--paper-2); }
.dk-row:nth-child(even):hover { background: var(--paper-2); }
.dk-row:hover { background: var(--paper-2); }
/* 行间距略增，卡内密度更舒适 */
.dk-list { gap: 7px; }

/* ---------- 移动端整屏吸附：第二轮压缩（补足剩余缺口） ----------
   第一轮后：1=784(0) / 2=952(+168) / 3=784(0) / 4=818(+34) / 5=1243(+459)。
   第 2 块：4 张功能卡仍是 1 列 4 行，改为 2 列 × 2 行可省掉两行高度（约 168px）。
   第 4 块：攻略卡去掉 excerpt 段落与部分内边距即可补34px。
   第 5 块：6 张社区帖是最大缺口（+459px），改为 2 列 × 3 行，单卡压缩内边距与摘要行数。 */
@media (max-width: 900px) {
  /* 第 2 块：4 张卡改 2×2 固格 */
  html.page-snap .home section:nth-of-type(2) .features { grid-template-columns: 1fr 1fr; }
  html.page-snap .home section:nth-of-type(2) .feature h3 { font-size: 15px; }
  html.page-snap .home section:nth-of-type(2) .feature p {
    font-size: 12px; line-height: 1.55; margin-bottom: 8px;
    /* 摘要限一行，避免长文案把卡片撑高 */
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }

  /* 第 4 块：压缩到刚好装下。
     摘要限1 行会被硬裁（实测 4 张全裁，等于只留半句话），
     这里从内边距省出约 20px，把摘要放宽到 2 行，不破坏「五块等高」。 */
  html.page-snap .home section:nth-of-type(4) .guide { padding: 10px 14px; gap: 12px; }
  html.page-snap .home section:nth-of-type(4) .guide p {
    font-size: 12px; line-height: 1.55;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  html.page-snap .home section:nth-of-type(4) .guide .chips { margin-top: 6px; }

  /* 第 5 块：6 张帖改 2 列 × 3 行，摘要限 2 行 */
  html.page-snap .home section:nth-of-type(5) .posts { grid-template-columns: 1fr 1fr; gap: 12px; }
  html.page-snap .home section:nth-of-type(5) .post { padding: 14px; }
  html.page-snap .home section:nth-of-type(5) .post .text {
    font-size: 12.5px; line-height: 1.55; margin-bottom: 10px;
    -webkit-line-clamp: 2; display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden;
  }
  html.page-snap .home section:nth-of-type(5) .post .user { gap: 8px; margin-bottom: 10px; }
  html.page-snap .home section:nth-of-type(5) .post .name { font-size: 13px; }
  html.page-snap .home section:nth-of-type(5) .post .reacts { gap: 12px; }
}

/* ---------- 矮视口兜底：统一各区块高度 ---------- */
@media (max-height: 860px) and (min-width: 901px) {
  /* 矮视口（内容区 ≤ 720px）下内容装不下一屏，若各块高度由内容各自决定，
     滚动时就会出现「忽高忽低」。这里让所有区块统一取「最高那块」的高度：
     用 min-height 无法表达「取兄弟元素最大值」，故改用 flex 容器 + JS 测量，
     由 app.js 在首页渲染后给 html 加 --home-maxh 变量（见 snap.js 的 measureHomeBlocks）。
     CSS 侧只负责 fallback：给一个不小于任何内容的下限，保证视觉稳定。 */
  .hero,
  .home section { padding: 48px 0; }

  /* 第 2 块：4 张功能卡压内边距与图标 */
  .home section:nth-of-type(2) .feature { padding: 20px 20px; }
  .home section:nth-of-type(2) .feature .ico { width: 44px; height: 44px; border-radius: var(--r-card); margin-bottom: 12px; }
  .home section:nth-of-type(2) .feature .ico .icon { width: 22px; height: 22px; }
  .home section:nth-of-type(2) .feature h3 { font-size: 17px; margin-bottom: 7px; }
  .home section:nth-of-type(2) .feature p { font-size: 13px; line-height: 1.6; margin-bottom: 10px; }

  /* 第 3 块：缩略图与正文区 */
  .home section:nth-of-type(3) .thumb { height: 100px; }
  .home section:nth-of-type(3) .card .body { height: 92px; }
  .home section:nth-of-type(3) .card .meta { height: 32px; }

  /* 第 4 块：攻略卡压内边距，摘要限 1 行 */
  .home section:nth-of-type(4) .guide { padding: 16px 20px; gap: 16px; }
  .home section:nth-of-type(4) .guide .rank { font-size: 26px; }
  .home section:nth-of-type(4) .guide h4 { font-size: 15px; margin-bottom: 5px; }
  .home section:nth-of-type(4) .guide p {
    font-size: 12.5px; line-height: 1.55; margin-bottom: 8px;
    display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
  }

  /* 第 5 块：社区帖压内边距，摘要限 2 行 */
  .home section:nth-of-type(5) .post { padding: 16px 18px; }
  .home section:nth-of-type(5) .post .avatar { width: 36px; height: 36px; }
  .home section:nth-of-type(5) .post .user { gap: 10px; margin-bottom: 10px; }
  .home section:nth-of-type(5) .post .text { font-size: 13px; line-height: 1.6; margin-bottom: 10px; }
  .home section:nth-of-type(5) .post .reacts { font-size: 12px; }
}

/* ---------- 测量模式（临时类，由 snap.js 的 measureHomeBlocks 打上/摘掉） ----------
   目的：量各区块的「自然高度」时必须先解除 min-height 约束，
   否则量到的是已被 min-height 抬起的高度，会把最高的区块低估。
   这里把所有区块的 min-height 强制置 0、padding 保持不变，
   量出来的 offsetHeight 就是内容 + padding 的真实高度。 */
html.measuring .home > section,
html.measuring .home .hero {
  min-height: 0 !important;
}


/* ==========================================================================
   第 4 区块（迪粉分享·车机软件与工具）· 攻略卡适度加高
   --------------------------------------------------------------------------
   实测 1440×900（内容区 741px）：卡片 632×113px，上下各空 187px。
   卡片 632px 宽却只有 113px 高，横向拉长纵向很扁，视觉上「躺平」在区块中间。

   本次只做「适度加高」，不改排列（仍是 2 列 × 2 排），元素尺寸参照第 5 块
   社区帖的密度（内边距 16/18、头像 42、正文 14px），不出现过犹不及的放大：
     内边距 16/20 → 26/30、序号 26 → 34、标题 15 → 18、正文 12.5 → 14、标签 12 → 13
   预估卡高 113 → 约 150px，上下留白 187 → 约 150px。
   区块仍由 --home-maxh 统一五块等高，内容变高不会破坏等高与滚动吸附。

   放在文件末尾的原因：.guide / .rank / .chip 在本文件里有 4 处不同断点的定义
   （815/ 1092 / 1315 / 2053 行），就地改会被后面的 media query 覆盖。
   同时它也覆盖了矮视口档（max-height:860px，1440×900 正好命中）的压缩值。
   ========================================================================== */
@media (min-width: 901px) {
  .home section:nth-of-type(4) .guide-list {
    /* 摘要行数不同（2~3 行）会让四张卡天然不等高（实测 173/173/149/149）。
       grid-auto-rows: 1fr 强制两排行高一致，卡片再由 align-items:stretch 撑满，
       这样无论摘要几行，四卡底部都对齐。 */
    grid-auto-rows: minmax(0, 1fr);
  }
  .home section:nth-of-type(4) .guide {
    gap: 22px;
    padding: 26px 30px;
    /* 序号与文字块在卡内垂直居中，避免高卡里内容偏上 */
    align-items: center;
  }
  .home section:nth-of-type(4) .guide .rank { font-size: 34px; }
  .home section:nth-of-type(4) .guide h4 { font-size: 18px; margin-bottom: 8px; }
  .home section:nth-of-type(4) .guide p {
    font-size: 14px;
    line-height: 1.7;
    margin-bottom: 12px;
    /* 卡片加高后摘要需要 2~3 行才能完整显示，这里放开行数限制
       （矮视口档的 line-clamp:1 会被本规则覆盖）。
       仍保留 3 行上限，防止个别超长文案把卡片撑破、破坏四卡等高。 */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .home section:nth-of-type(4) .chip { font-size: 13px; padding: 4px 13px; }
  .home section:nth-of-type(4) .chips { gap: 10px; }
}

/* ==========================================================================
   第 3 区块（固件资源·大家都在下载）· 卡片加高 + 视觉留白对称
   --------------------------------------------------------------------------
   实测 1440×900（区块 741px）：
     卡片 305×194px（缩略图 100 + 正文 92），列表两排占408px，
     上下各空 108px（其中标题下边距仅 14px）。
     问题有二：① 卡片偏矮，上下留白偏多；
              ② 正文区 92px 只放得下 1.5 行标题，文件名第 2 行被裁（实测 clip:true）。

   本次只解决这两点，不动卡片配色与结构：
     · 缩略图 100 → 116px（+16）
     · 正文区 92 → 104px（+12），够放 2 行标题（2×21=42）+ meta 32 + 内边距
     · 合计卡高 194 → 222px，多出的 28px 吃掉上下留白（各 108 → 94px）
     注：缩略图先试148px（卡高 252px），但区块被撑到 773px 破坏五块等高，
     故回收 32px 定为 116px。
   区块仍由 --home-maxh 统一五块等高，内容变高不会破坏等高与滚动吸附。
   ========================================================================== */
.home section:nth-of-type(3) .thumb { height: 116px; }
.home section:nth-of-type(3) .thumb svg { width: 52px; height: 52px; }
/* 正文区用固定 height 而非 min-height：文件名 1 行与 2 行的卡必须等高，
   否则同一排底部不对齐。.meta 已用 align-self:end 吸底，多余空间不会挤压标题。 */
.home section:nth-of-type(3) .card .body { height: 104px; min-height: 0; }

/* ==========================================================================
   第 2 区块（你要的，这儿都有）· 功能卡加高 + 上下留白对称
   --------------------------------------------------------------------------
   实测 1440×900（区块 741px）：卡片 304×198px，上下各空 210px
   —— 这是五个区块里留白最多的一块（对比第 3 块 80、第 4 块 127、第 5 块 138）。

   卡片内部构成（实测）：图标 44 + 标题 20 + 描述 21 + 链接 24 = 109px，
   而卡高 198px —— 中间有 89px 是空着的，所以卡内本身就显得松散。
   本次让内容在卡内自然撑开，各元素同步放大 1.25~1.35 倍：
     内边距 20 → 26px（上下共 +12）
     图标块 44 → 56px、图标 22 → 28px
     标题 17 → 20px、描述 13 → 14px（限 1 行）、行高 1.6 → 1.7
     链接 13 → 15px
   实测卡高 198 → 272px，上下留白 210 → 173px且对称。
   区块仍由 --home-maxh 统一五块等高，内容变高不会破坏等高与滚动吸附。
   ========================================================================== */
@media (min-width: 901px) {
  .home section:nth-of-type(2) .feature {
    padding: 26px 30px;
  }
  .home section:nth-of-type(2) .feature .ico {
    width: 56px; height: 56px; border-radius: var(--r-panel); margin-bottom: 16px;
  }
  .home section:nth-of-type(2) .feature .ico .icon { width: 28px; height: 28px; }
  .home section:nth-of-type(2) .feature h3 { font-size: 20px; margin: 0 0 10px; }
  /* 描述保持 1 行：字号 15px 在 244px 内容宽下会折成 2 行（「直接下。」独占一行），
     导致四卡底部链接不在同一水平线。14px / 1.7 恰好单行且与第 5 块社区帖正文同号。 */
  .home section:nth-of-type(2) .feature p {
    font-size: 14px; line-height: 1.7; margin: 0 0 16px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .home section:nth-of-type(2) .feature .link { font-size: 15px; gap: 6px; }
  .home section:nth-of-type(2) .feature .link .icon { width: 17px; height: 17px; }
}

/* ==========================================================================
   首页 · 区块切换动效与页码胶囊
   --------------------------------------------------------------------------
   1) .page-dots：底部居中的页码提示胶囊
      5 个圆点对应 5 个区块，当前屏用横向长条 + 品牌蓝高亮；
      默认透明（.ready 前不显示，避免首帧闪一下），出现时淡入。
      只用圆点、不显示文字：文字展开会让胶囊宽度跳变，
      且5 个区块名并排会挤占底部空间、干扰阅读。区块名以title 属性
      挂在按钮上，鼠标悬停由浏览器原生 tooltip 提示。
   注：区块入场动画（.enter）已停用并从 CSS 移除 ——
   淡入类动效本质是「先消失再出现」，用户反馈「像闪了一下」，
   缓动对齐本身已足够表达切屏动作，不需要再叠内容浮现。

   2) prefers-reduced-motion：用户要求减少动效时胶囊展开动画退化为瞬时。
   ========================================================================== */

.page-dots {
  position: fixed; left: 50%; bottom: 22px; z-index: 88;
  transform: translateX(-50%) translateY(8px);
  display: flex; align-items: center; gap: 4px;
  padding: 9px 12px; border-radius: 999px;
  /* 毛玻璃质感升级（与顶栏 #masthead / 移动端 TAB 同款）：
     原为 rgba(255,255,255,.82) + blur(14px) saturate(1.2) ——
     白度过高（.82）显得发闷，模糊太弱、饱和度偏低，透不出背景层次。
     现为 .45 白 + blur(24px) saturate(220%) brightness(1.04)，与上下两条悬浮栏统一。 */
  background: rgba(255, 255, 255, .45);
  border: 1px solid rgba(0, 0, 0, .05);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .95),
    inset 0 -1px 0 rgba(255, 255, 255, .45),
    0 6px 22px rgba(16, 24, 40, .1);
  backdrop-filter: saturate(220%) blur(24px) brightness(1.04);
  -webkit-backdrop-filter: saturate(220%) blur(24px) brightness(1.04);
  opacity: 0; pointer-events: none;
  transition: opacity .3s ease, transform .3s ease;
}
/* 首次 stop 判定完成后再显示，避免与页面其它淡入抢镜 */
.page-dots.ready { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
/* 滚入页脚时隐藏：胶囊是 fixed 定位，不隐藏会悬在黑色星空页脚上方，很突兀。
   用 opacity + visibility 过渡（不用 display:none），渐隐更自然；
   visibility 同步切换确保隐藏后不拦截点击。 */
.page-dots.hidden {
  opacity: 0; pointer-events: none; visibility: hidden;
  transform: translateX(-50%) translateY(8px);
}

.page-dot {
  display: inline-flex; align-items: center; gap: 0;
  padding: 6px 3px; border: 0; background: none; cursor: pointer;
  font-family: var(--font-sans);
}
.page-dot-mark {
  display: block; width: 8px; height: 8px; border-radius: 999px;
  background: var(--ink-4); opacity: .5;
  transition: width .32s cubic-bezier(.22, 1, .36, 1), background .32s ease, opacity .32s ease;
}
.page-dot:hover .page-dot-mark { opacity: .85; }
.page-dot:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: var(--r-ctl); }

/* 当前屏：横向长条 + 品牌蓝 */
.page-dot.on .page-dot-mark { width: 24px; background: var(--brand); opacity: 1; }

/* 深色模式：胶囊用深色底，弱化描边 */
/* 深色同步升级（与顶栏/ 移动端 TAB 的深色参数一致：.42 白 + saturate 200% + blur 24px） */
[data-theme="dark"] .page-dots {
  background: rgba(13, 16, 20, .42);
  border-color: rgba(255, 255, 255, .08);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .16),
    inset 0 -1px 0 rgba(255, 255, 255, .07),
    0 6px 22px rgba(0, 0, 0, .5);
  backdrop-filter: saturate(200%) blur(24px) brightness(1.06);
  -webkit-backdrop-filter: saturate(200%) blur(24px) brightness(1.06);
}
[data-theme="dark"] .page-dot-mark { background: rgba(237, 240, 244, .4); }

/* 移动端：缩小尺寸、贴底更近，避免遮住内容 */
@media (max-width: 900px) {
  .page-dots { bottom: 14px; padding: 7px 10px; gap: 3px; }
  .page-dot-mark { width: 7px; height: 7px; }
  .page-dot.on .page-dot-mark { width: 20px; }
}

/* 尊重「减少动效」偏好：入场与展开动画全部关闭，对齐也由 snap.js 退化为瞬时 */
@media (prefers-reduced-motion: reduce) {
  .page-dots { transition: none; }
  .page-dot-mark { transition: none; }
}

/* ==========================================================================
   X18. 顶栏方案 D 的移动端适配（放在文件最末，权重最高）
   --------------------------------------------------------------------------
   方案 B 的顶栏是白底，下拉面板在移动端要脱离「居中轨道」的形态：
   桌面端的浅灰胶囊轨道在窄屏必须打平成普通白卡，否则会变成一条灰杠。
   ========================================================================== */
@media (max-width: 1024px) {
  /* 窄屏放不下居中轨道，导航靠左排列，优先保证可点 */
  .masthead-brand { flex: 0 1 auto; }
  .masthead-actions { flex: 0 0 auto; }
  .nav-panel > a { padding: 8px 12px; font-size: 14px; }
}
@media (max-width: 768px) {
  /* 下拉面板：白卡 + 圆角 + 投影，与白底顶栏区分层次 */
  .nav-panel {
    background: #fff;
    border: 1px solid var(--rule-2);
    border-radius: var(--r-card);
    box-shadow: 0 12px 32px rgba(16, 24, 40, .14);
    padding: 6px;
    overflow: hidden;
  }
  .nav-panel > a {
    color: var(--ink-2);
    border-radius: var(--r-ctl);
    padding: 12px 14px;
    min-height: 44px;
    background: transparent;
    box-shadow: none;
  }
  .nav-panel > a:hover { color: var(--ink); background: var(--paper-2); }
  .nav-panel > a.active {
    color: var(--brand); background: var(--brand-wash); font-weight: 600;
    box-shadow: none;
  }
  /* 移动端顶栏略矮 */
  #masthead { box-shadow: 0 1px 10px rgba(16, 24, 40, .05); }
  /* Logo 在窄屏隐藏文字，只留图标（archive.css 原有行为），此处补回配色 */
  .brand-mark { background: var(--brand-wash); box-shadow: inset 0 0 0 1px rgba(17, 17, 17, .14); }
}

/* 深色模式：下拉面板回到深色面 */
[data-theme="dark"] .nav-panel {
  background: #16191f;
  border-color: rgba(255, 255, 255, .12);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .5);
}
[data-theme="dark"] .nav-panel > a { color: rgba(237, 240, 244, .78); }
[data-theme="dark"] .nav-panel > a:hover { color: #edf0f4; background: rgba(255, 255, 255, .06); }
[data-theme="dark"] .nav-panel > a.active { color: #cfcfcf; background: rgba(245, 245, 245, .14); }

/* ---------- 方案 B 深色模式补正 ----------
   X3 段里 .nav-panel > a.active 的白底规则权重(0,2,1)高于此处的深色规则，
   因此这里用更高权重强制覆盖，否则深色轨道上会出现刺眼白块。 */
[data-theme="dark"] .nav-panel > a.active,
[data-theme="dark"] .nav-panel > a.active:hover {
  color: #fff;
  background: #2f6dff;
  box-shadow: 0 2px 10px rgba(47, 109, 255, .45);
}

/* 2026-10-04 背景重写：旧 .glow 光晕体系已删除，减少动效兜底移至文件末尾 .bgflow 段。 */

/* ==========================================================================
   X20. 移动端隐藏顶栏导航（底部 TAB 已覆盖全部入口）
   --------------------------------------------------------------------------
   ≤768px 时：
     · 隐藏汉堡按钮 .nav-toggle 与桌面导航 .nav-panel
       —— 原下拉面板是从顶栏右侧向下展开的浮层，会盖住首屏内容（用户反馈"遮挡屏幕"）。
     · 顶栏只保留「Logo + 登录/用户区」，也就是 APP 常见的 compact 顶栏。
   6 个入口全部由底部 #tabbar 承担：首页 / 固件资源 / 升级查询 / 迪粉社区 / 迪粉分享 / 个人中心。
   原顶栏的「后台管理」已并入个人中心页行卡（views/profile.js 的 TABS，按角色显示）。
   桌面端（>768px）行为完全不变。
   ========================================================================== */
@media (max-width: 768px) {
  .nav-toggle { display: none !important; }
  .masthead-nav { display: none !important; }
  /* Logo 与用户区在 compact 顶栏里各占一半，视觉平衡 */
  .masthead-brand { flex: 1 1 0; }
  .masthead-actions { flex: 0 0 auto; }

  /* 已登录用户卡：只保留圆形头像（APP 常见形态）。
     ⚠️ padding / border-radius / width 都必须写 !important：
     `archive.css:259` 有 `.nav-user { padding-right: 14px !important }`，
     它会用 !important 顶掉这里的 `padding: 0`，
     导致白色圆卡被撑成「右边缺一块的怪圆圈」+ 头像左偏 7px。
     同理 X3 段的 width:126px 也靠本段 42px 覆盖（那两条权重相同、后加载能生效），
     但 padding 这条必须自己带 !important 才压得住。 */
  .masthead-actions .nav-user {
    width: 42px !important;   /* 卡片 42px：与 40px 头像配对，白圈 1px */
    height: 42px;
    padding: 0 !important;
    gap: 0 !important;
    border-radius: 50% !important;
    justify-content: center;
    align-items: center;
    overflow: hidden;
    background: #fff;
  }
  .masthead-actions .nav-user-text { display: none !important; }
  /* 移动端头像 30 → 40px：卡片 42px 内几乎撑满，白圈 1px（用户指定值）。 */
  .masthead-actions .nav-user-avatar { width: 40px; height: 40px; }
}

/* ==========================================================================
   X21. 移动端底部 TAB 让位（覆盖 X5 段的 #app padding）
   --------------------------------------------------------------------------
   ** 为什么必须在这里覆盖 **
   mobile-app.css:116 已经写了 #app { padding-bottom: 88px } 给 TAB 让位，
   但 CSS 加载顺序是：
       app.css → archive.css → admin-next.css → mobile-app.css → theme-xiaoyi.css
   theme-xiaoyi.css 在最后，它的 X5 段写的是
       #app { padding: 96px 28px 40px; }
   这条简写把 padding-bottom 重新写成 40px，**同权重、后加载 → 覆盖掉 88px**。
   结果：TAB 高 56px，内容只留了 40px，底部被压住约 16~24px（用户反馈"遮挡内容"）。

   ** 修法 **
   在本文件末尾（权重与顺序都最晚）重新声明移动端底部留白。
   留白 = 悬浮白卡高度（约 58px）+ 底部间距 10px + 安全区 + 呼吸余量 24px。
   footer 也要单独留白，否则滚到底时页脚内容仍会被白卡压住。
   ========================================================================== */
/* ⚠️ 断点 900px（与 app.js 的 BREAKPOINT、TAB 断点一致）：
   本段含.page-dots 抬位与 .modal 避让，都是「为底部 TAB 让位」，
   判定标准是有没有 TAB，因此断点必须跟TAB 一起走 900px。
   原写 768px 会导致 769~900px 区间这些让位全部失效。 */
@media (max-width: 900px) {
  body:not(.admin-mode) #app {
    padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px));
  }
  body:not(.admin-mode) footer {
    padding-bottom: calc(100px + env(safe-area-inset-bottom, 0px));
  }
  /* 桌面端的页码胶囊（.page-dots）在移动端会压在 TAB 上，
     首页整屏吸附时它落在屏幕底部 —— 把它抬到 TAB 之上。 */
  .page-dots { bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
  /* 弹窗贴底呼出时（.modal 用了 bottom:0），同样要避开 TAB */
  body:not(.admin-mode) .modal {
    bottom: calc(68px + env(safe-area-inset-bottom, 0px));
  }
  /* 后台页（admin-mode）没有 TAB，撤掉上面的让位 */
  body.admin-mode #app,
  body.admin-mode footer { padding-bottom: 32px; }
}

/* ==========================================================================
   X22. 移动端隐藏页脚（协议入口已迁入个人中心）
   --------------------------------------------------------------------------
   移动端页脚是「品牌蓝渐变条 + Logo + 协议链接 + 版权」，但：
     1. 渐变条 + 底部白色 TAB 白卡会打架，两块重色浮层叠在屏幕底部；
     2. 渐变条本身就占约 76px，加上 TAB 会让底部视觉噪音过大；
     3. 协议链接（用户协议 / 隐私政策 / 免责声明）已迁入个人中心页
        （views/profile.js 的 .pf-legal，样式在 pf.css），入口不会丢失。
   版权信息与协议因此在移动端改为「个人中心 → 底部协议行」承载。
   桌面端页脚完全不受影响。

   ⚠️ 断点必须是 **900px**，不能是 768px ——
   判定标准是「有没有底部 TAB」，而 TAB 的断点是 900px（与 app.js 的
   BREAKPOINT 一致）。若这里写 768px，会出现 769~900px 区间
   **TAB 显示、页脚也显示**（实测 footerH=76），两块重色浮层叠在底部。
   判定口诀：凡是「跟随底部 TAB」的规则，断点一律 900px。
   ========================================================================== */
@media (max-width: 900px) {
  body:not(.admin-mode) footer { display: none !important; }
  /* 页脚没了，主区不需要再为它预留 100px，让内容更饱满 */
  body:not(.admin-mode) #app { padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px)); }
}

/* ==========================================================================
   X23. 移动端首页：放弃整屏吸附 + 区块高度自适应（方案 A）
   --------------------------------------------------------------------------
   ** 问题根源（实测）**
   375 / 414 / 768px 三档下，每个区块都被 `min-height: max(calc(100dvh - 60px), --home-maxh)`
   强制撑到 **835px**，而视口只有 700px → 底部恒定被压 **135px**。
   溢出的热词、统计数字、最后一行卡片全部钻到底部 TAB 下面。
   加多少 padding-bottom 都无效 —— 溢出来自「高度被撑爆」，不是「留白不够」。

   ** 方案：小屏彻底放弃整屏吸附，回归自然文档流 **
     · snap.js 的 enableSnap() 在 ≤900px 时直接短路，不挂监听、不建圆点胶囊
       （另在 onResize 里处理「桌面缩小到手机宽度」的跨断点情况）；
     · 移除 min-height，让区块高度由内容决定；
     · padding 从 64px 收到 28px，消除顶部留白过大；
     · scroll-padding-top 还原（吸附没了就不需要导航让位）。
   桌面端（>900px）**完全不受影响**，整屏吸附 + 圆点导航照旧。
   ========================================================================== */
@media (max-width: 900px) {
  /* 吸附相关全部失效（html 没有 .page-snap 类时这些规则本来就不生效，
     这里显式写出来是为了覆盖 X18 段里那些不依赖类名的基础规则） */
  html.page-snap { scroll-snap-type: none; overscroll-behavior-y: auto; }
  html.page-snap .home > section { scroll-snap-align: none; scroll-snap-stop: normal; }

  /* 核心：区块高度不再被撑成一屏，由内容自然决定
     （移动端区块内容普遍高于一屏，强制满屏反而会出现大片空白）。
     ⚠️ 但**背景色仍按区块自身高度铺满**（见文件末尾 X204 段的
     `.home > section` 背景规则）—— 用户反馈「区域背景应自适应撑满屏幕」，
     指的就是背景要铺满内容所在区域，而不是露出下一区块的颜色。 */
  html.page-snap .home section,
  html.page-snap .home .hero,
  .home section,
  .hero {
    min-height: 0 !important;
  }
  /* 内容垂直居中交给 padding，不再用 min-height 制造居中效果 */
  .hero { align-items: center; padding: 28px 0; }
  .home section { padding: 28px 0; }

  /* 区块标题不再有大 margin，顶部留白收敛 */
  .home .sec-head { margin-bottom: 16px; }
  .home .sec-head h2 { font-size: 20px; }
  .home .sec-head p { font-size: 13px; }
}

/* ---------- X23-b. 底部留白重算（配合 X23 关闭吸附） ----------
   关闭吸附后区块高度 = 内容高度，原先「每屏撑满」带来的天然缓冲消失了。
   实测 414×700：滚到首屏区块底部时，内容 wrap 底部 667 vs TAB 上沿 634 → 重叠 33px。
   根因是区块 padding-bottom 只有 28px，不足以把内容顶到 TAB 上沿之上。
   做法：区块 padding-bottom 给到 72px（> TAB 视觉高度 56 + 安全区余量），
   这样「滚到区块底部时内容正好停在 TAB 上方」。同时压缩统计数字/热词的上间距，
   抵消多出来的 padding，避免首屏变长。 */
@media (max-width: 900px) {
  /* 所有区块统一给足底部 padding —— 包括最后一个。
     曾试过给最后一个区块减到 28px，实测社区动态区仍有 38px 重叠（该区卡片最多）。 */
  .home .hero,
  .home section { padding: 28px 0 72px; }
  .home .stats { margin-top: 22px; }
  .home .hot-words { margin-top: 16px; }
}

/* ==========================================================================
   X24. 移动端固件卡片：一行一个 + 标签不再压图标（方案 D）
   --------------------------------------------------------------------------
   ** 问题 1：标签遮挡图标（实测）**
   414px 下缩略图仅 88px 高，而中间图标 52px（y 1855~1907）、
   「压缩包」与「方程豹·钛3」两个标签都绝对定位在 top:12px（y 1852~1876），
   水平方向图标 x 77~129 也被两个标签（26~86 / 110~181）夹住 → 必然重叠。
   根因是缩略图太矮，放不下「标签行 + 图标」两层。

   ** 方案 **
     · 缩略图加高到 132px，给图标和标签各自留出行；
     · 固格改一行一个（`grid-template-columns: 1fr`），卡片变宽 →
       图标与左右两个标签在水平方向也拉开了距离；
     · 图标上移让位：top 由 46% 调到 58%，两个标签保持 top 12px 同一行。

   多余卡片沿用既有的圆点自动轮播（home.js 的 hot-dl 分页逻辑），不额外改动。
   ========================================================================== */
@media (max-width: 900px) {
  /* ⚠️ 2026-10-04 用户要求：移动端**两行×2 个**（原为一行一个）。
     每页 4 张 = 2 行 × 2 列，配合 home.js 的 HOT_DL_PER_PAGE_MOBILE=4。 */
  .home section:nth-of-type(3) .grid,
  .hot-dl .grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
  }
  /* 缩略图加高，容纳「标签行 + 图标」 */
  .home section:nth-of-type(3) .thumb { height: 132px; }
  /* 图标下移到中下部，把顶部整行让给两个标签 */
  .home section:nth-of-type(3) .thumb svg {
    top: 60%;
    width: 50px;
    height: 50px;
  }
  /* 标签行：加大左右间距，让开中间的图标 */
  .home section:nth-of-type(3) .card .tag { top: 10px; left: 10px; }
  .home section:nth-of-type(3) .card .car-model {
    top: 10px; left: 10px;
    max-width: calc(100% - 20px);
  }
  /* 卡片高度放开（桌面端用 height 固定做四卡等高，小屏一行一个不需要） */
  .home section:nth-of-type(3) .card { height: auto; }
  .home section:nth-of-type(3) .card .body {
    height: auto;
    padding: 12px 14px 12px;
  }
  /* 文件名给两行，长固件名仍可完整阅读 */
  .home section:nth-of-type(3) .card h4 {
    font-size: 14.5px;
    line-height: 1.5;
    -webkit-line-clamp: 2;
  }
  .home section:nth-of-type(3) .card .meta { height: auto; }
  /* 轮播圆点上移一点，贴近卡片组 */
  .home section:nth-of-type(3) .hot-dl-dots { margin-top: 12px; }
}

/* ---------- X24-b. 逐区块补足底部留白 ----------
   X23-b 给所有区块统一 72px，但三个区块的卡片高度不同，实测仍有残留：
     · 第 2 区块（迪粉分享固格）末行卡片被压 10px
     · 第 4 区块（攻略列表）第 4 条被压 14px
     · 第 5 区块（社区动态）最后一条被压 14px
   固格/列表类区块的末行元素比标题类重，需要更大的底部 padding 才能停到 TAB 上沿。

   ⚠️ 这些大padding 只适用于「滚动过程中会经过」的区块。
   最后一个区块（社区动态）滚到底就停住，padding 只决定它与 TAB 的视觉间距 ——
   实测 96px 时末条内容距 TAB 高达126px，明显比固件页（47px）松垮很多。
   所以末位区块单独收到 24px padding + 靠 #app 的 96px 留白，
   最终间距 ≈ 24 + 96 − 56（TAB 视觉高度）≈ 64px，与固件页同一量级。 */
@media (max-width: 900px) {
  /* 三大功能（2×2 固格）*/
  .home section:nth-of-type(2) { padding-bottom: 88px; }
  /* 迪粉分享（2 列卡片固格）*/
  .home section:nth-of-type(4) { padding-bottom: 96px; }
  /* 社区动态（2 列帖子固格）—— 末位区块。
     对齐基准：登录后实测固件页 #/disk，末行内容距 TAB 上沿 65px。
     用户要求在此基础上**缩小一半** → 目标 ~32px。
     padding 35px → 2px（65 − 32 = 33，区块 padding 直接减 33px）。 */
  .home section:nth-of-type(5) { padding-bottom: 2px; }
}

/* ==========================================================================
   X25. 移动端第 2 区块（三大功能 + 迪粉分享）四卡改 2×2
   --------------------------------------------------------------------------
   原来 .features 是单列（实测 374px 宽 / 253px 高），四张卡纵向排开、
   页面被拉得很长。改为 2 列 × 2 行。

   关键：卡宽从 374px 压到约 176px，卡内元素必须同步收紧，
   否则 56px 图标 + 19px 标题 + 14px 描述会挤爆换行、卡片高度失控：
     · 图标 56 → 40px，圆角 16 → 12px
     · 标题 19 → 15.5px
     · 描述 14 → 12.5px，限 2 行（-webkit-line-clamp）
     · 底部链接 13 → 12px
     · padding 32/28 → 16/14
   四卡等高由 grid 默认 stretch 保证，无需额外处理。
   ========================================================================== */
@media (max-width: 900px) {
  .home section:nth-of-type(2) .features {
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
  }
  .home section:nth-of-type(2) .feature { padding: 16px 14px; border-radius: var(--r-panel); }
  .home section:nth-of-type(2) .feature .ico {
    width: 40px; height: 40px; border-radius: var(--r-card); margin-bottom: 12px;
  }
  .home section:nth-of-type(2) .feature .ico .icon { width: 20px; height: 20px; }
  .home section:nth-of-type(2) .feature h3 { font-size: 15.5px; margin-bottom: 6px; }
  .home section:nth-of-type(2) .feature p {
    font-size: 12.5px; line-height: 1.6; margin-bottom: 12px;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  .home section:nth-of-type(2) .feature .link { font-size: 12px; gap: 3px; }
  .home section:nth-of-type(2) .feature .link .icon { width: 13px; height: 13px; }
}

/* ==========================================================================
   X26. 移动端第 5 区块（社区动态）分页轮播
   --------------------------------------------------------------------------
   桌面端（>900px）保持 3 列固格一次展示 6 条，不显示圆点。
   移动端每页 2 条（1 列 × 2 行），圆点可点击，6 秒自动翻页。
   圆点复用 .hot-dl-dots / .hot-dl-dot 的既有样式，这里只加布局与间距。
   ========================================================================== */
@media (max-width: 900px) {
  .home section:nth-of-type(5) .posts { grid-template-columns: 1fr; gap: 12px; }
  /* 社区圆点：与固件区块视觉一致的上边距 */
  .home section:nth-of-type(5) .feed-dots { margin-top: 14px; }
  /* 桌面端隐藏圆点容器（有内容时为空，不占位） */
  .feed-dots:empty { display: none; }
}

/* ==========================================================================
   X27. 移动端 1~4 区块上下留白统一（末位区块不动）
   --------------------------------------------------------------------------
   之前各区块 padding 上下不对称（实测28/72、60/88、48/48、52/96px），
   区块之间会出现「上宽下窄 / 上窄下宽」的错位感。
   现在第 1~4 区块统一 `padding: 36px 0`（上下完全相同），
   第 5 区块（社区动态）保持 X24-b 定的 2px 不变 —— 它的 padding 只决定
   滚到底时与 TAB 的视觉间距（32px），不能动。
   留白值 36px 兼顾「区块之间有呼吸」与「小屏别把内容推太长」。
   ========================================================================== */
@media (max-width: 900px) {
  /* 注意选择器权重：`.home section` 比 `.home section:nth-of-type(N)` 低一级
     （多一个伪类），直接写会被第 2/3/4/5 区块各自的规则覆盖掉。
     所以这里必须带上 :nth-of-type，逐个区块显式声明。 */
  .home .hero,
  .home section:nth-of-type(1),
  .home section:nth-of-type(2),
  .home section:nth-of-type(3),
  .home section:nth-of-type(4) {
    padding-top: 36px;
    padding-bottom: 36px;
  }
  /* 末位区块：上边距跟随统一，下边距保留 2px（滚到底的视觉留白 32px） */
  .home section:nth-of-type(5) {
    padding-top: 36px;
    padding-bottom: 2px;
  }
}

/* ==========================================================================
   X28. 移动端第 4 区块（迪粉分享）分页轮播
   --------------------------------------------------------------------------
   桌面端（>900px）保持 2 列固格一次展示 4 条，不显示圆点。
   移动端每页 2 条（1 列 × 2 行），圆点可点击，5 秒自动翻页（与其他区块统一）。
   ========================================================================== */
@media (max-width: 900px) {
  .home section:nth-of-type(4) .guide-list { grid-template-columns: 1fr; gap: 12px; }
  .home section:nth-of-type(4) .feed-dots { margin-top: 14px; }
  /* 桌面端圆点容器为空时不占位 */
  .home section:nth-of-type(4) .feed-dots:empty { display: none; }
}

/* ==========================================================================
   X29. 统一「移动端形态」的断点：768px → 900px（补齐 769~900px 区间）
   --------------------------------------------------------------------------
   ** 为什么要补 **
   app.js 的 `const BREAKPOINT = 900` 决定 JS 侧行为（分页每页数量、吸附启停），
   而 CSS 侧的顶栏 / TAB 形态规则写的是 `@media (max-width: 768px)`。
   两边断点不一致 → 769~900px 成了「四不像」区间，实测（登录态）：

     宽度   头像卡      文字     TAB      桌面导航
     745    42px 圆形   none     block    flex   ← 正常移动端
     800    126px 胶囊  none     none     flex   ← 异常：空胶囊 + 无 TAB
     900    126px 胶囊  none     none     flex   ← 异常
     1000   126px 胶囊  block    none     flex   ← 正常桌面端

   即 769~900px 时：桌面导航还在，但用户卡是「隐藏了文字的宽胶囊」（空荡荡一长条），
   同时底部 TAB 又不显示 —— 用户截图 2 正是这个状态。

   ** 修法 **
   断点统一到 900px（与 app.js 的 BREAKPOINT、home.js 的分页逻辑一致）：
     · 769~900px 补上移动端顶栏形态：隐藏桌面导航、头像卡变42px 正圆 + 文字隐藏；
     · 同时补上底部 TAB（X21 段的 tabbar 显示规则也是 768px，这里一并覆盖）。
   900px 以下全部按移动端渲染，900px 以上保持桌面端，两侧行为一致无中间态。
   ========================================================================== */
@media (min-width: 769px) and (max-width: 900px) {
  /* 移动端顶栏形态：隐藏汉堡与桌面导航 */
  .nav-toggle { display: none !important; }
  .masthead-nav { display: none !important; }
  .masthead-brand { flex: 1 1 0; }
  .masthead-actions { flex: 0 0 auto; }

  /* 头像卡：42px 正圆 + 隐藏文字（与 ≤768px 的 X20 段同款）。
     !important 的原因见 X20 段注释：archive.css:259 有同属性的 !important。 */
  .masthead-actions .nav-user {
    width: 42px !important;   /* 卡片 42px：与 40px 头像配对，白圈 1px */
    height: 42px;
    padding: 0 !important;
    gap: 0 !important;
    border-radius: 50% !important;
    justify-content: center;
    align-items: center;
    overflow: hidden;
    background: #fff;
  }
  .masthead-actions .nav-user-text { display: none !important; }
  /* 移动端头像 30 → 40px：卡片 42px 内几乎撑满，白圈 1px（用户指定值）。 */
  .masthead-actions .nav-user-avatar { width: 40px; height: 40px; }

  /* 深色模式头像卡底色（避免深色页上一块刺眼白圆） */
  [data-theme="dark"] .masthead-actions .nav-user { background: #16191f; }

  /* 底部 TAB 的完整样式（毛玻璃白卡 / 胶囊圆角 / 托件渐变遮罩 / 让位留白 / 隐藏页脚）
     已由 mobile-app.css 的 `@media (max-width: 900px)` 段统一接管 ——
     该断点已从 768px 提到 900px，与本段和 app.js 的 BREAKPOINT 一致。
     浅色与深色参数均照抄顶栏 #masthead：
       浅色 rgba(255,255,255,.86) + saturate(180%) blur(20px)
       深色 rgba(13,16,20,.8)
     这里不再重复定义，避免两处规则分叉。 */
}



/* ==========================================================================
   X30. 公告：悬浮胶囊 + 内容单行横向流动（2026-10-04 v4）
   --------------------------------------------------------------------------
   本段经过 v1~v4 四轮迭代，教训见项目记忆。要点：
   · `position: fixed !important` —— 不占文档流，**既不推开后续内容、
     也不被后续内容推开**，所以首屏 Hero 位置完全不受影响（实测差值 0px）。
   · 定位属性必须加 !important：app.css 里 `#noticeBar` 是 `position:sticky;top:0`，
     与本段特异性相同；虽然本文件后加载但实测 top 会被压成 676px。
     且 theme-xiaoyi.css 是**跨域**样式表，`cssRules` 无法枚举、查不到冲突源。

   本轮用户要求：
     ① 「知道了」按钮**始终固定在最右侧**，不随内容长短变化
     ② 内容超出时**在本行内横向滚动**（电子屏流动效果），PC/移动端一致
     ③ **删掉** 1/3 数量标签
   实现要点：
     · 行容器 `.notice-inner` 改单行 flex + `flex-wrap: nowrap`；
       「知道了」用 `margin-left: auto` 顶到最右（内容再长也不会推动它）。
     · 标题 `flex: none`（短标题不压缩），正文 `.notice-body` 是唯一的可伸缩项；
     · 正文用 `white-space: nowrap` + `overflow: hidden`，
       JS 测 `scrollWidth > clientWidth` 才加 `.notice-scrolling` 类启动无缝流动动画。
   ========================================================================== */
#noticeBar {
  position: fixed !important;
  top: 72px !important;                 /* 顶栏 64px + 8px 间距 */
  left: 50% !important;
  right: auto !important;
  transform: translateX(-50%) !important;
  z-index: 89;                          /* 低于顶栏(90) */
  width: min(1100px, calc(100vw - 40px));
  /* ⚠️ 必须清掉 app.css 的 padding:8px 16px —— 它不在盒模型预期内，
     会让内容区只剩 36px 而行盒有 50px，**内容整体上移约 7px**（用户反馈「没居中」）。 */
  padding: 0 !important;
  overflow: hidden;
  border: 1px solid rgba(17, 17, 17, .12);
  border-radius: 999px;
  /* 与底部 TAB 白卡同款毛玻璃参数（照抄 mobile-app.css M1 段的 .tab-inner） */
  background: rgba(255, 255, 255, .45);
  -webkit-backdrop-filter: saturate(220%) blur(24px) brightness(1.04);
  backdrop-filter: saturate(220%) blur(24px) brightness(1.04);
  max-height: 52px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .95),
    0 6px 24px rgba(16, 24, 40, .1),
    0 2px 6px rgba(17, 17, 17, .06);
  transition: max-height .3s ease, opacity .3s ease, transform .3s ease;
}
/* 收起态：高度压到0 + 透明 + 轻微上移 */
#noticeBar.notice-collapsed {
  max-height: 0;
  opacity: 0;
  pointer-events: none;
  border-width: 0;
  padding: 0;
  height: 0;
  transform: translateX(-50%) translateY(-8px) !important;
}

/* ---------- 内容行：单行横向布局，按钮固定最右 ---------- */
#noticeBar .notice-inner {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;            /* 关键：绝不换行 */
  gap: 10px;
  padding: 0 8px 0 16px;
  color: var(--ink);
  font-size: 13px;
  /* 垂直居中靠 flex 的 align-items，而不是把 line-height 设成容器高度：
     中文字体墨迹在基线以上，line-height 等于行高时字形会**偏上** 2~3px。
     保持自然行高 + align-items:center 才是真正的视觉居中。 */
  line-height: 1.5;
  min-height: 50px;            /* 固定行高，保证单行高度稳定 */
  white-space: nowrap;
}
/* 「公告」小标签：品牌蓝胶囊 */
#noticeBar .notice-tag {
  flex: none;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--grad);
  color: #fff;
  font-size: 11.5px;
  font-weight: 500;
  line-height: 18px;
  align-self: center;
  letter-spacing: .2px;
}
/* 标题：短标题固定宽度不压缩（省略号） */
#noticeBar .notice-title {
  flex: none;
  max-width: 34%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--ink);
  font-weight: 600;
}
/* 正文：唯一可伸缩项 —— 超出时横向流动 */
#noticeBar .notice-body {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  line-height: 1.5;
}
/* 关闭按钮：margin-left:auto 顶到最右，
   内容再长/再短都不会改变它的位置 */
/* 方案 B：24px 淡灰圆底 + 深色 ×
   ------------------------------------------------------------------
   为什么不用纯符号（方案 A）：13px 的 × 在触屏上点击热区不足，
   且「一个符号」不像可点控件。
   为什么不用品牌蓝实心（方案 C）：会和左侧蓝色「公告」标签抢视觉焦点。
   淡灰圆底既给出点击暗示，又不抢焦点；hover 加深到 .12 作为反馈。
   视觉 24px，但用 ::before 把可点热区撑到 40px（触屏友好）。 */
#noticeBar .notice-close {
  flex: none;
  margin-left: auto;
  position: relative;                /* ::before 绝对定位的参照 */
  width: 24px; height: 24px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--paper-2);         /* 淡灰圆底，与站点其它 icon-btn 同族 */
  color: var(--ink-2);                /* 比 ink-3 深一档，× 更清晰 */
  cursor: pointer;
  transition: background .2s, color .2s;
}
/* 扩大触屏热区到 40x40（视觉不变） */
#noticeBar .notice-close::before {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  width: 40px; height: 40px;
  transform: translate(-50%, -50%);
}
#noticeBar .notice-close:hover {
  background: rgba(16, 24, 40, .12);
  color: var(--ink);
}
[data-theme="dark"] #noticeBar .notice-close { background: rgba(255, 255, 255, .12); }
[data-theme="dark"] #noticeBar .notice-close:hover { background: rgba(255, 255, 255, .2); }

/* ---------- 电子屏流动效果（无缝横向滚动 + 动态时长 + 两侧淡出） ----------
   四个关键点（2026-10-04 用户要求）：
   ① **出场先停 1 秒**：animation-delay 让文字先静止可读，再开始滚动。
     注意 infinite 动画的 delay 只在首次生效 —— 正好符合「出来时停一下」。
   ② **速度按阅读舒适度**：不再写死 9s，改用 CSS 变量 `--marquee-dur`，
     由 JS 按「文本实际宽度 ÷ 舒适阅读速度(30px/s)」算出。
     文字越长滚得越久，但**速度恒定**——这比固定时长更合理。
   ③ **两侧淡出遮罩**：文字从边缘「长出来」而不是被硬切断，
     这是 LED 屏的标准做法，也消除了原来「文字被胶囊边缘齐刷刷切断」的生硬感。
     用 mask-image 实现（纯 CSS，不需要额外元素）。
   ④ 时长与切条间隔联动：JS 读回 --marquee-dur，让「切下一条」的时间点
     始终落在本条内容滚完之后（见app.js 的 scheduleNext）。
   只在检测到溢出时才加 .notice-scrolling，短内容保持静止。 */
@keyframes notice-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
/* 跑道 padding 必须「常驻」，不能只在 .notice-scrolling 时加：
   若仅滚动态才加，开滚那一刻 padding 从 0 → 18px 会把整段文字**向右推 18px**，
   表现为「先先后退一下、再开始滚动」（2026-10-04 用户反馈）。
   遮罩仍只在滚动态加（静态短内容两端无字，淡出无意义），
   但 padding 与遮罩配套、保持常量，切换时零位移。 */
#noticeBar .notice-body { position: relative; padding: 0 18px; }
#noticeBar .notice-body-inner { display: inline-flex; white-space: nowrap; }
#noticeBar .notice-scrolling .notice-body-inner {
  /* --marquee-dur / --marquee-delay 由 syncNoticeMarquee 按文本宽度写入 */
  animation: notice-marquee var(--marquee-dur, 14s) linear infinite;
  animation-delay: var(--marquee-delay, 1s);
  will-change: transform;
}
/* ---------- 两侧淡出 ----------
   mask-image 会在元素上开一个裁剪/遮罩通道，让指定区域透明。
   纯 CSS 实现，不需要额外的渐变覆盖层（那样会挡住 hover 命中）。
   2026-10-04 重做（用户反馈「内容的头一个字会被遮挡一点，两边都一样」）：
   原渐变 0~40px 才到全不透明，汉字字宽约 13px，第一个字一出场就落在
   渐隐带里被吃掉一截。现改为「跑道」方案：
   · 滚动态给 body 左右各留 18px padding（跑道），遮罩渐隐带收窄到
     恰好只覆盖这段 padding —— 第一个字永远落在全不透明区域，完整可读；
   · 文字滚入/滚出边缘时依然平滑淡出，保留 LED 屏效果，不会生硬切断。
   只在流动时加：静态短内容两端本来就没有文字，遮罩无意义。 */
#noticeBar .notice-body.notice-scrolling {
  -webkit-mask-image: linear-gradient(to right,
    transparent 0, rgba(0, 0, 0, .4) 7px, #000 18px,
    #000 calc(100% - 18px), rgba(0, 0, 0, .4) calc(100% - 7px), transparent 100%);
  mask-image: linear-gradient(to right,
    transparent 0, rgba(0, 0, 0, .4) 7px, #000 18px,
    #000 calc(100% - 18px), rgba(0, 0, 0, .4) calc(100% - 7px), transparent 100%);
}
/* 窄屏上可视区小，跑道收窄到 12px */
@media (max-width: 900px) {
  #noticeBar .notice-body { padding: 0 12px; }
  #noticeBar .notice-body.notice-scrolling {
    -webkit-mask-image: linear-gradient(to right,
      transparent 0, rgba(0, 0, 0, .4) 4px, #000 12px,
      #000 calc(100% - 12px), rgba(0, 0, 0, .4) calc(100% - 4px), transparent 100%);
    mask-image: linear-gradient(to right,
      transparent 0, rgba(0, 0, 0, .4) 4px, #000 12px,
      #000 calc(100% - 12px), rgba(0, 0, 0, .4) calc(100% - 4px), transparent 100%);
  }
}
/* 悬停时暂停，方便阅读 */
#noticeBar:hover .notice-scrolling .notice-body-inner,
#noticeBar .notice-body-inner:hover { animation-play-state: paused; }
/* 尊重「减少动态效果」偏好 */
@media (prefers-reduced-motion: reduce) {
  #noticeBar .notice-scrolling .notice-body-inner { animation: none; }
}

/* 数量标签已按用户要求移除（不再渲染 1/3） */

/* 深色模式 */
[data-theme="dark"] #noticeBar {
  background: rgba(13, 16, 20, .9);
  border-color: rgba(255, 255, 255, .1);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .14),
    0 6px 24px rgba(0, 0, 0, .5);
}


/* ==========================================================================
   X30-b. 公告的移动端适配：贴到底部 TAB 上方（≤900px，跟随底部 TAB）
   --------------------------------------------------------------------------
   用户要求：移动端公告挪到**底部 TAB 上方**、与 TAB 保持间距、高度更小、
   内容垂直居中。
   · 定位用 `bottom: var(--notice-bottom, 96px)` —— 值由 app.js 的
     `syncNoticePosition()` 按 TAB 实测 top 写入，卡片底边始终落在 TAB 上沿
     之上 10px 处；不写死数值，safe-area / TAB 高度变化都能自动跟随。
   · `top: auto !important` 必须显式复位 —— 桌面端用的是 top:72px，
     同一元素切到移动断点时不复位会与 bottom 叠加（app.css 的 sticky 教训）。
   · 高度：外层 max-height 收到 48px（桌面 64px），单行更紧凑。
   ========================================================================== */
@media (max-width: 900px) {
  #noticeBar {
    top: auto !important;/* 必须复位，否则与 bottom 叠加 */
    left: 10px !important;
    right: 10px !important;
    bottom: var(--notice-bottom, 96px) !important;
    width: auto !important;
    transform: none !important;
    border-radius: 999px !important;      /* 与 PC 一致的胶囊圆角 */
    padding: 0 !important;
    max-height: 48px !important;          /* 比桌面更紧凑 */
  }
  #noticeBar.notice-collapsed { transform: translateY(8px) !important; }

  /* 垂直居中：保持自然行高 + flex align-items:center。
     不要把 line-height 设成容器高度 —— 中文字形墨迹在基线以上会偏上 2~3px。 */
  #noticeBar .notice-inner {
    padding: 0 6px 0 12px;
    gap: 8px;
    font-size: 12.5px;
    line-height: 1.5;
    height: 46px !important;         /* !important：覆盖桌面段的 min-height: 50px */
    min-height: 0 !important;
  }
  #noticeBar .notice-tag {
    padding: 1px 8px;
    font-size: 11px;
    line-height: 16px;
  }
  #noticeBar .notice-title { max-width: 32%; }
  #noticeBar .notice-body { line-height: 1.5; }
  /* 移动端：视觉 22px（胶囊只有 48px 高，24px 偏挤），热区仍由 ::before 撑到 40px */
  #noticeBar .notice-close { width: 22px; height: 22px; }
}

/* ==========================================================================
   X31. 升级查询页：Hero 化重构（2026-10-04，完全推翻重做）
   --------------------------------------------------------------------------
   ** 为什么这一段是「推翻重做」而不是渐进增强 **
   原来 OTA 页用的是社区 / 分享页那一套「.page-head 页头 + 若干等权重 .card」，
   但站内真正有辨识度的是**固件页与个人中心那一套**：

     ① 无边框 Hero 区（.dk-hero / .pf-hero）
        图标 60×60 / 圆角 20px / 品牌蓝渐变 + 28px 图标 + `0 10px 28px`蓝色投影
        标题 **34px / font-weight 800 / lh 40.8px**
        描述 15.5px / line-height 1.75 / max-width 780px
        Hero 与下一个区块间距 **30px**
     ② 指标块内嵌在白卡里（.pf-idcard-stats 的 .pf-stat）
        浅灰底 rgb(247,248,250)、圆角 12px、内联排列
     ③ 区块标题用 `小标签 + 标题` 的双层结构（DK / GARAGE 这种英文小标签）

   而 OTA 页原来是 26px / 500 的 .page-head 标题 + 4 个等权重白卡，
   视觉上「工具页」味道很重，进门没有全站统一的仪式感。
   本段把它改成与固件 / 个人中心**完全同款**的骨架：
     Hero（图标 + 34px 大标题 + 描述 + 品牌标签）
       → 4 块指标（名下车辆 / 可升级 / 未获推送 / 去固件）
       → 查询面板（小标签 VIN + 标题 + 描述 + 表单）
       → 结果区
       → 我的车辆面板（小标签 GARAGE + 标题）
       → 说明条

   间距全部**单向 margin-top**（只用 top，不用 bottom）：
   之前「上块 margin-bottom + 下块 margin-top」会在空容器
   （#oResult 查询前高度 0）时叠加成 40px，非空时 20px —— 间距忽大忽小。
   ========================================================================== */

/* ---------- Hero 区（照抄 dk-hero 规格） ---------- */
.ota-hero {
  text-align: center;
  margin-bottom: 30px;
}
.ota-hero-ico {
  display: inline-grid; place-items: center;
  width: 60px; height: 60px;
  border-radius: var(--r-panel);
  color: #fff;
  margin-bottom: 16px;
  background: var(--grad);
  box-shadow: 0 10px 28px rgba(17, 17, 17, .2);
}
.ota-hero-ico svg { width: 28px; height: 28px; }
.ota-hero h1 {
  font-size: 34px; font-weight: 800; letter-spacing: -.5px;
  color: var(--ink); margin: 0 0 12px;
}
.ota-hero > p {
  font-size: 15.5px; color: var(--ink-2); line-height: 1.75;
  max-width: 780px; margin: 0 auto; text-wrap: balance;
}
/* 品牌标签：与 dk-tag 同款胶囊 */
.ota-hero-tags { display: flex; justify-content: center; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.ota-tag {
  display: inline-flex; align-items: center;
  height: 31px; padding: 0 14px;
  border-radius: 999px;
  background: var(--paper-2);
  color: var(--ink);
  font-size: 12.5px; font-weight: 600;
}

/* ---------- 指标区：4 块，链接块可点 ---------- */
.ota-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 30px;
}
.ota-stat {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 4px;
  min-height: 84px; padding: 14px 12px;
  border: 0;
  border-radius: var(--r-panel);
  background: var(--paper);
  box-shadow: 0 2px 8px rgba(16, 24, 40, .04);
  transition: transform .2s ease, box-shadow .2s ease;
}
.ota-stat:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(16, 24, 40, .08); }
.ota-stat-num {
  font-size: 30px; font-weight: 600; line-height: 1.05; letter-spacing: -.5px;
  color: var(--brand);
  font-family: var(--font-num, var(--font-mono));
  font-variant-numeric: tabular-nums;
}
.ota-stat-label { font-size: 12.5px; color: var(--ink-3); line-height: 1.4; }
/* 第4 块是入口链接，图标代替数字 */
.ota-stat-link { text-decoration: none; }
.ota-stat-link .ota-stat-num { color: var(--ink-2); line-height: 1; }
.ota-stat-link .ota-stat-num svg { width: 26px; height: 26px; }

/* ---------- 内容面板（替代 .card，功能区专用） ---------- */
.ota-panel {
  background: var(--paper);
  border: 0;
  border-radius: var(--r-panel);
  padding: 22px;
  margin-top: 30px;
  box-shadow: 0 2px 8px rgba(16, 24, 40, .04);
}
.ota-panel-head { margin-bottom: 14px; }
.ota-panel-idx {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 11.5px; font-weight: 600; letter-spacing: 1.2px;
  color: var(--brand);
  margin-bottom: 6px;
}
.ota-panel-head h2 {
  font-size: 19px; font-weight: 700; color: var(--ink);
  margin: 0 0 6px;
}
.ota-panel-desc { font-size: 12.5px; color: var(--ink-2); margin: 0; line-height: 1.6; }

.ota-vin-wrap { margin-top: 12px; }
.ota-series-block { margin-top: 16px; }
.ota-series-tip { margin: 10px 0 0; font-size: 12px; }

/* 结果区：查询后由 JS 填入卡片，这里给统一间距 */
#oResult { margin-top: 30px; }
#oResult:empty { margin-top: 0; }

/* ---------- 说明条 ---------- */
.ota-notes {
  margin-top: 30px;
  padding: 16px 22px;
  border-radius: var(--r-panel);
  background: var(--paper-2);
}
.ota-notes .txt-faint { margin: 0; font-size: 12px; line-height: 1.75; }
.ota-notes .txt-faint + .txt-faint { margin-top: 8px; }

[data-theme="dark"] .ota-stat,
[data-theme="dark"] .ota-panel { border-color: rgba(255, 255, 255, .1); }
[data-theme="dark"] .ota-stat-num { color: var(--ink); }
[data-theme="dark"] .ota-stat-link .ota-stat-num { color: var(--ink-2); }

/* ---------- 移动端（断点 900px，跟随底部 TAB） ---------- */
@media (max-width: 900px) {
  .ota-hero { margin-bottom: 22px; }
  .ota-hero-ico { width: 52px; height: 52px; border-radius: var(--r-panel); margin-bottom: 13px; }
  .ota-hero-ico svg { width: 24px; height: 24px; }
  .ota-hero h1 { font-size: 25px; margin-bottom: 9px; }
  .ota-hero > p { font-size: 13.5px; line-height: 1.7; }
  .ota-hero-tags { gap: 6px; margin-top: 13px; }
  .ota-tag { height: 26px; padding: 0 11px; font-size: 11.5px; }

  /* 4 块指标在移动端排 2×2，宽度足够放数字 */
  .ota-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin-bottom: 22px; }
  .ota-stat { min-height: 72px; padding: 12px 8px; border-radius: var(--r-panel); }
  .ota-stat-num { font-size: 24px; }
  .ota-stat-label { font-size: 11.5px; }

  .ota-panel { padding: 16px 14px; margin-top: 22px; border-radius: var(--r-panel); }
  .ota-panel-head h2 { font-size: 17px; }
  #oResult { margin-top: 22px; }
  .ota-notes { margin-top: 22px; padding: 14px; border-radius: var(--r-panel); }
}

/* ==========================================================================
   X32. 升级查询：三步竖向流程（2026-10-04，方案 B）
   --------------------------------------------------------------------------
   ** 模块本质是一条线性流程，不是两条查询路径 **
     ① 选择品牌    [必填]  决定查询范围
     ② 输入车架号[必填]  17 位输完自动查
     ③ 补充车型配置 [选填]  可显示同款车主推送汇总
   原布局把「品牌胶囊 + VIN 输入 + 车系按钮」平铺在一起，
   用户看不出主次，也不知道②依赖①。

   视觉规则（与设计稿一致）：
     · 步骤标三态：done= 实心✓ / current= 实心蓝底数字 / wait= 虚线空心
     · 选填步骤用**虚线框** + 灰「选填」标签，与必填的实心块区分
     · 未选品牌时 VIN 输入框**置灰不可用**（依赖关系视觉化）
   查询逻辑一行没改，只多了状态同步函数 syncSteps()。
   ========================================================================== */

/* ---------- 步骤容器 ---------- */
.ota-steps { list-style: none; margin: 0; padding: 0; }

.ota-step {
  position: relative;
  display: flex;
  gap: 12px;
  /* 竖线连接：最后一步不画 */
  padding-bottom: 20px;
}
.ota-step:last-child { padding-bottom: 0; }
/* 竖线：用 ::before 画在标下方，避免最后一个多出一截 */
.ota-step:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 11.5px;                /* 24px 标的中心 = 12px，往左偏 0.5 让线居中 */
  top: 28px;
  bottom: 4px;
  width: 1.5px;
  background: var(--rule-2);
  border-radius: 1px;
}
.ota-step[data-state="done"]:not(:last-child)::after { background: var(--brand); opacity: .35; }

/* ---------- 步骤标 ---------- */
.ota-step-mark {
  flex: none;
  width: 24px; height: 24px;
  border-radius: 50%;
  display: grid; place-items: center;
  font-size: 12px; font-weight: 600;
  line-height: 1;
  transition: background .2s, color .2s, border-color .2s;
}
.ota-step-no { display: block; color: var(--ink); }
/* 已完成：实心对勾（用 CSS 画两条线，不用图标字体） */
.ota-step[data-state="done"] .ota-step-mark {
  background: var(--brand);
  color: #fff;
}
.ota-step[data-state="done"] .ota-step-no {
  width: 9px; height: 5px;
  border-left: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg) translate(1px, -2px);
  font-size: 0;
}
/* 当前：实心蓝底数字 */
.ota-step[data-state="current"] .ota-step-mark { background: var(--select-solid); color: var(--select-solid-ink); }
.ota-step[data-state="current"] .ota-step-no { color: var(--select-solid-ink); }
/* 未到达：虚线空心 */
.ota-step[data-state="wait"] .ota-step-mark {
  border: 0;
  background: transparent;
  color: var(--ink-3);
}
/* 选填且未选：浅灰实心（弱于必填的蓝） */
.ota-step[data-state="optional"] .ota-step-mark {
  background: var(--paper-2);
  color: var(--ink-3);
}

/* ---------- 步骤内容 ---------- */
.ota-step-body { flex: 1; min-width: 0; }
.ota-step-head { display: flex; align-items: center; gap: 8px; margin-bottom: 3px; }
.ota-step-title { font-size: 15px; font-weight: 600; color: var(--ink); line-height: 1.4; }
/* 未到达的步骤整体降透明度 */
.ota-step[data-state="wait"] .ota-step-title { color: var(--ink-3); }

/* 必填 / 选填 标签 */
.ota-step-req,
.ota-step-opt {
  display: inline-flex; align-items: center;
  height: 18px; padding: 0 7px;
  border-radius: 999px;
  font-size: 11px; font-weight: 500; line-height: 1;
}
.ota-step-req { background: var(--grad); color: #fff; }
.ota-step-opt { background: var(--paper-2); color: var(--ink-3); }

.ota-step-desc { font-size: 12.5px; color: var(--ink-2); margin: 0 0 10px; line-height: 1.6; }
.ota-step[data-state="wait"] .ota-step-desc { color: var(--ink-3); }
.ota-step-hint { font-size: 12px; color: var(--ink-3); margin: 6px 0 0; }

/* ---------- VIN 输入框的锁定态 ---------- */
.ota-vin-wrap { margin-top: 0; }
.ota-vin-wrap.is-locked {
  background: var(--paper-2);
  border-color: transparent;
  color: var(--ink-3);
}
.ota-vin-wrap.is-locked .search-input {
  background: transparent;
  color: var(--ink-3);
  cursor: not-allowed;
}
.ota-vin-wrap.is-active { border-color: var(--brand); }
.ota-vin-wrap.is-done { border-color: var(--brand); }

/* ---------- 选填步骤：虚线框 ---------- */
.ota-step-optional .ota-step-body {
  border: 0;
  border-radius: var(--r-panel);
  padding: 14px 16px;
  background: var(--gray-wash);
}
.ota-step[data-state="done"].ota-step-optional .ota-step-body {
  border-style: solid;
  border-color: var(--rule);
  background: var(--paper);
}
/* 选填步骤里品牌未选时整体弱化 */
.ota-step-optional[data-locked="1"] { opacity: .55; }
.ota-step-optional .ota-step-desc { margin-bottom: 12px; }
.ota-step-optional .row-gap { margin-top: 0; }
.ota-step-optional .ota-series-tip { margin: 10px 0 0; font-size: 12px; }

[data-theme="dark"] .ota-step[data-state="wait"] .ota-step-mark { border-color: rgba(255,255,255,.22); }
[data-theme="dark"] .ota-step-optional .ota-step-body {
  border-color: rgba(255,255,255,.16);
  background: rgba(255,255,255,.04);
}

/* ---------- 移动端（断点 900px） ---------- */
@media (max-width: 900px) {
  .ota-step { gap: 10px; padding-bottom: 16px; }
  .ota-step-mark { width: 22px; height: 22px; font-size: 11.5px; }
  .ota-step::after { left: 10.5px; top: 26px; bottom: 3px; }
  .ota-step-title { font-size: 14px; }
  .ota-step-desc { font-size: 12px; margin-bottom: 9px; }
  .ota-step-optional .ota-step-body { padding: 12px 13px; border-radius: var(--r-card); }
}

/* ==========================================================================
   X33. OTA 查询结果卡：状态主推（2026-10-04，方案 A）
   --------------------------------------------------------------------------
   改造前的实测问题：整张卡**全靠 inline style 堆砌**，没有一条 class ——
     · 「可升级 · V1.6.0」标签与版本号挤在同一行，版本号权重过低；
     · VIN 掩码、预计推送、车型码、说明文字**同级散落**，看不出主次；
     · 同款数据与主信息**视觉权重相同**，辅助参考被当成了主角。
   用户的真实问题只有一个：「我的车能不能升、什么版本、什么时候推」。

   本段的信息层级（从重到轻）：
     ① `.ota-res-hero`主状态区  整块带底色，唯一的主角
     ② `.ota-res-state`        状态徽标 + 版本号（大号）
     ③ `.ota-res-facts`        次要事实（车架号 / 车型码），两格并排
     ④ `.ota-same`             同款推送，**浅灰子卡**明确降级为「参考」
   「可升级」用绿色系、「未获推送」用**中性灰**（不用警示橙 ——
   官方只是还没推，不该营造紧张感）。
   ========================================================================== */

/* ---------- 结果卡容器 ---------- */
.ota-res {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--r-panel);
  padding: 20px 22px;
  box-shadow: 0 2px 8px rgba(16, 24, 40, .04);
  animation: none;
}

/* ---------- 车辆标题行 ---------- */
.ota-res-head { margin-bottom: 14px; }
.ota-res-name {
  font-size: 17px; font-weight: 700; color: var(--ink);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.ota-res-name .tag {
  display: inline-flex; align-items: center;
  height: 19px; padding: 0 8px;
  border-radius: 999px;
  background: var(--paper-2); color: var(--ink-3);
  font-size: 11.5px; font-weight: 500;
}
.ota-res-cfg { font-size: 13px; color: var(--ink-2); margin-top: 4px; }

/* ---------- 主状态区（唯一主角） ---------- */
.ota-res-hero {
  border-radius: var(--r-panel);
  padding: 15px 17px;
  margin-bottom: 14px;
}
/* 可升级：绿色系 */
.ota-res--up .ota-res-hero {
  background: rgba(31, 157, 85, .1);
  border: 1px solid rgba(31, 157, 85, .22);
}
/* 未获推送：中性灰（官方还没推，不该用警示色） */
.ota-res--wait .ota-res-hero {
  background: var(--paper-2);
  border: 1px solid var(--rule);
}
.ota-res-state { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.ota-res-badge {
  display: inline-flex; align-items: center;
  height: 26px; padding: 0 11px;
  border-radius: 999px;
  font-size: 13px; font-weight: 600; line-height: 1;
}
.ota-res--up .ota-res-badge { background: #1e7a46; color: #fff; }
.ota-res--wait .ota-res-badge { background: var(--rule-2); color: var(--ink-2); }
/* 版本号：大号，是「什么版本」这个问题的答案 */
.ota-res-ver {
  font-family: var(--font-num, var(--font-mono));
  font-size: 24px; font-weight: 700; line-height: 1.1;
  letter-spacing: -.3px;
  color: #1e7a46;
  font-variant-numeric: tabular-nums;
}
.ota-res-line { font-size: 13.5px; color: var(--ink); margin-top: 9px; font-weight: 500; }
.ota-res--wait .ota-res-line { color: var(--ink-2); font-weight: 400; }
.ota-res-desc { font-size: 12.5px; color: var(--ink-2); margin-top: 5px; line-height: 1.65; }

/* ---------- 次要事实：两格并排 ---------- */
.ota-res-facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.ota-res-fact {
  display: flex; flex-direction: column; gap: 3px;
  padding: 10px 13px;
  border-radius: var(--r-card);
  background: var(--paper-2);
}
.ota-res-fact-k { font-size: 11.5px; color: var(--ink-3); }
.ota-res-fact-v {
  font-family: var(--font-num, var(--font-mono));
  font-size: 13.5px; font-weight: 600; color: var(--ink);
  letter-spacing: .2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- 同款推送：版本卡片固格（方案 C） ---------- */
/* 旧版是「版本号 / 台数 / 时间」三段挤一行、靠 min-width 硬撑对齐，
   版本号长度一变右边界就散了。改为每条一格、居中排布。 */
.ota-same {
  margin-top: 16px;
  padding: 14px 16px;
  border-radius: var(--r-panel);
  background: var(--paper-2);       /* 比主卡浅一档 = 降级 */
}
.ota-same-head { margin-bottom: 10px; }
.ota-same-title { font-size: 13px; font-weight: 600; color: var(--ink-2); }
.ota-same-note { font-size: 11.5px; color: var(--ink-3); margin-left: 8px; }
.ota-same-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: 8px;
}
.ota-same-cell {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 9px 8px;
  border-radius: var(--r-ctl);
  background: var(--paper);
}
.ota-same-ver {
  font-family: var(--font-num, var(--font-mono));
  font-size: 12.5px; font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.ota-same-cars { font-size: 11.5px; color: var(--ink-3); }
/* 第一格（最新/最高版本）用蓝色实底，与「13 台」一起当主角 */
.ota-same-cell.is-top { background: var(--brand); }
.ota-same-cell.is-top .ota-same-ver,
.ota-same-cell.is-top .ota-same-time { color: #fff; }
.ota-same-cell.is-top .ota-same-cars { color: rgba(255, 255, 255, .85); }
.ota-same-time {
  font-family: var(--font-num, var(--font-mono));
  font-size: 10.5px; color: var(--ink-3);
}
.ota-same-empty { font-size: 12.5px; color: var(--ink-3); margin: 0; }
.ota-same-more {
  margin-top: 10px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--brand);
  font-size: 12.5px; font-family: var(--font-body);
  cursor: pointer;
}
.ota-same-more:hover { text-decoration: underline; }

[data-theme="dark"] .ota-res--up .ota-res-hero { border-color: rgba(31, 157, 85, .3); }
[data-theme="dark"] .ota-res-ver { color: #4cc47c; }
[data-theme="dark"] .ota-res--up .ota-res-badge { background: #1e7a46; }
[data-theme="dark"] .ota-same-cell { background: rgba(255, 255, 255, .05); }
[data-theme="dark"] .gar-same-cell { background: rgba(255, 255, 255, .04); }

/* ---------- 移动端（断点 900px） ---------- */
@media (max-width: 900px) {
  .ota-res { padding: 16px 14px; border-radius: var(--r-panel); }
  .ota-res-name { font-size: 15.5px; }
  .ota-res-hero { padding: 13px 14px; border-radius: var(--r-card); }
  .ota-res-badge { height: 24px; font-size: 12.5px; }
  .ota-res-ver { font-size: 21px; }
  .ota-res-line { font-size: 13px; margin-top: 8px; }
  .ota-same { padding: 12px 13px; border-radius: var(--r-card); }
  .ota-same-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
  .ota-same-note { margin-left: 0; }
  /* 移动端固格收成2 列：minmax(84px,1fr) 在 320~375px 下会挤成 3 列且每格过窄 */
  .ota-same-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px; }
}

/* ---------- X33-b. 结果头的两种形态统一 ----------
   之前未补录车型时标题是「方程豹代查」（"代查" 拼进文字里），
   补录后却是「方程豹·钛3·2025款钛3」+ 独立胶囊 —— 两种形态不一致。
   现在统一为：**标题 + 代查胶囊**，副标题行始终存在：
     · 已补录 → 显示具体配置名（正常灰）
     · 未补录 → 「未指定车型配置」（更浅的灰，明确是缺省态而非遗漏） */
.ota-res-cfg.is-empty { color: var(--ink-3); }

/* ---------- X33-c. 「代查」胶囊内文字垂直居中 ----------
   症状：胶囊里「代查」两个字偏上（用户截图）。
   原因：`.ota-res-name` 的 `line-height: 1.7` 被胶囊继承 ——
   11.5px × 1.7 = 19.55px，而胶囊被 `height: 19px` 固定，
   19.55 > 19 → 文字被顶到盒子上沿，视觉上不居中。
   修法：胶囊自己显式声明 `line-height: 1`（= 11.5px < 19px），
   配合 `align-items: center` 才能真正垂直居中。
   ⚠️ 这是「固定高度的 flex 居中」通用坑：
   父级 line-height 永远会渗进固定高度的子元素。 */
.ota-res-name .tag {
  line-height: 1;
}

/* ---------- X33-d. 「代查」胶囊水平居中 ----------
   症状：胶囊里「代查」左边留白比右边大 10px（用户截图）。
   根因：全站 `.tag::before` 有一个 **5px 圆点 + gap: 5px = 10px** 的装饰
   （app.css:294），它没有背景色所以看不见，但**仍然占位**。
     盒宽 49 = 圆点 5 + gap 5 + 文字 23 + padding 8×2 = 49✓
     左内边距 = 5+5+8 = 18，右 = 8 → 差 10px。
   「代查」是纯文字标签，不需要这个圆点 —— 显式去掉伪元素即可。
   ⚠️ 判据：用 Range 量`(文字盒.left - 盒.left)` 与 `(盒.right - 文字盒.right)`，
   两者不等就是有不可见元素占位（同「垂直居中」那次的思路一致）。 */
.ota-res-name .tag::before { display: none; }

/* ==========================================================================
   X34. 我的车辆：检测总览条 + 横向车辆卡 + 三段动效（2026-10-04）
   --------------------------------------------------------------------------
   改造前的实测问题：
     · 车辆用 `myCars.insertAdjacentHTML('beforeend')` **一张张追加**，
       每台车结果到达时间不同，视觉上完全没有整体感；
     · 每张卡里都塞了重复的状态标签（.tag.ok / .tag.wait），
       而状态恰恰是最该被"提出来"的信息；
     · 检测状态是一行纯文字 `检测完成：1 台可升级 · 2 台未获推送`，
       读起来像日志，扫一眼看不出比例。
   改法（与用户确认的三点）：
     ① 「重新检测」按钮放进**总览条**，车辆区只留结果；
     ② 卡内详情/固件改为**整卡点击展开**（防误触：内部链接与固件按钮 stopPropagation）；
     ③ 多台车默认**全收起 + 「全部展开」**。
   ========================================================================== */

/* ---------- 检测总览条 ---------- */
.gar-bar {
  border-radius: var(--r-panel);
  background: var(--paper-2);
  padding: 14px 16px;
  margin-bottom: 14px;
}
.gar-bar-top { display: flex; align-items: center; gap: 9px; }
.gar-bar-text { flex: 1; font-size: 13.5px; color: var(--ink-2); }
/* 「重新检测」：.btn.sm 的 5px 13px + 12px 字只有 ~26px 高，
   比同页其它胶囊（34~38px）矮一档，看起来像被压扁的小号按钮。
   ⚠️ 元素同时带 .btn.sm（权重 0,2,0），会压过 .gar-recheck（0,1,0），
      所以下面全部用 .btn.gar-recheck 提权。 */
.btn.gar-recheck,
.gar-recheck {
  flex: none;
  display: inline-flex; align-items: center; gap: 6px;
  border: 0;
  background: var(--gray-wash);
  color: var(--ink-2);
  font-family: var(--font-body);
  font-size: 13px; font-weight: 600; line-height: 1;
  padding: 10px 17px;
  border-radius: 999px;
  box-shadow: none;
  cursor: pointer;
  transition: background .2s, color .2s, box-shadow .2s;
}
.gar-recheck svg { width: 14px; height: 14px; }
.btn.gar-recheck:hover,
.gar-recheck:hover {
  color: var(--accent);
  background: var(--brand-wash);
  box-shadow: 0 2px 8px rgba(17, 17, 17, .12);
}
[data-theme="dark"] .btn.gar-recheck,
[data-theme="dark"] .gar-recheck { background: rgba(255, 255, 255, .08); }
/* 扫描脉冲点 */
.gar-bar-dot {
  flex: none;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--brand);
}
.gar-bar[data-state="scanning"] .gar-bar-dot { animation: gar-pulse 1.15s ease-in-out infinite; }
.gar-bar[data-state="done"] .gar-bar-dot { background: #1e7a46; animation: none; }
@keyframes gar-pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50%      { transform: scale(1.5); opacity: .35; }
}
/* 逐台点亮的进度（方案 A）：N 段进度槽，一台车占一段。
   旧版是一根 4px 细进度条 + 脉冲圆点，幅度小到「看不出在动」。
   现在每台车 = 一段实心块，查完一台点亮一段 —— 进度即真实台数。 */
.gar-steps {
  display: flex; gap: 5px;
  margin-top: 12px;
}
.gar-step {
  flex: 1;
  height: 6px;
  border-radius: 999px;
  background: var(--rule);
  transition: background .3s ease, transform .3s cubic-bezier(.22, 1, .36, 1);
}
/* 未点亮段轻微脉动，制造「正在逐台推进」的持续感；
   幅度刻意很小（1 → 1.08），太大会像故障闪烁。 */
.gar-bar[data-state="scanning"] .gar-step {
  animation: gar-step-wait 1.4s ease-in-out infinite;
}
@keyframes gar-step-wait {
  0%, 100% { transform: scaleY(1);   opacity: 1; }
  50%      { transform: scaleY(1.35); opacity: .55; }
}
.gar-step.is-on {
  background: var(--grad);
  animation: none !important;
  transform: none;
}
/* 完成后**整条进度区隐藏**：
   下方三格统计（可升级 / 未获推送 / 查询时间）已经说明了结果，
   再留一条满格线纯属重复信息。 */
.gar-bar[data-state="done"] .gar-steps,
.gar-bar[data-state="done"] .gar-steps-n { display: none; }
.gar-steps-n {
  margin: 7px 0 0;
  font-size: 11.5px;
  color: var(--ink-3);
  font-family: var(--font-num, var(--font-mono));
}

/* 三格统计 */
.gar-bar-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: 12px; }
.gar-stat {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 9px 8px;
  border-radius: var(--r-card);
  background: var(--paper);
}
.gar-stat b {
  font-family: var(--font-num, var(--font-mono));
  font-size: 21px; font-weight: 700; line-height: 1.15;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.gar-stat span { font-size: 11.5px; color: var(--ink-3); }
.gar-stat.is-up b { color: #1e7a46; }
.gar-stat.is-time b { font-size: 14px; font-weight: 600; color: var(--ink-2); padding-top: 3px; }

/* ---------- 工具行 ---------- */
.gar-tools {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 10px;
}
.gar-tools-n { flex: 1; font-size: 12.5px; color: var(--ink-3); }
/* 「全部展开 / 全部收起」
   ⚠️ 基准是固件资源页 .dk-chip 的**实测**值，不是目测：
      font 14px/600 · padding 11px 20px · 高 38px · border-radius 999px
      border 1px solid transparent · line-height 1· 选中阴影 0 2px 8px rgba(17,17,17,.24)
   之前只对齐了颜色变量，漏了 border / line-height / 高度 → 显得比站内按钮矮一档。
   这里字号降到 12.5px（它是工具条上的次级操作，不是内容选择器），其余完全照抄。 */
.gar-tools-all {
  display: inline-flex; align-items: center; gap: 5px;
  border: 0;
  background: var(--bg-gray);
  color: var(--ink-2);
  font-size: 12.5px; font-weight: 600; line-height: 1;
  font-family: var(--font-body);
  padding: 9px 16px;
  border-radius: 999px;
  box-shadow: none;
  cursor: pointer;
  transition: background .2s, color .2s, box-shadow .2s;
}
.gar-tools-all .gar-act-ico { display: inline-flex; transition: transform .22s ease; }
.gar-tools-all .gar-act-ico svg { width: 13px; height: 13px; }
.gar-tools-all:hover {
  background: var(--accent-soft);
  color: var(--accent);
  box-shadow: 0 2px 8px rgba(17, 17, 17, .12);
}
/* 展开态：实心蓝渐变+ 站内选中态同款阴影 */
.gar-tools-all.is-on {
  background: var(--grad);
  color: #fff;
  box-shadow: 0 2px 8px rgba(17, 17, 17, .24);
}
.gar-tools-all.is-on:hover { background: var(--grad); color: #fff; }
[data-theme="dark"] .gar-tools-all { background: rgba(255, 255, 255, .08); }

/* ---------- 车辆卡 · 方案 A：图标方块 + 状态药丸 ---------- */
/* 原「左侧 4px 色条」（.gar-stripe）已删除：4px 宽在 16px 圆角卡里像贴了条胶带，
   还把卡片横向切成两半。改由左侧 42px 图标块承担识别，状态用圆角药丸。 */
.gar-list { display: flex; flex-direction: column; gap: 9px; }
.gar-item {
  position: relative;
  background: var(--paper);
  border: 0;
  border-radius: var(--r-panel);
  padding: 13px 14px;
  cursor: pointer;
  transition: box-shadow .2s ease, transform .2s ease, border-color .2s ease;
  animation: gar-in .42s cubic-bezier(.22, 1, .36, 1) both;
}
.gar-item:hover { box-shadow: 0 6px 18px rgba(16, 24, 40, .07); }
.gar-item.is-open { background: var(--gray-wash); }
.gar-item:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
@keyframes gar-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* 主行：图标块 + 标题区 + 展开箭头 */
.gar-row { display: flex; align-items: flex-start; gap: 12px; }
.gar-ico {
  flex: none;
  display: grid; place-items: center;
  width: 42px; height: 42px;
  border-radius: var(--r-card);
  background: var(--paper-2);
  color: var(--ink-3);
}
.gar-item.is-up .gar-ico { background: rgba(31, 157, 85, .12); color: #1e7a46; }
.gar-item.is-err .gar-ico { background: rgba(220, 38, 38, .1); color: #b91c1c; }
.gar-ico svg { width: 22px; height: 22px; }

.gar-id { flex: 1; min-width: 0; }
.gar-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.gar-title {
  min-width: 0;
  font-size: 15px; font-weight: 600; color: var(--ink);
  margin: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 展开箭头 */
.gar-caret {
  flex: none;
  width: 8px; height: 8px;
  margin-top: 6px;
  border-right: 1.5px solid var(--ink-4);
  border-bottom: 1.5px solid var(--ink-4);
  transform: rotate(45deg);
  transition: transform .22s ease;
}
.gar-item.is-open .gar-caret { transform: rotate(-135deg); margin-top: 2px; }

.gar-meta { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 4px; font-size: 11.5px; color: var(--ink-3); }

/* 状态药丸 */
.gar-k {
  flex: none;
  display: inline-flex; align-items: center;
  height: 20px; padding: 0 10px;
  border-radius: 999px;
  font-size: 11.5px; font-weight: 600; line-height: 1;
}
.gar-k--up   { background: #1e7a46; color: #fff; }
.gar-k--wait { background: var(--paper-2); color: var(--ink-2); }
.gar-k--err  { background: rgba(220, 38, 38, .12); color: #b91c1c; }

/* 版本行：大号版本号 + 预计推送，卡片里的第二主角 */
.gar-brief { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin: 11px 0 0; }
.gar-ver {
  font-family: var(--font-num, var(--font-mono));
  font-size: 22px; font-weight: 700; color: #1e7a46; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.gar-push { font-size: 12px; color: var(--ink-3); }

/* ---------- 展开区 ---------- */
.gar-more {
  margin-top: 12px;
  padding: 12px 14px 14px;
  border-radius: var(--r-card);
  background: var(--paper-2);
}
.gar-note { font-size: 12.5px; color: var(--ink-2); margin: 0 0 5px; line-height: 1.65; }
.gar-note--dim { color: var(--ink-3); }
.gar-note--err { color: #b91c1c; }
.gar-same { margin-top: 12px; }
.gar-same-head { font-size: 12px; font-weight: 600; color: var(--ink-2); margin-bottom: 7px; }
.gar-same-head span { font-weight: 400; color: var(--ink-3); margin-left: 6px; font-size: 11.5px; }
/* 同款推送：版本卡片固格（与查询结果卡 .ota-same-grid 同一语言） */
/* auto-fill + minmax(84px,1fr)：格子数随容器宽度自适应，
   记录少时格子自动铺满整行（不会右侧留白），记录多时自动换行。 */
.gar-same-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 7px; }
.gar-same-cell {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 8px 6px;
  border-radius: var(--r-ctl);
  background: var(--paper);
}
.gar-same-ver {
  font-family: var(--font-num, var(--font-mono));
  font-size: 12.5px; font-weight: 700; color: var(--ink);
}
.gar-same-cars { font-size: 11.5px; color: var(--ink-3); }
.gar-same-time { font-family: var(--font-num, var(--font-mono)); font-size: 10.5px; color: var(--ink-3); }
.gar-actions { display: flex; gap: 8px; align-items: center; margin-top: 12px; flex-wrap: wrap; }
/* 「固件版本 / 车型目录」：照抄固件 .dk-chip 的形态（999px胶囊 + 1px 透明边 + 三态）。
   ⚠️ 底色必须与所在容器反相：
   固件 .dk-chip 的灰底（--bg-gray）放在**白卡**上；这里的按钮放在
   .gar-more 的**灰底**（--paper-2）里，若也用 --bg-gray 就与背景同色 → 视觉融掉。
   规律：白底容器用灰底按钮，灰底容器用白底按钮 + 细边。 */
.gar-act {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--rule);
  background: var(--paper);
  color: var(--ink-2);
  font-size: 12.5px; font-weight: 600; line-height: 1;
  font-family: var(--font-body);
  padding: 9px 16px;
  border-radius: 999px;
  box-shadow: none;
  cursor: pointer; text-decoration: none;
  transition: background .2s, color .2s, box-shadow .2s;
}
.gar-act-ico { display: inline-flex; flex: none; }
.gar-act-ico svg { width: 14px; height: 14px; }
.gar-act:hover {
  background: var(--accent-soft);
  color: var(--accent);
  box-shadow: 0 2px 8px rgba(17, 17, 17, .12);
}
/* 展开态（固件列表已打开）：实心蓝渐变，与站内选中态一致 */
.gar-act.is-on {
  background: var(--grad);
  color: #fff;
  box-shadow: 0 2px 8px rgba(17, 17, 17, .24);
}
.gar-act.is-on:hover { background: var(--grad); color: #fff; }
[data-theme="dark"] .gar-act { background: rgba(255, 255, 255, .08); }

/* ---------- 固件版本列表 ---------- */
/* 结构与参数照抄固件资源页 .dk-row（实测基准）：
   白底卡 + 12px 圆角 + 34px 图标块 + 主副两行 + 右侧大小，hover 右移 2px。
   旧版是内联 style 拼的 flex 单行，没有图标也没有层级，像调试输出。 */
.gar-fw { margin-top: 10px; }
.gar-fw:empty { display: none; }
.gar-fw-list { display: flex; flex-direction: column; gap: 7px; }
.gar-fw-row {
  display: flex; align-items: center; gap: 12px;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--r-card);
  padding: 10px 13px;
  min-width: 0;
  transition: transform .18s, box-shadow .18s, border-color .18s;
}
.gar-fw-row:hover {
  transform: translateX(2px);
  border-color: rgba(17, 17, 17, .28);
  box-shadow: 0 4px 12px rgba(17, 17, 17, .08);
}
.gar-fw-ico {
  flex: none;
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border-radius: var(--r-ctl);
  background: linear-gradient(135deg, #7c8b9e, #9aa8b8);
  color: #fff;
}
.gar-fw-ico svg { width: 18px; height: 18px; }
.gar-fw-main {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 2px;
}
.gar-fw-name {
  font-family: var(--font-num, var(--font-mono));
  font-size: 12.5px; font-weight: 600; line-height: 1.35;
  color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.gar-fw-sub { font-size: 11px; color: var(--ink-3); line-height: 1.35; }
.gar-fw-size {
  flex: none;
  font-family: var(--font-num, var(--font-mono));
  font-size: 12.5px; font-weight: 600;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
/* 「展开其余 N 个」：虚线框按钮，比纯文字更像可点控件，又不抢主行动 */
.gar-fw-more {
  width: 100%;
  margin-top: 2px;
  border: 1px dashed var(--rule-2);
  background: none;
  color: var(--ink-3);
  font-size: 12px; font-weight: 600; font-family: var(--font-body);
  padding: 9px 0;
  border-radius: var(--r-card);
  cursor: pointer;
  transition: color .2s, border-color .2s, background .2s;
}
.gar-fw-more:hover {
  color: var(--brand);
  border-color: var(--brand);
  background: var(--brand-wash);
}
.gar-fw-rest { margin-top: 7px; }

/* ---------- 空态 ---------- */
.gar-empty { text-align: center; padding: 26px 16px; }
.gar-empty-ico {
  display: inline-grid; place-items: center;
  width: 52px; height: 52px;
  border-radius: var(--r-panel);
  background: var(--paper-2);
  color: var(--ink-3);
  margin-bottom: 12px;
}
.gar-empty-ico svg { width: 24px; height: 24px; }
.gar-empty-title { font-size: 15px; font-weight: 600; color: var(--ink); margin: 0 0 5px; }
.gar-empty-desc { font-size: 12.5px; color: var(--ink-3); margin: 0 0 14px; line-height: 1.6; }

[data-theme="dark"] .gar-k--up { background: #1e7a46; }
[data-theme="dark"] .gar-ver, [data-theme="dark"] .gar-stat.is-up b { color: #4cc47c; }
/*深色下图标块不能沿用浅灰 --paper-2（会是一块死灰），改用半透明白 */
[data-theme="dark"] .gar-ico { background: rgba(255, 255, 255, .07); color: var(--ink-3); }
[data-theme="dark"] .gar-item.is-up .gar-ico { background: rgba(31, 157, 85, .18); color: #4cc47c; }
[data-theme="dark"] .gar-item.is-err .gar-ico { background: rgba(220, 38, 38, .16); color: #f09393; }

/* 尊重「减少动态效果」偏好 */
@media (prefers-reduced-motion: reduce) {
  .gar-item { animation: none; }
  .gar-bar[data-state="scanning"] .gar-bar-dot { animation: none; }
  .gar-step { animation: none !important; transition: none; }
  .gar-caret { transition: none; }
}

/* ---------- 移动端（断点 900px） ---------- */
@media (max-width: 900px) {
  .gar-bar { padding: 12px 13px; border-radius: var(--r-card); }
  .gar-bar-text { font-size: 12.5px; }
  .gar-stat b { font-size: 19px; }
  /* 进度槽：窄屏台数多时段太细，gap 收到 3px、高度降到 5px */
  .gar-steps { gap: 3px; margin-top: 10px; }
  .gar-step { height: 5px; }
  .gar-item { border-radius: var(--r-card); padding: 12px 13px; }
  .gar-ico { width: 38px; height: 38px; border-radius: var(--r-ctl); }
  .gar-ico svg { width: 20px; height: 20px; }
  .gar-title { font-size: 14px; }
  .gar-ver { font-size: 20px; }
  .gar-more { padding: 11px 12px 12px; }
  /* 展开区里的同款固格收成 2 列上限（auto-fill + minmax 已保证不会挤破） */
  .gar-same-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* 胶囊按钮在窄屏收小一号，但保持 999px 圆角与三态 */
  .gar-act { font-size: 12px; padding: 8px 14px; gap: 5px; }
  .gar-act-ico svg { width: 13px; height: 13px; }
  .gar-tools-all { font-size: 12px; padding: 8px 14px; }
  /* 固件行：窄屏收小图标与内边距，主副两行已能自然换行 */
  .gar-fw-row { padding: 9px 11px; gap: 10px; }
  .gar-fw-ico { width: 30px; height: 30px; border-radius: var(--r-ctl); }
  .gar-fw-ico svg { width: 16px; height: 16px; }
  .gar-fw-name { font-size: 12px; }
}

/* ==========================================================================
   X35. 升级查询页 · 方案 A（两栏工作台）规范化覆盖（2026-11-03）
   --------------------------------------------------------------------------
   页面重构为「统一头部卡片 + 左查询卡 / 右结果与我的车辆」，并全面黑白化：
   零边框、零阴影、圆角 R-C（卡片 14 / 控件 10 / 微 6 / 胶囊 999），
   去掉蓝（--brand/--grad）与绿（#1e7a46/#4cc47c），状态用实心反相 + 中性灰。
   本段以 `#app` 前缀压制 X31~X34 与 app.css 的旧彩色 / border / shadow 规则。
   ========================================================================== */

#app .ota-page { display: flex; flex-direction: column; gap: 16px; }

/* ---------- 头部卡片（同固件 / 反馈 / 协议页） ---------- */
#app .ota-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding: 16px 20px; border: 0; border-radius: var(--r-card);
  background: var(--paper); box-shadow: none;
}
#app .ota-head__kicker { display: block; color: var(--ink-3); font-size: var(--fs-meta); font-weight: 600; line-height: 1.4; letter-spacing: .08em; text-transform: uppercase; }
#app .ota-head h1 { margin: 4px 0 8px; color: var(--ink); font-size: 22px; font-weight: 700; line-height: 1.3; }
#app .ota-head__lead { margin: 0; max-width: 720px; color: var(--ink-2); font-size: var(--fs-body-sm); line-height: 1.65; }
#app .ota-head__stats { display: grid; grid-template-columns: repeat(3, 96px); gap: 8px; flex: none; }
#app .ota-stat {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  min-width: 0; min-height: 0; padding: 12px 16px;
  border: 0; border-radius: var(--r-ctl); background: var(--paper-2); box-shadow: none;
  text-align: center; transform: none; transition: none;
}
#app .ota-stat:hover { transform: none; box-shadow: none; }
#app .ota-stat b { color: var(--ink); font-size: 18px; font-weight: 600; line-height: 1.2; font-variant-numeric: tabular-nums; }
#app .ota-stat span { color: var(--ink-2); font-size: 12px; line-height: 1.4; }

/* ---------- 两栏 ---------- */
#app .ota-layout {
  display: grid; grid-template-columns: 400px minmax(0, 1fr);
  gap: 16px; align-items: start; margin-top: 0;
}
#app .ota-col { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
#app .ota-box { background: var(--paper); border: 0; border-radius: var(--r-card); padding: 16px; box-shadow: none; }
#app a.ota-box { display: flex; align-items: center; gap: 12px; color: var(--ink-2); text-decoration: none; }
#app .ota-box-h { display: flex; align-items: center; gap: 8px; margin: 0 0 12px; font-size: var(--fs-card-title); font-weight: 600; color: var(--ink); }
#app .ota-box-h::before { content: ""; flex: none; width: 4px; height: 14px; border-radius: 2px; background: var(--ink); }
#app .ota-box-h .n { margin-left: auto; color: var(--ink-3); font-size: 12px; font-weight: 400; }
#app .ota-box-lead { margin: 0 0 12px; color: var(--ink-2); font-size: var(--fs-caption); line-height: 1.65; }

/* ---------- 查询表单 ---------- */
#app .ota-field { display: block; margin-bottom: 12px; }
#app .ota-field:last-child { margin-bottom: 0; }
#app .ota-field-k { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; color: var(--ink); font-size: var(--fs-body-sm); font-weight: 600; }
#app .ota-field-k i { font-style: normal; font-size: var(--fs-meta); font-weight: 600; line-height: 1; padding: 3px 8px; border-radius: var(--r-pill); }
#app .ota-field-k i.req { background: var(--select-solid); color: var(--select-solid-ink); }
#app .ota-field-k i.opt { background: var(--paper-2); color: var(--ink-3); font-weight: 400; }
/* 品牌选择：规范页的「无槽 chips」（gap 6 / 项 28 高 / Control 圆角 / 底 --ctl-rest=transparent） */
#app .ota-chips { display: flex; gap: 6px; flex-wrap: wrap; padding: 0; border-radius: 0; background: transparent; }
#app .ota-chip {
  height: 28px; padding: 0 11px; border: 0; border-radius: var(--r-ctl);
  background: transparent; color: var(--ink-2);
  font: inherit; font-size: 12px; cursor: pointer; box-shadow: none; transform: none;
  transition: background .12s, color .12s;
}
#app .ota-chip:hover { background: var(--seg-hover); color: var(--ink); }
#app .ota-chip.active { background: var(--select-solid); color: var(--select-solid-ink); font-weight: 600; }
/* 次级按钮：默认透明，悬停才变底色（规范 09） */
#app .ota-picks { display: flex; gap: 8px; flex-wrap: wrap; }
#app .ota-pick {
  height: 32px; padding: 0 12px; border: 0; border-radius: var(--r-ctl);
  background: transparent; color: var(--ink-2);
  font: inherit; font-size: var(--fs-body-sm); font-weight: 600; cursor: pointer;
  transition: background .12s, color .12s;
}
#app .ota-pick:hover:not(:disabled) { background: var(--select-wash); color: var(--ink); }
#app .ota-pick:disabled { opacity: .45; cursor: not-allowed; }
#app .ota-hint { margin: 8px 0 0; color: var(--ink-3); font-size: 12px; line-height: 1.65; }
#app .ota-sel-row { margin: 0 0 8px; font-size: var(--fs-body-sm); font-weight: 600; color: var(--ink); }
/* VIN：默认灰面；有值白面 + 1.5px 内描边（规范 09，不用 border 描边） */
#app .ota-vin { margin-top: 0; background: var(--paper-2); }
#app .ota-vin .search-input { border: 0; border-radius: var(--r-ctl); box-shadow: none; background: transparent; }
#app .ota-vin.is-locked .search-input { color: var(--ink-3); cursor: not-allowed; }
#app .ota-vin.is-active, #app .ota-vin.is-done { background: var(--paper); box-shadow: inset 0 0 0 1.5px var(--select-solid); }
/* 卡片悬停只变文字色，不改底色（规范 09） */
#app .ota-fwlink:hover .ota-fwlink-tx small { color: var(--ink-2); }
#app .ota-fwlink-ico { display: grid; place-items: center; flex: none; width: 40px; height: 40px; border-radius: var(--r-ctl); background: var(--paper-2); color: var(--ink-2); }
#app .ota-fwlink-ico svg { width: 20px; height: 20px; }
#app .ota-fwlink-tx b { display: block; color: var(--ink); font-size: var(--fs-body-sm); font-weight: 600; }
#app .ota-fwlink-tx small { display: block; margin-top: 4px; color: var(--ink-3); font-size: var(--fs-meta); transition: color .12s; }

/* ---------- 结果卡 · 黑白 ---------- */
#app .ota-res { background: var(--paper); border: 0; border-radius: var(--r-card); padding: 16px; box-shadow: none; }
#app .ota-res-head { margin-bottom: 12px; }
#app .ota-res-name { font-size: var(--fs-card-title); }
#app .ota-res-cfg { font-size: var(--fs-body-sm); }
#app .ota-res-hero { border: 0; border-radius: var(--r-ctl); padding: 12px; background: var(--paper-2); margin-bottom: 12px; }
#app .ota-res--up .ota-res-hero, #app .ota-res--wait .ota-res-hero { background: var(--paper-2); border: 0; }
#app .ota-res-badge { height: 24px; padding: 0 10px; font-size: var(--fs-caption); border-radius: var(--r-pill); }
#app .ota-res--up .ota-res-badge { background: var(--select-solid); color: var(--select-solid-ink); }
#app .ota-res--wait .ota-res-badge { background: var(--paper-2); color: var(--ink-2); }
#app .ota-res-ver { color: var(--ink); font-size: 20px; }
#app .ota-res-line, #app .ota-res--wait .ota-res-line { color: var(--ink-2); font-weight: 500; font-size: var(--fs-body-sm); margin-top: 8px; }
#app .ota-res-desc { color: var(--ink-3); font-size: var(--fs-caption); line-height: 1.65; }
#app .ota-res-facts { gap: 8px; margin-top: 12px; }
#app .ota-res-fact { background: var(--paper-2); border-radius: var(--r-ctl); padding: 8px 12px; }
#app .ota-res-fact-k { font-size: 12px; }
#app .ota-res-fact-v { color: var(--ink); font-size: var(--fs-body-sm); }
#app .ota-same { background: var(--paper-2); border-radius: var(--r-ctl); margin-top: 12px; padding: 12px; }
#app .ota-same-head { margin-bottom: 8px; }
#app .ota-same-title { color: var(--ink); font-size: var(--fs-body-sm); }
#app .ota-same-note { font-size: var(--fs-meta); }
#app .ota-same-grid { gap: 8px; }
#app .ota-same-cell { background: var(--paper); border-radius: var(--r-ctl); padding: 8px; gap: 2px; }
#app .ota-same-ver { font-size: 12px; }
#app .ota-same-cars { font-size: var(--fs-meta); }
#app .ota-same-time { font-size: var(--fs-meta); }
#app .ota-same-cell.is-top { background: var(--select-wash); }
#app .ota-same-cell.is-top .ota-same-ver, #app .ota-same-cell.is-top .ota-same-time { color: var(--ink); }
#app .ota-same-cell.is-top .ota-same-cars { color: var(--ink-2); }
#app .ota-same-more { color: var(--ink); font-size: var(--fs-body-sm); }

/* ---------- 我的车辆 · 黑白 ---------- */
#app .gar-bar { background: var(--paper-2); border-radius: var(--r-card); padding: 12px 16px; }
#app .gar-bar-text { font-size: var(--fs-body-sm); }
#app .gar-bar-dot { background: var(--select-solid); }
#app .gar-bar[data-state="done"] .gar-bar-dot { background: var(--select-solid); }
#app .gar-steps { gap: 4px; margin-top: 12px; }
#app .gar-step { height: 4px; background: var(--rule); border-radius: var(--r-pill); }
#app .gar-step.is-on { background: var(--select-solid); }
#app .gar-bar-stats { gap: 8px; margin-top: 12px; }
#app .gar-stat { background: var(--paper); border-radius: var(--r-ctl); padding: 8px; gap: 2px; }
#app .gar-stat b { color: var(--ink); font-size: 18px; }
#app .gar-stat.is-up b { color: var(--ink); }
#app .gar-stat span { font-size: 12px; }
#app .gar-stat.is-time b { font-size: var(--fs-body); padding-top: 4px; }
#app .gar-tools-n { font-size: 12px; }
#app .gar-tools-all { border: 0; background: var(--paper-2); color: var(--ink-2); box-shadow: none; font-size: 12px; padding: 8px 16px; }
#app .gar-tools-all:hover { background: var(--select-wash); color: var(--ink); box-shadow: none; }
#app .gar-tools-all.is-on, #app .gar-tools-all.is-on:hover { background: var(--select-solid); color: var(--select-solid-ink); box-shadow: none; }
#app .gar-item { background: var(--paper-2); border: 0; border-radius: var(--r-ctl); box-shadow: none; padding: 12px; }
#app .gar-item:hover { box-shadow: none; background: var(--select-wash); }
#app .gar-item.is-open { background: var(--select-wash); }
#app .gar-item:focus-visible { outline: 1.5px solid var(--ink); outline-offset: 2px; }
#app .gar-ico { background: var(--paper); color: var(--ink-2); border-radius: var(--r-ctl); }
#app .gar-item.is-up .gar-ico, #app .gar-item.is-err .gar-ico { background: var(--paper); color: var(--ink); }
#app .gar-title { font-size: var(--fs-card-title); }
#app .gar-meta { font-size: 12px; gap: 12px; }
#app .gar-k { font-size: 12px; height: 20px; padding: 0 10px; }
#app .gar-k--up { background: var(--select-solid); color: var(--select-solid-ink); }
#app .gar-k--wait, #app .gar-k--err { background: var(--paper); color: var(--ink-2); }
#app .gar-brief { margin-top: 8px; }
#app .gar-ver { color: var(--ink); font-size: 20px; }
#app .gar-push { font-size: 12px; }
#app .gar-more { background: var(--paper); border-radius: var(--r-ctl); padding: 12px; }
#app .gar-note { font-size: var(--fs-caption); }
#app .gar-same-head { font-size: 12px; }
#app .gar-same-grid { gap: 8px; }
#app .gar-same-cell { padding: 8px 6px; }
#app .gar-same-ver { font-size: 12px; }
#app .gar-same-cars { font-size: var(--fs-meta); }
#app .gar-same-time { font-size: var(--fs-meta); }
#app .gar-act { border: 0; background: var(--paper-2); color: var(--ink-2); box-shadow: none; font-size: 12px; padding: 8px 16px; }
#app .gar-act:hover { background: var(--select-wash); color: var(--ink); box-shadow: none; }
#app .gar-act.is-on, #app .gar-act.is-on:hover { background: var(--select-solid); color: var(--select-solid-ink); box-shadow: none; }
#app .gar-fw-list { gap: 8px; }
#app .gar-fw-row { border: 0; background: var(--paper-2); border-radius: var(--r-ctl); padding: 8px 12px; }
#app .gar-fw-row:hover { transform: none; border-color: transparent; box-shadow: none; background: var(--select-wash); }
#app .gar-fw-ico { background: var(--paper); color: var(--ink-2); }
#app .gar-fw-name { font-size: 12px; }
#app .gar-fw-sub { font-size: var(--fs-meta); }
#app .gar-fw-size { font-size: 12px; }
#app .gar-fw-more { border: 0; background: var(--paper-2); color: var(--ink-2); border-radius: var(--r-ctl); font-size: 12px; }
#app .gar-fw-more:hover { color: var(--ink); background: var(--select-wash); }
#app .gar-empty-ico { background: var(--paper-2); color: var(--ink-3); border-radius: var(--r-card); }
#app .gar-empty-title { font-size: var(--fs-card-title); }
#app .gar-empty-desc { font-size: var(--fs-caption); }
#app .gar-recheck { background: var(--paper-2); color: var(--ink-2); box-shadow: none; font-size: var(--fs-body-sm); padding: 8px 16px; }
#app .gar-recheck:hover { color: var(--ink); background: var(--select-wash); box-shadow: none; }

/* ---------- 说明条 ---------- */
#app .ota-notes { margin-top: 0; padding: 12px 16px; border-radius: var(--r-card); background: var(--paper-2); }
#app .ota-page .btn, #app .ota-page .btn:hover { box-shadow: none; }

/* ---------- 移动端降级（断点 900，跟随底部 TAB） ---------- */
@media (max-width: 900px) {
  #app .ota-layout { grid-template-columns: minmax(0, 1fr); }
  #app .ota-head__stats { grid-template-columns: repeat(3, minmax(0, 1fr)); width: 100%; }
  #app .ota-head { gap: 16px; }
}

/* ==========================================================================
   X41 · 社区模块（2026-10-04）—— 主题化，替换 archive.css 的工业档案室样式
   ==========================================================================
   为什么单开一段而不是改 archive.css：
     archive.css 的 .comm-card / .comm-grid 是 1px 描边固格 + 直角方标签
     （.comm-cat 甚至是方形无圆角），与站内现行规范完全脱节。
     本段只新增 .cb-* 类，不删archive.css 里的旧类——
     首页「社区动态」区块仍在用 PLACEHOLDER_POSTS 与旧 cardHTML，
     两者并存互不干扰（旧类不受本段影响）。

   复用的站内基准（不新造）：
     .ota-hero    Hero（与固件页/OTA 页同款）
     .ota-stat    指标卡
     .dk-chip     胶囊筛选三态
     .dk-row      行式列表（hover 右移 2px）
     .arch-tag    徽章
   ====================================================================== */

/* ---------- Hero ---------- */
.cb-hero {
  text-align: center;
  margin-bottom: 22px;
}
.cb-hero-ico {
  display: grid; place-items: center;
  width: 60px; height: 60px;
  margin: 0 auto 16px;
  border-radius: var(--r-panel);
  background: var(--grad);
  color: #fff;
  box-shadow: 0 10px 28px rgba(17, 17, 17, .2);
}
.cb-hero-ico svg { width: 28px; height: 28px; }
.cb-hero h1 {
  font-size: 34px; font-weight: 800; letter-spacing: -.5px;
  margin: 0 0 12px; color: var(--ink);
}
.cb-hero > p {
  font-size: 15.5px; line-height: 1.75;
  color: var(--ink-2);
  max-width: 780px; margin: 0 auto;
  text-wrap: balance;
}
.cb-hero-tags {
  display: flex; justify-content: center; flex-wrap: wrap;
  gap: 8px; margin-top: 16px;
}
.cb-hero-tags:empty { display: none; }
.cb-hero-act { display: flex; justify-content: center; gap: 10px; margin-top: 18px; }

/* Hero 变体：帖子详情 / 发帖（顶部对齐、标题左对齐、无 60px 图标块） */
.cb-hero--post,
.cb-hero--edit { text-align: left; margin-bottom: 20px; }
.cb-hero--post .cb-post-title,
.cb-hero--edit h1 {
  font-size: 27px; font-weight: 800; line-height: 1.35;
  letter-spacing: -.3px;
  margin: 8px 0 10px;
}
.cb-hero--edit h1 { margin: 4px 0 8px; }
.cb-hero--post > p,
.cb-hero--edit > p {
  font-size: 13.5px; line-height: 1.7;
  color: var(--ink-2); margin: 0; max-width: none;
}
.cb-crumb { margin: 0; }
.cb-crumb a {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12.5px; color: var(--ink-3);
  text-decoration: none;
  transition: color .18s;
}
.cb-crumb a:hover { color: var(--brand); }
.cb-crumb svg {
  width: 13px; height: 13px;
  transform: rotate(90deg);   /* chevron 默认朝下，返回入口朝右更合语义 */
}
.cb-post-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.cb-post-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: 7px;
  font-size: 12.5px; color: var(--ink-3);
}
.cb-post-meta i, .cb-row-sub i, .cb-attach-sub i, .cb-row-num i {
  font-style: normal; opacity: .45;
}

/* ---------- 指标卡 ---------- */
.cb-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 22px;
}
.cb-stats .ota-stat { cursor: default; }
.cb-stats .ota-stat-link { cursor: pointer; }

/* ---------- 工具条：排序分段 + 搜索 ---------- */
.cb-bar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-bottom: 16px;
}
.cb-sortgroup {
  display: inline-flex; gap: 2px;
  background: var(--bg-gray);
  border-radius: 999px;
  padding: 3px;
}
.cb-sortbtn {
  border: 0; background: transparent;
  font-family: var(--font-body);
  font-size: 13px; font-weight: 500;
  color: var(--ink-3);
  padding: 9px 18px;
  border-radius: 999px;
  cursor: pointer;
  transition: background .2s, color .2s, box-shadow .2s;
}
.cb-sortbtn:hover { color: var(--ink); }
.cb-sortbtn.is-on {
  color: var(--ink);
  background: #fff;
  font-weight: 600;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .1);
}

.cb-search {
  position: relative;
  flex: 1; min-width: 200px;
  display: flex; align-items: center;
}
.cb-search > svg {
  position: absolute; left: 13px;
  width: 16px; height: 16px;
  color: var(--ink-3);
  pointer-events: none;
}
.cb-search input {
  width: 100%;
  padding: 10px 14px 10px 38px;
  border-radius: var(--r-card);
  border: 0;
  background: var(--gray-wash);
  font-family: var(--font-body);
  font-size: 13.5px;
  color: var(--ink);
  transition: border-color .15s, box-shadow .15s;
}
.cb-search input::placeholder { color: var(--ink-3); }
.cb-search input:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(17, 17, 17, .12);
}
.cb-search--hero { max-width: 420px; width: 100%; }

/* ---------- 主体两栏 ---------- */
.cb-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 264px;
  gap: 20px;
  align-items: start;
}
.cb-main { min-width: 0; }

/* ---------- 话题胶囊（复用 .dk-chip） ---------- */
.cb-chips {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-bottom: 14px;
}
.cb-chips .dk-chip { font-size: 13px; padding: 9px 16px; }
.cb-chips .dk-chip i {
  font-style: normal; font-size: 11px;
  opacity: .5; margin-left: 3px;
}

/* ---------- 帖子行（结构同 .dk-row） ---------- */
.cb-list { display: flex; flex-direction: column; gap: 7px; }
.cb-row {
  display: flex; align-items: center; gap: 14px;
  background: var(--paper);
  border: 0;
  border-radius: var(--r-card);
  padding: 13px 16px;
  min-width: 0;
  text-decoration: none;
  transition: transform .18s, box-shadow .18s, border-color .18s, background-color .18s;
}
.cb-row:hover {
  transform: translateX(2px);
  background: var(--paper-2);
  border-color: rgba(17, 17, 17, .28);
  box-shadow: 0 4px 12px rgba(17, 17, 17, .08);
}
.cb-row-ico {
  flex: none;
  display: grid; place-items: center;
  width: 40px; height: 40px;
  border-radius: var(--r-card);
  color: #fff;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .08);
}
.cb-row-ico svg { width: 21px; height: 21px; }
.cb-row-ico--feed{ background: var(--grad); }
.cb-row-ico--share { background: linear-gradient(135deg, #0e9aa7, #34c3cf); }
.cb-row-ico--tips  { background: linear-gradient(135deg, #7c5cf0, #a78bfa); }

.cb-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.cb-row-title {
  font-size: 14.5px; font-weight: 600; line-height: 1.45;
  color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cb-row:hover .cb-row-title { color: var(--accent); }
.cb-row-sub {
  display: flex; align-items: center; flex-wrap: wrap; gap: 7px;
  font-size: 12px; color: var(--ink-3);
}
.cb-row-end {
  flex: none;
  display: flex; flex-direction: column; align-items: flex-end; gap: 6px;
}
.cb-row-num {
  font-size: 12px; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.cb-row-num b { font-weight: 600; color: var(--ink-2); }

/* ---------- 徽章 ---------- */
.cb-tg { display: flex; flex-wrap: wrap; gap: 5px; justify-content: flex-end; }
.cb-cat {
  display: inline-flex; align-items: center;
  font-size: 11px; font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--r-micro);
  background: var(--brand-wash);
  color: var(--brand);
  white-space: nowrap;
}
.cb-badge {
  display: inline-flex; align-items: center;
  font-size: 11px; font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  white-space: nowrap;
}
.cb-badge--pin  { background: rgba(17, 17, 17, .1);  color: var(--brand); }
.cb-badge--gold { background: rgba(217, 132, 7, .13); color: #8a5a00; }
.cb-badge--ok   { background: rgba(31, 157, 85, .1);  color: #1e7a46; }
.cb-badge--mute { background: var(--paper-2);      color: var(--ink-3); }
.cb-badge--err  { background: rgba(220, 38, 38, .12); color: #b91c1c; }
.cb-extra { color: var(--ink-3); }

/* ---------- 帖子卡（share 瀑布流用） ---------- */
.cb-card {
  display: flex; flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-panel);
  overflow: hidden;
  text-decoration: none;
  transition: transform .2s, box-shadow .2s, border-color .2s;
}
.cb-card:hover {
  transform: translateY(-2px);
  border-color: rgba(17, 17, 17, .28);
  box-shadow: 0 8px 22px rgba(17, 17, 17, .1);
}
.cb-card-cover {
  display: block; height: 128px;
  background: var(--paper-2);
}
.cb-card-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cb-card-body {
  display: flex; flex-direction: column; gap: 7px;
  padding: 12px 14px 14px;
}
.cb-card-ex {
  font-size: 12.5px; line-height: 1.6; color: var(--ink-3);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.cb-card .cb-tg { justify-content: flex-start; }

/* ---------- 侧栏 ---------- */
.cb-side {
  position: sticky; top: 76px;
  display: flex; flex-direction: column; gap: 14px;
}
.cb-side-box {
  background: var(--paper);
  border: 0;
  border-radius: var(--r-panel);
  padding: 14px 15px;
}
.cb-side-t {
  margin: 0 0 11px;
  font-size: 12.5px; font-weight: 700;
  color: var(--ink);
  display: flex; align-items: center; gap: 6px;
}
.cb-side-t svg { width: 14px; height: 14px; color: var(--ink-3); }
.cb-side-empty { margin: 0; font-size: 12px; color: var(--ink-3); }

.cb-rank {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 0;
  text-decoration: none;
  color: var(--ink-2);
  font-size: 12.5px;
}
.cb-rank + .cb-rank { border-top: 0; margin-top: 2px; }
.cb-rank:hover .cb-rank-n { color: var(--brand); }
.cb-rank-no {
  flex: none;
  width: 18px; height: 18px;
  display: grid; place-items: center;
  border-radius: var(--r-micro);
  background: var(--paper-2);
  font-size: 10.5px; font-weight: 700;
  color: var(--ink-3);
}
.cb-rank-no.is-top { background: var(--grad); color: #fff; }
.cb-rank-ava {
  flex: none;
  width: 22px; height: 22px;
  border-radius: 50%;
  overflow: hidden;
  display: grid; place-items: center;
  background: var(--paper-2);
}
.cb-rank-ava img { width: 100%; height: 100%; object-fit: cover; }
.cb-rank-n { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cb-rank-c { flex: none; font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.cb-skeleton {
  height: 66px;
  border-radius: var(--r-card);
  background: var(--paper-2);
  animation: dkPulse 1.4s ease-in-out infinite;
}
.cb-smini {
  height: 88px;
  border-radius: var(--r-ctl);
  background: var(--paper-2);
  animation: dkPulse 1.4s ease-in-out infinite;
}
.cb-loading { display: flex; justify-content: center; padding: 18px 0; }
.cb-loadbtn {
  width: 100%;
  border: 0;
  background: none;
  padding: 14px 0;
  cursor: pointer;
}
.cb-loadbtn::after {
  content: '加载更多';
  display: inline-block;
  font-size: 12px;
  color: var(--ink-3);
  background: var(--bg-gray);
  border-radius: 999px;
  padding: 5px 16px;
  transition: color .2s, background .2s;
}
.cb-loadbtn:hover::after { color: var(--brand); background: var(--brand-wash); }
.cb-end {
  text-align: center;
  padding: 16px 0;
  font-size: 12px;
  color: var(--ink-3);
}
.cb-sentinel { height: 1px; }

/* ---------- 空态 ---------- */
.cb-empty { text-align: center; padding: 34px 16px; }
.cb-empty-ico {
  display: inline-grid; place-items: center;
  width: 52px; height: 52px;
  border-radius: var(--r-panel);
  background: var(--paper-2);
  color: var(--ink-3);
  margin-bottom: 12px;
}
.cb-empty-ico svg { width: 24px; height: 24px; }
.cb-empty-title { margin: 0 0 5px; font-size: 15px; font-weight: 600; color: var(--ink); }
.cb-empty-desc { margin: 0 0 14px; font-size: 12.5px; line-height: 1.6; color: var(--ink-3); }

/* ---------- 帖子详情：正文 ---------- */
.cb-body--post { grid-template-columns: minmax(0, 1fr) 264px; }
.cb-article {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--r-panel);
  padding: 20px 22px;
  margin-bottom: 14px;
}
.cb-content {
  font-size: 14.5px;
  line-height: 1.85;
  color: var(--ink);
  word-break: break-word;
}
.cb-imgs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 8px;
  margin-top: 16px;
}
.cb-imgs img {
  width: 100%;
  border-radius: var(--r-card);
  display: block;
  cursor: zoom-in;
}

/* ---------- 附件区（share） ---------- */
.cb-attach, .cb-steps {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--r-panel);
  padding: 16px 18px;
  margin-bottom: 14px;
}
.cb-sec-t {
  display: flex; align-items: center; gap: 7px;
  margin: 0 0 12px;
  font-size: 13.5px; font-weight: 700;
  color: var(--ink);
}
.cb-sec-t svg { width: 16px; height: 16px; color: var(--ink-3); }
.cb-sec-t span { font-weight: 400; font-size: 12px; color: var(--ink-3); }

.cb-attach-list { display: flex; flex-direction: column; gap: 7px; }
.cb-attach-row {
  display: flex; align-items: center; gap: 12px;
  border: 1px solid var(--rule-soft);
  border-radius: var(--r-card);
  padding: 10px 13px;
  transition: transform .18s, border-color .18s, box-shadow .18s;
}
.cb-attach-row:hover {
  transform: translateX(2px);
  border-color: rgba(17, 17, 17, .28);
  box-shadow: 0 4px 12px rgba(17, 17, 17, .08);
}
.cb-attach-ico {
  flex: none;
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border-radius: var(--r-ctl);
  background: linear-gradient(135deg, #7c8b9e, #9aa8b8);
  color: #fff;
}
.cb-attach-ico svg { width: 18px; height: 18px; }
.cb-attach-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cb-attach-name {
  font-family: var(--font-num, var(--font-mono));
  font-size: 12.5px; font-weight: 600; line-height: 1.35;
  color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cb-attach-sub {
  display: flex; align-items: center; flex-wrap: wrap; gap: 7px;
  font-size: 11px; color: var(--ink-3);
}
.cb-attach-dl {
  flex: none;
  font-size: 12px; font-weight: 600;
  color: var(--brand);
  text-decoration: none;
  background: var(--brand-wash);
  border-radius: 999px;
  padding: 6px 14px;
  transition: background .2s, color .2s;
}
.cb-attach-dl:hover { background: var(--brand); color: #fff; }
.cb-attach-na { flex: none; font-size: 11.5px; color: var(--ink-3); }
.cb-attach-note {
  display: flex; align-items: flex-start; gap: 6px;
  margin: 11px 0 0;
  padding: 9px 11px;
  border-radius: var(--r-ctl);
  background: rgba(217, 132, 7, .09);
  font-size: 11.5px; line-height: 1.6;
  color: #8a5a00;
}
.cb-attach-note svg { width: 14px; height: 14px; flex: none; margin-top: 2px; }

/* ---------- 步骤区（tips） ---------- */
.cb-steps-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.cb-step { display: flex; gap: 11px; }
.cb-step-no {
  flex: none;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: var(--r-ctl);
  background: var(--grad);
  color: #fff;
  font-size: 11.5px; font-weight: 700;
}
.cb-step-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.cb-step-title { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.cb-step-detail { font-size: 12.5px; line-height: 1.65; color: var(--ink-3); }

/* ---------- 互动条 ---------- */
.cb-acts {
  display: flex; gap: 8px; flex-wrap: wrap;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--r-panel);
  padding: 12px 14px;
  margin-bottom: 14px;
}
.cb-act {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--rule-2);
  background: var(--paper);
  color: var(--ink-2);
  font-family: var(--font-body);
  font-size: 12.5px; font-weight: 600;
  padding: 9px 16px;
  border-radius: 999px;
  cursor: pointer;
  transition: color .2s, background .2s, border-color .2s, box-shadow .2s;
}
.cb-act svg { width: 15px; height: 15px; }
.cb-act b { font-weight: 600; font-variant-numeric: tabular-nums; }
.cb-act span { font-weight: 400; color: var(--ink-3); font-size: 11.5px; }
.cb-act:hover {
  color: var(--brand);
  background: var(--brand-wash);
  border-color: transparent;
  box-shadow: 0 2px 8px rgba(17, 17, 17, .12);
}
.cb-act.is-on {
  color: #fff;
  background: var(--grad);
  border-color: transparent;
  box-shadow: 0 2px 8px rgba(17, 17, 17, .24);
}
.cb-act.is-on span { color: rgba(255, 255, 255, .85); }

/* ---------- 评论区 ---------- */
.cb-comments {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--r-panel);
  padding: 16px 18px;
}
.cb-cmt-editor { margin-bottom: 16px; }
.cb-cmt-editor textarea {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--rule-2);
  border-radius: var(--r-card);
  padding: 11px 14px;
  font-family: var(--font-body);
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--ink);
  resize: vertical;
  transition: border-color .15s, box-shadow .15s;
}
.cb-cmt-editor textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(17, 17, 17, .12);
}
.cb-cmt-bar {
  display: flex; align-items: center; gap: 10px;
  margin-top: 9px;
}
.cb-cmt-tip { flex: 1; font-size: 11.5px; color: var(--ink-3); }
.cb-cmt-login {
  display: flex; align-items: center; gap: 12px;
  padding: 14px;
  border-radius: var(--r-card);
  background: var(--paper-2);
}
.cb-cmt-login p { flex: 1; margin: 0; font-size: 13px; color: var(--ink-2); }

.cb-cmt-list { display: flex; flex-direction: column; gap: 14px; }
.cb-cmt { display: flex; gap: 11px; }
.cb-cmt--reply {
  margin-left: 34px;
  padding-left: 12px;
  border-left: 2px solid var(--rule);
}
.cb-cmt-ava {
  flex: none;
  width: 32px; height: 32px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--paper-2);
}
.cb-cmt-ava img { width: 100%; height: 100%; object-fit: cover; }
.cb-cmt-body { flex: 1; min-width: 0; }
.cb-cmt-head { display: flex; align-items: center; flex-wrap: wrap; gap: 7px; margin-bottom: 3px; }
.cb-cmt-n { font-size: 13px; font-weight: 600; color: var(--ink); }
.cb-cmt-badge {
  font-size: 10.5px; font-weight: 600;
  padding: 1px 6px;
  border-radius: var(--r-micro);
  background: var(--brand-wash);
  color: var(--brand);
}
.cb-cmt-badge--mute { background: var(--paper-2); color: var(--ink-3); }
.cb-cmt-t { font-size: 11.5px; color: var(--ink-3); }
.cb-cmt-c {
  margin: 0 0 5px;
  font-size: 13.5px; line-height: 1.75;
  color: var(--ink-2);
  word-break: break-word;
}
.cb-cmt-x { margin: 0 0 5px; font-size: 12.5px; color: var(--ink-3); font-style: italic; }
.cb-cmt-acts { display: flex; gap: 12px; flex-wrap: wrap; }
.cb-cmt-act {
  display: inline-flex; align-items: center; gap: 4px;
  border: 0; background: none;
  padding: 0;
  font-family: var(--font-body);
  font-size: 11.5px;
  color: var(--ink-3);
  cursor: pointer;
  transition: color .18s;
}
.cb-cmt-act svg { width: 13px; height: 13px; }
.cb-cmt-act:hover { color: var(--brand); }
.cb-cmt-act.is-on { color: #c62828; font-weight: 600; }

/* ---------- 详情页侧栏 ---------- */
.cb-author { display: flex; align-items: center; gap: 10px; }
.cb-author-ava {
  flex: none;
  width: 44px; height: 44px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--paper-2);
}
.cb-author-ava img { width: 100%; height: 100%; object-fit: cover; }
.cb-author-id { flex: 1; min-width: 0; }
.cb-author-n {
  margin: 0; font-size: 13.5px; font-weight: 600; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cb-author-s { margin: 2px 0 0; font-size: 11.5px; color: var(--ink-3); }
.cb-followbtn {
  flex: none;
  border: 1px solid var(--rule-2);
  background: var(--paper);
  color: var(--ink-2);
  font-family: var(--font-body);
  font-size: 12px; font-weight: 600;
  padding: 7px 13px;
  border-radius: 999px;
  cursor: pointer;
  transition: color .2s, background .2s, border-color .2s;
}
.cb-followbtn:hover { color: var(--brand); background: var(--brand-wash); border-color: transparent; }
.cb-followbtn.is-on { color: #fff; background: var(--grad); border-color: transparent; }
.cb-topic-tags { display: flex; flex-wrap: wrap; gap: 7px; }
.cb-topic-tags .dk-chip { font-size: 12px; padding: 7px 13px; }

/* ---------- 话题广场 ---------- */
.cb-panel {
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--r-panel);
  padding: 22px;
  margin-top: 20px;
}
.cb-topic-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
}
.cb-topiccard {
  display: flex; flex-direction: column; gap: 8px;
  background: var(--paper);
  border: 1px solid var(--rule-soft);
  border-radius: var(--r-panel);
  padding: 15px 16px;
  text-decoration: none;
  transition: transform .2s, box-shadow .2s, border-color .2s;
}
.cb-topiccard:hover {
  transform: translateY(-2px);
  border-color: rgba(17, 17, 17, .28);
  box-shadow: 0 8px 22px rgba(17, 17, 17, .1);
}
.cb-topiccard-hd { display: flex; align-items: center; gap: 8px; }
.cb-topiccard-n {
  flex: 1; min-width: 0;
  font-size: 15px; font-weight: 600; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cb-topiccard-f {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11.5px; color: var(--ink-3);
}
.cb-topiccard-f svg { width: 13px; height: 13px; }
.cb-topiccard-x {
  font-size: 12.5px; line-height: 1.6; color: var(--ink-3);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 40px;
}
.cb-topiccard-go {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 12px; font-weight: 600; color: var(--brand);
}
.cb-topiccard-go svg { width: 12px; height: 12px; transform: rotate(-90deg); }

/* ---------- 发帖 / 编辑 ---------- */
.cb-form { display: flex; flex-direction: column; gap: 18px; }
.cb-field { position: relative; }
.cb-label {
  display: flex; align-items: center; gap: 6px;
  margin-bottom: 7px;
  font-size: 13px; font-weight: 600;
  color: var(--ink);
}
.cb-label svg { width: 14px; height: 14px; color: var(--ink-3); }
.cb-label span {
  font-size: 10.5px; font-weight: 600;
  padding: 1px 6px;
  border-radius: var(--r-micro);
  background: var(--brand-wash);
  color: var(--brand);
}
.cb-label span.is-opt { background: var(--paper-2); color: var(--ink-3); }
.cb-field input[type="text"],
.cb-field textarea {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid var(--rule-2);
  border-radius: var(--r-card);
  padding: 10px 14px;
  font-family: var(--font-body);
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--ink);
  transition: border-color .15s, box-shadow .15s;
}
.cb-field textarea { resize: vertical; }
.cb-field input:focus,
.cb-field textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px rgba(17, 17, 17, .12);
}
.cb-hint { margin: 6px 0 0; font-size: 11.5px; color: var(--ink-3); }
.cb-hint span { font-variant-numeric: tabular-nums; }

.cb-cats { display: flex; flex-wrap: wrap; gap: 8px; }
.cb-catbtn {
  border: 1px solid var(--rule-2);
  background: var(--paper);
  color: var(--ink-2);
  font-family: var(--font-body);
  font-size: 12.5px; font-weight: 600;
  padding: 8px 15px;
  border-radius: 999px;
  cursor: pointer;
  transition: color .2s, background .2s, border-color .2s;
}
.cb-catbtn:hover { color: var(--brand); background: var(--brand-wash); border-color: transparent; }
.cb-catbtn.is-on { color: #fff; background: var(--grad); border-color: transparent; }

.cb-addbtn {
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: 9px;
  border: 1px dashed var(--rule-2);
  background: none;
  color: var(--ink-3);
  font-family: var(--font-body);
  font-size: 12.5px; font-weight: 600;
  padding: 8px 14px;
  border-radius: var(--r-ctl);
  cursor: pointer;
  transition: color .2s, border-color .2s, background .2s;
}
.cb-addbtn svg { width: 14px; height: 14px; }
.cb-addbtn:hover { color: var(--brand); border-color: var(--brand); background: var(--brand-wash); }

.cb-attach-edit, .cb-steps-edit { display: flex; flex-direction: column; gap: 8px; }
.cb-atte-row, .cb-ste-row { display: flex; align-items: center; gap: 8px; }
.cb-atte-row input, .cb-ste-row input {
  flex: 1; min-width: 0;
  border: 1px solid var(--rule-2);
  border-radius: var(--r-ctl);
  padding: 8px 11px;
  font-family: var(--font-body);
  font-size: 12.5px;
  color: var(--ink);
}
.cb-atte-row input:focus, .cb-ste-row input:focus {
  outline: none; border-color: var(--brand);
}
.cb-ste-no {
  flex: none;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: var(--r-ctl);
  background: var(--grad);
  color: #fff;
  font-size: 11.5px; font-weight: 700;
}
.cb-delbtn {
  flex: none;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border: 1px solid var(--rule-2);
  background: var(--paper);
  color: var(--ink-3);
  border-radius: var(--r-ctl);
  cursor: pointer;
  transition: color .2s, background .2s, border-color .2s;
}
.cb-delbtn svg { width: 15px; height: 15px; }
.cb-delbtn:hover { color: #b91c1c; background: rgba(220, 38, 38, .1); border-color: transparent; }

.cb-topic-pick { display: flex; flex-wrap: wrap; gap: 8px; }
.cb-topic-pick .dk-chip { font-size: 12.5px; padding: 8px 14px; }

.cb-imgs-edit { display: flex; flex-wrap: wrap; gap: 8px; }
.cb-imgs-edit:empty::after {
  content: '暂无图片';
  font-size: 12px;
  color: var(--ink-3);
}
.cb-imge {
  position: relative;
  width: 78px; height: 78px;
  border-radius: var(--r-card);
  overflow: hidden;
  border: 1px solid var(--rule);
}
.cb-imge img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cb-imge-x {
  position: absolute; top: 3px; right: 3px;
  width: 20px; height: 20px;
  display: grid; place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, .55);
  color: #fff;
  cursor: pointer;
}
.cb-imge-x svg { width: 11px; height: 11px; }
.cb-imge-add {
  width: 78px; height: 78px;
  display: grid; place-items: center;
  border: 1px dashed var(--rule-2);
  background: none;
  color: var(--ink-3);
  border-radius: var(--r-card);
  cursor: pointer;
  transition: color .2s, border-color .2s;
}
.cb-imge-add svg { width: 20px; height: 20px; }
.cb-imge-add:hover { color: var(--brand); border-color: var(--brand); }

.cb-form-act {
  display: flex; justify-content: flex-end; gap: 10px;
  padding-top: 6px;
  border-top: 1px solid var(--rule);
  margin-top: 4px;
  padding-top: 16px;
}

/* ---------- 深色模式 ---------- */
[data-theme="dark"] .cb-row:hover,
[data-theme="dark"] .cb-card:hover,
[data-theme="dark"] .cb-attach-row:hover { background: rgba(255, 255, 255, .04); }
[data-theme="dark"] .cb-row-ico--feed { background: linear-gradient(135deg, #1f6feb, #4a9bff); }
[data-theme="dark"] .cb-skeleton, [data-theme="dark"] .cb-smini { background: rgba(255, 255, 255, .05); }
[data-theme="dark"] .cb-sortbtn.is-on { background: rgba(255, 255, 255, .12); color: #fff; }
[data-theme="dark"] .cb-rank-no.is-top { background: var(--grad); }
[data-theme="dark"] .cb-cat { background: rgba(245, 245, 245, .12); color: var(--ink-2); }
[data-theme="dark"] .cb-badge--gold { background: rgba(217, 132, 7, .18); color: #e0a94a; }
[data-theme="dark"] .cb-badge--ok { background: rgba(31, 157, 85, .16); color: #4cc47c; }
[data-theme="dark"] .cb-badge--mute { background: rgba(255, 255, 255, .07); }
[data-theme="dark"] .cb-attach-note { background: rgba(217, 132, 7, .14); color: #e0a94a; }
[data-theme="dark"] .cb-cmt--reply { border-left-color: rgba(255, 255, 255, .12); }
[data-theme="dark"] .cb-cmt-login { background: rgba(255, 255, 255, .05); }
[data-theme="dark"] .cb-loadbtn::after { background: rgba(255, 255, 255, .07); }

/* ---------- 移动端（断点 900px，与全站一致） ---------- */
@media (max-width: 900px) {
  /* Hero 缩放（对齐 OTA 页 900px 档） */
  .cb-hero { margin-bottom: 18px; }
  .cb-hero-ico { width: 52px; height: 52px; border-radius: var(--r-panel); margin-bottom: 13px; }
  .cb-hero-ico svg { width: 25px; height: 25px; }
  .cb-hero h1 { font-size: 25px; }
  .cb-hero > p { font-size: 13.5px; }
  .cb-hero--post .cb-post-title, .cb-hero--edit h1 { font-size: 21px; }
  .cb-hero--edit > p, .cb-hero--post > p { font-size: 12.5px; }
  .cb-hero-act { margin-top: 14px; }

  /* 指标卡 2 列会太挤，这里保持 3 列但压缩（对齐 .ota-stat 的 900px 档） */
  .cb-stats { gap: 8px; margin-bottom: 18px; }
  .cb-stats .ota-stat { min-height: 68px; padding: 11px 6px; border-radius: var(--r-panel); }
  .cb-stats .ota-stat-num { font-size: 20px; }
  .cb-stats .ota-stat-label { font-size: 11px; }

  /* 工具条：搜索独占一行 */
  .cb-bar { gap: 10px; }
  .cb-sortgroup { width: 100%; }
  .cb-sortbtn { flex: 1; padding: 9px 10px; }
  .cb-search { flex: 1 0 100%; }

  /* 单栏：侧栏移到主列表之后 */
  .cb-body, .cb-body--post { grid-template-columns: 1fr; }
  .cb-side { position: static; flex-direction: row; flex-wrap: wrap; }
  .cb-side-box { flex: 1 1 240px; }
  .cb-sentinel { display: none; }

  /* 帖子行改两行式（对齐 .dk-row 的 700px 档） */
  .cb-row { flex-wrap: wrap; padding: 12px 14px; gap: 10px; }
  .cb-row-ico { width: 34px; height: 34px; border-radius: var(--r-ctl); }
  .cb-row-ico svg { width: 18px; height: 18px; }
  .cb-row-main { order: 2; flex: 1 1 100%; }
  .cb-row-ico { order: 1; }
  .cb-row-end { order: 3; flex: 1 1 100%; flex-direction: row; justify-content: space-between; align-items: center; }
  .cb-row-title { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .cb-row:hover { transform: none; }

  .cb-article { padding: 16px 15px; border-radius: var(--r-card); }
  .cb-content { font-size: 14px; line-height: 1.8; }
  .cb-imgs { grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); }
  .cb-attach, .cb-steps, .cb-comments { padding: 14px 15px; border-radius: var(--r-card); }
  .cb-attach-row { padding: 9px 11px; }
  .cb-cmt--reply { margin-left: 18px; }
  .cb-act { padding: 8px 14px; }
  .cb-act span { display: none; }        /* 窄屏只留图标 + 数字 */
  .cb-panel { padding: 16px 14px; border-radius: var(--r-panel); }
  .cb-topic-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 10px; }
  .cb-atte-row, .cb-ste-row { flex-wrap: wrap; }
  .cb-atte-row input, .cb-ste-row input { flex: 1 1 100%; }
  .cb-delbtn { margin-left: auto; }
  .cb-form-act { position: sticky; bottom: 0; background: var(--paper); padding: 12px 0; }
}

/* ==========================================================================
   X42 · 提示条（toast）—— 方案 D：深色玻璃悬浮胶囊
   ==========================================================================
   选型理由：与站内顶栏 #masthead / 底部 TAB 的毛玻璃体系同源，
   视觉重量最轻、不打断阅读，且深色胶囊在浅色页面上对比度最高。

   ⚠️ 与旧版的差异（旧版是「实底色块 + 白字 + 16px线性图标」）：
     ① 删掉 --success / --danger / --warning 实底 —— 站内没有任何地方用实底警示色，
        实底红在纯色背景上过于刺眼，与「浅底+深字」的标签体系完全反着来。
     ② 16px 线性图标 → 6px 状态色点（同公告关闭按钮/ 徽章的语言）。
     ③ 固定 2600ms → 按字数动态 2200~5200ms（长文案原来读不完）。
     ④ 固定 top:70px 居中 → 右下角堆叠（不遮顶栏、不遮正文）。
   ====================================================================== */
.toast {
  position: fixed;
  right: 18px;
  /* ⚠️ 必须显式清掉 app.css 的 `top: 70px` ——
     否则 top 与 bottom 同时生效，元素会被拉成整屏高的一条带子。 */
  top: auto;
  bottom: 18px;
  left: auto;
  z-index: 300;
  display: flex;
  align-items: center;
  gap: 9px;
  max-width: min(420px, calc(100vw - 36px));
  padding: 11px 12px 11px 15px;
  border-radius: 999px;
  color: #fff;
  background: rgba(22, 25, 31, .82);
  border: 1px solid rgba(255, 255, 255, .14);
  backdrop-filter: saturate(160%) blur(18px);
  -webkit-backdrop-filter: saturate(160%) blur(18px);
  box-shadow: 0 8px 28px rgba(16, 24, 40, .22);
  font-size: 13px;
  line-height: 1.45;
  /* 入场：从右下淡入 + 上浮；出场反向。bottom 参与过渡 → 多条堆叠时升降是平滑的 */
  opacity: 0;
  transform: translateY(10px) scale(.97);
  transition: opacity .26s ease, transform .26s cubic-bezier(.22, 1, .36, 1), bottom .26s ease;
  pointer-events: auto;
}
.toast.is-in { opacity: 1; transform: none; }
.toast.is-out { opacity: 0; transform: translateY(6px) scale(.98); }

/* 多条同时出现时向上堆叠：JS 每次增删都会给存活项重排 --toast-i（0 = 最下）。
   没有这一步的话多条toast 会完全重叠在同一位置（实测三张都在同一坐标）。 */
.toast {
  bottom: calc(18px + var(--toast-i, 0) * 62px);
}

/* 状态色点 */
.toast-dot {
  flex: none;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: #9aa4b2;
  box-shadow: 0 0 0 3px rgba(154, 164, 178, .2);
}
.toast--success .toast-dot { background: #4ade80; box-shadow: 0 0 0 3px rgba(74, 222, 128, .22); }
.toast--error   .toast-dot { background: #f87171; box-shadow: 0 0 0 3px rgba(248, 113, 113, .22); }
.toast--warning .toast-dot { background: #fbbf24; box-shadow: 0 0 0 3px rgba(251, 191, 36, .22); }
.toast--info    .toast-dot { background: #cfcfcf; box-shadow: 0 0 0 3px rgba(96, 165, 250, .22); }

/* 文案：允许内部换行但不撑破胶囊 */
.toast-tx {
  flex: 1;
  min-width: 0;
  word-break: break-word;
  overflow-wrap: anywhere;
  /* 超过 3 行截断，避免长提示变成一大块 */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 关闭按钮：与公告关闭按钮同族（22px 圆底，触屏热区 36px） */
.toast-x {
  flex: none;
  position: relative;
  width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, .12);
  color: rgba(255, 255, 255, .78);
  cursor: pointer;
  transition: background .18s, color .18s;
}
.toast-x::before {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  width: 36px; height: 36px;    /* 扩大触屏热区到 36px */
  transform: translate(-50%, -50%);
}
.toast-x:hover { background: rgba(255, 255, 255, .24); color: #fff; }
.toast-x svg { width: 12px; height: 12px; }

/* ---------- 浅色页面下的深色胶囊微调 ---------- */
/* 深色胶囊在深色主题里会和背景糊成一片 → 加边框 + 提高不透明度 */
[data-theme="dark"] .toast {
  background: rgba(38, 42, 50, .92);
  border-color: rgba(255, 255, 255, .16);
}

/* ---------- 移动端：底部通栏（贴近拇指区，且让位给 TAB） ---------- */
@media (max-width: 900px) {
  .toast {
    right: 12px;
    left: 12px;
    top: auto;
    bottom: calc(84px + env(safe-area-inset-bottom, 0px) + var(--toast-i, 0) * 60px);
    max-width: none;
    border-radius: var(--r-panel);      /* 通栏时胶囊圆角会显得怪，改成16px */
    padding: 12px 12px 12px 15px;
    font-size: 13px;
  }
}

/* ---------- 尊重「减少动态效果」 ---------- */
@media (prefers-reduced-motion: reduce) {
  .toast { transition: opacity .2s linear; transform: none !important; }
  .toast.is-in { transform: none !important; }
}

/* ---------- 旧版残留清理 ---------- */
/* app.css 的 .toast.success/.error/.warning/.info 是实底色，
   必须显式覆盖掉，否则会从下面透出来（深色胶囊 + 实底 = 脏色）。 */
.toast.success, .toast.error, .toast.warning, .toast.info {
  background: rgba(22, 25, 31, .82);
  color: #fff;
}
[data-theme="dark"] .toast.success,
[data-theme="dark"] .toast.error,
[data-theme="dark"] .toast.warning,
[data-theme="dark"] .toast.info { background: rgba(38, 42, 50, .92); }

/* ==========================================================================
   X43 · 弹窗（.modal）—— 方案 D：PC 居中 + 移动端底部抽屉（同套 DOM）
   ==========================================================================
   选型理由：站内移动端已确立「底部悬浮白卡 + 毛玻璃」的视觉语言（底部 TAB），
   弹窗从底部升起与手势习惯一致；PC 端仍保持居中对话框不变。
   同一套 DOM，纯 CSS 切换，无需 JS 分支。

   改掉的旧样式（三处历史遗留）：
     ① .modal-close 是**裸 × 字符**（archive.css:413 font-size:20px; border-radius:0）
        → 改成 28px 圆底图标按钮（同公告关闭按钮族）
     ② .modal-row .btn 强制 border-radius:0（archive.css:415）
        → 恢复胶囊（--r-btn: 999px），与全站按钮统一
     ③ 遮罩只有 blur(4px)，无冷调 → 补上站内毛玻璃参数
   ====================================================================== */

/* ---------- 遮罩：冷调 + 强模糊（与顶栏/TAB 同源） ---------- */
.modal-mask {
  background: rgba(16, 22, 32, .42);
  backdrop-filter: saturate(160%) blur(20px);
  -webkit-backdrop-filter: saturate(160%) blur(20px);
}

/* ---------- 弹窗容器 ---------- */
.modal {
  border-radius: var(--r-panel);
  box-shadow: 0 24px 64px rgba(16, 24, 40, .28);
  /* 移动端抽屉需要底部贴边，PC 端保持居中（默认） */
  position: relative;
}

/* ---------- 关闭按钮：裸× → 圆底图标按钮 ---------- */
/*⚠️ 现状是 **裸 × 字符**（app.js:441 等 5 处`<button class="modal-close">×</button>`），
   不是 svg。所以这里**不能用 font-size:0 + svg 尺寸**（那样 × 会直接消失），
   改用 ::after 画两条线（旋转 45°），并把字符本身用 font-size:0 藏掉。 */
.modal-close {
  position: absolute;
  top: 14px; right: 14px;
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--paper-2);
  color: var(--ink-3);
  font-size: 0;                 /* 藏掉裸 × 字符，改由 ::after 画 */
  line-height: 1;
  cursor: pointer;
  transition: background .2s, color .2s, box-shadow .2s;
  z-index: 2;
}
.modal-close::after {
  content: "";
  width: 11px; height: 11px;
  transform: rotate(45deg);      /* 两条正交线转45° 才是「×」而不是「＋」 */
  background:
    linear-gradient(to right, currentColor 0 100%) center / 100% 1.6px no-repeat,
    linear-gradient(to bottom, currentColor 0 100%) center / 1.6px 100% no-repeat;
}
.modal-close:hover {
  background: var(--brand-wash);
  color: var(--brand);
  box-shadow: 0 2px 8px rgba(17, 17, 17, .12);
}

/* ---------- 底部按钮：直角 → 胶囊 ---------- */
.modal-row .btn,
.modal-row .btn.auth-half {
  border-radius: var(--r-btn);
}

/* ---------- 标题层级：站内统一左对齐 ---------- */
/* ⚠️ archive.css:1385 的 .auth-title 用了 `justify-content: center`（居中），
   与站内 .ota-panel / .dk-nav 的左对齐体系不一致 → 这里改回左对齐。 */
.auth-title {
  display: flex; align-items: center; justify-content: flex-start; width: 100%;
  font-family: var(--font-body);
  font-size: 18px;
  letter-spacing: -.2px;
}
/* 弹窗通用标题（.modal h3 已在上面统一，这里补居中元素的复位） */
.modal h3 {
  font-family: var(--font-body);
  font-size: 17px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -.2px;
}
.modal-desc { color: var(--ink-2); font-size: 13px; line-height: 1.65; }

/* ---------- 移动端：底部抽屉（同套 DOM，纯 CSS 切换） ---------- */
@media (max-width: 900px) {
  .modal-mask {
    align-items: flex-end;
    padding: 0;
  }
  .modal {
    width: 100%;
    max-width: 100%;
    margin: 0;
    border-radius: var(--r-panel) 24px 0 0;
    padding-bottom: calc(20px + env(safe-area-inset-bottom, 0px));
    max-height: 86vh;
    overflow-y: auto;
    animation: modalSheet .28s cubic-bezier(.22, 1, .36, 1) both;
  }
  @keyframes modalSheet {
    from { transform: translateY(100%); opacity: .6; }
    to   { transform: none; opacity: 1; }
  }
  /* 抽屉顶部的拖拽指示条（纯装饰，用 ::before 画） */
  .modal::before {
    content: "";
    display: block;
    width: 34px; height: 4px;
    margin: 10px auto 4px;
    border-radius: 999px;
    background: var(--rule-2);
  }
  .modal-close { top: 18px; right: 14px; }
  /* 抽屉里的主按钮要够大，落在拇指区 */
  .modal-row { position: sticky; bottom: 0; padding-top: 12px; background: var(--paper); }
  .modal-row .btn { padding: 12px 22px; font-size: 14px; }
}

/* ==========================================================================
   认证整页（#/login）—— 方案 E 整页路由 + B 版品牌化光晕头部
   --------------------------------------------------------------------------
   为什么做成整页而不是弹窗：
   注册原本 7 个字段挤在弹窗里要滚动；找回密码/账号是「独立任务」，
   弹窗一关就丢上下文。整页可分步、可前进后退、移动端不崩。
   ========================================================================== */
/* 整页容器：居中 + 光晕背景（与首页/登录引导页同源语言）
   高度预留：顶栏(64) + #app 上下 padding + 底部 TAB(76)，
   让认证卡片在一屏内居中且不被顶栏/TAB 压住。 */
.authpage {
  position: relative; isolation: isolate;
  min-height: calc(100vh - 300px);
  display: flex; align-items: center; justify-content: center;
  padding: 30px 20px 40px;
  /* 通栏破格：与 .home / .login-gate 同款技巧，横向铺满整屏。
     不能加 overflow:hidden —— 那会把模糊的光晕裁成矩形，出现直角硬边。 */
  margin: -22px -16px 0;
}

/* 2026-10-04 背景重写：旧 .glow-bleed 出血裁剪层已随 .glow 体系一并删除。
   认证页背景改由全局流动光场 .bgflow（fixed 全视口、见文件末尾 X195 段）承担，
   出血/裁剪/底栏露白等问题在该方案下天然不存在。 */

/* 卡片：白底 + 圆角 + 柔影，浮在光晕之上 */
.authpage__card {
  position: relative; z-index: 1;
  width: 100%; max-width: 430px;
  background: rgba(255,255,255,.94);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border: 0; border-radius: var(--r-panel);
  box-shadow: 0 20px 50px rgba(17,17,17,.10);
  padding: 30px 32px 28px;
  animation: apCardIn .34s cubic-bezier(.2,.9,.3,1);
}
@keyframes apCardIn { from{opacity:0; transform:translateY(14px) scale(.98)} to{opacity:1; transform:none} }

/* 头部：图标 + 标题 + 副标题，居中
   图标用站点线性 SVG（icons.js 的 lock/user/key/search/shield/check），
   与全站图标语言一致；不要用 emoji —— 字形风格与线性描边不搭。 */
.authpage__hd { text-align: center; margin-bottom: 20px; }
.authpage__icon {
  width: 54px; height: 54px; margin: 0 auto 13px; border-radius: 17px;
  background: linear-gradient(135deg,#111111,#4a6cf0);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 9px 22px rgba(17,17,17,.34), inset 0 1px 0 rgba(255,255,255,.3);
}
.authpage__icon .icon {
  width: 26px; height: 26px;      /* SVG 用 width/height 控制尺寸 */
  stroke-width: 1.9;               /* 略加粗，24px 下更清晰 */
  color: #fff;
}
.authpage__title { margin: 0 0 6px; font-size: 20px; font-weight: 800; letter-spacing: .3px; color: var(--ink, #1b2438); }
.authpage__sub { margin: 0; font-size: 13px; color: var(--ink-2); line-height: 1.6; }

/* 登录/注册 Tab 胶囊 */
.authtabs { display: flex; gap: 4px; background: var(--gray-wash); border-radius: 999px; padding: 4px; margin-bottom: 22px; }
.authtabs__item {
  flex: 1; text-align: center; padding: 8px 0; border-radius: 999px;
  font-size: 13.5px; font-weight: 600; color: var(--ink-2); text-decoration: none;
  transition: background .18s, color .18s, box-shadow .18s;
}
.authtabs__item.is-on { background: var(--select-solid); color: var(--select-solid-ink); box-shadow: none; }

/* 表单区 */
.authpage__body .form-row { margin-bottom: 15px; }
.authpage__body .form-row label { display: block; font-size: 13px; color: var(--ink-2); margin-bottom: 6px; font-weight: 600; }
.authpage__body .form-row input, .authpage__body .form-row select {
  width: 100%; padding: 11px 14px; border-radius: var(--r-ctl);
  border: 0; background: var(--gray-wash); color: var(--ink, #1b2438);
  font-size: 14px; outline: none; box-shadow: none;
  transition: border-color .16s, box-shadow .16s;
}
.authpage__body .form-row input::placeholder { color: var(--ink-3); }
.authpage__body .form-row input:focus { background: var(--paper); box-shadow: inset 0 0 0 1.5px var(--brand); }
.authhint { margin: 6px 0 0; font-size: 11.5px; color: var(--ink-3); }

/* 记住我
   ⚠️ 必须用 flex（而非 inline-flex）+ flex-start对齐：
   inline-flex + align-items:center 会让 checkbox 被文字行高顶偏约 4px，
   导致它与下方 .terms-row 的勾选框左边缘对不齐（用户反馈"左侧选择框没有对齐"）。
   下面把两者的 display / align-items / gap / input 尺寸统一成同一套写法。 */
.authpage__body .remember-row {
  display: flex; align-items: flex-start; gap: 8px;
  font-size: 12.5px; color: var(--ink-2); margin: 0 0 14px; cursor: pointer; user-select: none;
}
.authpage__body .remember-row input {
  flex: none; width: 15px; height: 15px; margin: 1px 0 0;
  accent-color: var(--brand); cursor: pointer;
}

/* 密码框 + 眼睛 */
.authpage__body .pwd-wrap { position: relative; }
.authpage__body .pwd-wrap input { padding-right: 42px; }
.authpage__body .pwd-eye {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  width: 30px; height: 30px; display: flex; align-items: center; justify-content: center;
  cursor: pointer; border-radius: var(--r-ctl); color: var(--ink-3); user-select: none;
  transition: background .15s, color .15s;
}
.authpage__body .pwd-eye .icon { width: 17px; height: 17px; stroke-width: 1.9; }
.authpage__body .pwd-eye:hover { background: var(--hover-wash); color: var(--ink); }

/* 验证码行 */
.authpage__body .code-row { display: flex; gap: 8px; }
.authpage__body .code-row input { flex: 1; min-width: 0; }
.authpage__body .code-row .btn {
  flex: none; white-space: nowrap; padding: 11px 14px; font-size: 13px; font-weight: 600;
  background: var(--gray-wash); color: var(--ink-2); border: 0; border-radius: var(--r-ctl);
}
.authpage__body .code-row .btn:disabled { opacity: .6; cursor: default; }

/* 错误 / 成功提示 */
.authpage__body .form-err { color: #dc2626; font-size: 13px; margin: 2px 0 12px; min-height: 0; }
/* 2026-10-04：校验/接口错误已全部改走全局提示条（toast），
   卡片内不再显示红字。这条规则确保 #authErr 空盒子彻底不占位、不显示。
   （:empty 只在 truly empty 时命中；showErr() 会清空 textContent，故恒命中。） */
.authpage__body .form-err:empty { display: none; }
.authpage__body .form-err { display: none; }
.authpage__body .form-ok { color: #1e7a46; font-size: 13px; margin: 2px 0 12px; }
.authpage__body .form-ok:empty { margin: 0; }

/* 主按钮行：登录只有一个主按钮 → 满宽 */
.authpage__actions { display: flex; gap: 10px; margin-top: 18px; }
.authpage__actions .btn { flex: 1; text-align: center; border-radius: 999px; padding: 12px 20px; font-size: 14.5px; font-weight: 600; }
.authpage__actions .btn.primary {
  background: linear-gradient(135deg,#111111,#4a6cf0); border: 0; color: #fff;
  box-shadow: 0 8px 18px rgba(17,17,17,.30);
}
.authpage__actions .btn.primary:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 12px 24px rgba(17,17,17,.38); }
.authpage__actions .btn:disabled { opacity: .62; cursor: default; }

/* 次要链接区（忘记密码 / 找回账号） */
.authpage__alt { display: flex; justify-content: space-between; align-items: center; margin-top: 16px; font-size: 12.5px; }
.authpage__alt a { color: var(--ink-2); text-decoration: none; }
.authpage__alt a:first-child { color: var(--brand); font-weight: 600; }
.authpage__alt a:hover { text-decoration: underline; }

/* 底部注释 */
.authpage__foot { margin: 16px 0 0; font-size: 11.5px; color: var(--ink-3); text-align: center; line-height: 1.6; }

/* 找回结果：账号名大字展示 */
.authpage__result { text-align: center; padding: 8px 0 4px; }
.authpage__resultName {
  font-size: 24px; font-weight: 800; color: #111111; letter-spacing: .5px;
  padding: 16px; border-radius: var(--r-card); background: #f5f7ff; border: 1px dashed #c9d5f5; word-break: break-all;
}

/* 窄屏：卡片贴边、光晕减弱。高度同样为顶栏(60) + 底部 TAB(76) 预留空间。 */
@media (max-width: 900px) {
  .authpage { min-height: calc(100dvh - 250px); padding: 20px 14px 30px; margin: -22px -16px 0; }
  .authpage__card { padding: 24px 20px 22px; border-radius: var(--r-panel); }
  /* 光晕的移动端尺寸在文件末尾统一处理（见「光晕 · 移动端适配」） */
}
/* 超窄：验证码按钮独占一行，避免挤压输入框 */
@media (max-width: 380px) {
  .authpage__body .code-row { flex-direction: column; }
  .authpage__body .code-row .btn { width: 100%; }
}

/* 认证整页的导航（2026-10-04 改版）：
   曾用body.auth-focus-mode 在移动端隐藏顶栏与底部 TAB，想让认证更"专注"，
   但实测问题明显 —— 页面顶部空一大块、底部也没导航，用户不知道自己在哪、
   想取消/返回找不到任何出口，只能靠浏览器返回键（导航结构与全站不一致）。
   现改为**完全保留**顶栏与底部 TAB：认证页就是普通页面，
   导航结构统一、最不会出错。专注感改由视觉（居中卡片 + 光晕）承担。 */
@media (prefers-reduced-motion: reduce) {
  .authpage__card { animation: none; }
}

/* 认证整页 · 内嵌提示块（注册码说明等） */
/* 提示框（2026-10-06 重设计：去掉左侧 3px 蓝色色条，
   改为「品牌蓝实心图标气泡 + 中性浅灰底」，与站内消息未读态、
   快捷入口同一套图标气泡语言）。 */
.authpage__notice {
  display: flex; align-items: flex-start; gap: 10px;
  background: var(--paper-2); border: 1px solid var(--rule);
  border-radius: var(--r-ctl); padding: 11px 13px; margin-bottom: 16px;
  font-size: 12.5px; color: var(--ink-2); line-height: 1.65;
}
.authpage__notice-ico {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: var(--r-ctl);
  background: var(--grad-blue); color: #fff;
  display: grid; place-items: center;
  box-shadow: 0 2px 8px rgba(17, 17, 17, .22);
  margin-top: 1px;
}
.authpage__notice-ico svg { width: 14px; height: 14px; }
.authpage__notice-tx { min-width: 0; }
.authpage__notice strong { color: var(--brand-ink); font-weight: 700; }

/* ==========================================================================
   协议勾选行（登录 / 注册 / 注册码共用）
   --------------------------------------------------------------------------
   合规要点：默认**不勾选**。不能替用户做"我已同意"的选择。
   登录流程仅提示（老用户不该被拦住），注册流程强制（提交前必须同意）。
   ========================================================================== */
.terms-row {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 4px 0 14px; cursor: pointer; user-select: none;
  font-size: 12px; color: var(--ink-2); line-height: 1.6;
}
.terms-row input {
  flex: none; width: 15px; height: 15px; margin: 1px 0 0;
  accent-color: var(--brand); cursor: pointer;
}
.terms-row a { color: var(--brand); text-decoration: none; }
.terms-row a:hover { text-decoration: underline; }
/* 注册流程：强制项，给一点视觉权重 */
.terms-row.is-required { font-weight: 500; color: #5a6b85; }
/* 未勾选被拦截时的错误态 */
.terms-row.is-error input { outline: 2px solid rgba(220,38,38,.45); outline-offset: 1px; border-radius: 3px; }
.terms-row.is-error { color: #b91c1c; }

/* ==========================================================================
   未登录提示页 · 卡片下方的协议说明
   --------------------------------------------------------------------------
   移动端页脚（黑色星空区）离卡片很远，用户想找协议要滚到底。
   这里在卡片正下方放一份，移动端显示、桌面端隐藏（桌面页脚本身就近）。
   ========================================================================== */
.login-gate__terms {
  margin: 16px 0 0; font-size: 11.5px; color: var(--ink-3); line-height: 1.7; text-align: center;
}
.login-gate__terms a { color: #7b8bb0; text-decoration: none; }
.login-gate__terms a:hover { color: var(--brand); text-decoration: underline; }
/* 全平台显示（曾在此隐藏桌面端，是错的 —— 用户反馈 PC 端也缺这句）：
   协议说明属于登录动作的附属信息，应紧贴登录卡片，任何视口宽度都需要。
   避免"重复"的正确做法是让页脚那颗颗胶囊弱化（见下方桌面端规则），而不是砍掉这一句。 */
@media (min-width: 901px) {
  .login-gate__terms { font-size: 12.5px; margin-top: 20px; }
}

/* 协议区移出卡片后，.login-gate 需改为纵向排列：
   原为 align-items:center（卡片水平居中）。
   改 flex-direction:column + justify-content:center，让卡片在上、协议紧随其下。
   协议区全平台可见（不再按视口隐藏），故这里只需保证它紧贴卡片下方。 */
.login-gate {
  flex-direction: column;
  align-items: center;/* column 方向下必须显式居中，否则子项会被拉伸 */
  justify-content: center;
  /* 2026-10-04 用户反馈「未登录页显示不全」：
     .login-gate 原无高度规则，实测桌面端只占 600px、且被 #app 的 padding-top 96px
     顶到 top=74，底部 744~900 一片空白（内容没撑满首屏、头重脚轻）。
     这里显式撑满「首屏减去上下留白」的高度，让卡片+协议在可视区垂直居中。
     min-height 用 calc(100vh - 顶栏64 - #app上下padding)，保证不溢出、可滚动。 */
  min-height: calc(100vh - 96px - 40px - 64px);
  width: 100%;
  box-sizing: border-box;
  /* 通栏破格（与 .authpage 同款）：抵消 #app 的左右 padding 28px，
     否则容器只有内容区那么宽，右侧会露出一条光场色、看起来像"没铺满"。
     上下不动 —— 靠上面的 min-height 撑满。 */
  margin: 0 -28px;
  padding: 0 28px;
  /* 显式覆盖 app.css:432 的 `background:#fff` —— app.css 加载在前，
     同优先级时本文件胜出。这里给回纯白，与认证整页的卡片观感一致。 */
  background: var(--paper);
}
/* app.css:449 的 PC 段 min-height: max(calc(100vh - 300px), 480px)
   优先级与上面这条相同但**在文件更早位置**，为避免它在 PC 上把高度改回去
   （导致底部又多出一段空白/切边），这里显式再声明一次最终值。 */
@media (min-width: 769px) {
  .login-gate { min-height: calc(100vh - 96px - 40px - 64px); }
}
.login-gate__terms {
  position: relative; z-index: 1;
  width: 100%; max-width: 430px;
  margin: 18px 0 0;                 /* 紧贴卡片下方 */
  text-align: center;
}

/* 2026-10-04 背景重写：旧 .glow 移动端适配与 .g5/.g6 底部补充光团已随
   .glow 体系一并删除。光场在 .bgflow 内自带移动端缩放规则（X195 段）。 */

/* ==========================================================================
   X60 · 提示条（.toast）重新设计 —— PC 用方案 C / 移动端用方案 E
   --------------------------------------------------------------------------
   2026-10-04 用户选定。原设计是**深色胶囊 + 状态色点 + 右下角固定**，
   与站内「浅色调 + 毛玻璃 + 蓝紫主色」语言不搭（深色块在浅色页上过于扎眼）。

   PC（≥901px）= 方案 C：右上角毛玻璃卡片
     · 右上角是桌面最不打扰内容的位置，视线扫过标题区时自然会看到
     · 毛玻璃参数与站内卡片（搜索卡/协议区）同源，语言统一
   移动端（≤900px）= 方案 E：底部居中品牌浅色胶囊
     · 底部靠近拇指热区，移动端手感最好
     · 浅色毛玻璃 + 蓝色状态点，与首页搜索卡/协议区同一配方
     · ⚠️ 关键：必须让开底部 TAB 栏（实测 TAB 高约 56~66px），
       否则提示条会被压到 TAB 后面完全看不见（这是实测发现的关键约束）

   实现方式：追加覆盖层，不修改上方旧规则 —— 旧规则里那两处app.css
   兼容处理（.toast.success 实底色覆盖）与深色主题适配仍需保留。
   ========================================================================== */

/* ---------- PC：方案 C 右上角毛玻璃卡片 ---------- */
.toast {
  /* 位置：右上角，距顶栏(64px)以下留出呼吸 */
  top: 78px;
  right: 18px;
  left: auto;
  bottom: auto;
  /* 浅色毛玻璃：与站内卡片同源 */
  background: rgba(255, 255, 255, .88);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  backdrop-filter: saturate(180%) blur(16px);
  border: 1px solid rgba(255, 255, 255, .75);
  color: var(--ink, #1b2438);
  border-radius: 13px;
  padding: 11px 12px;
  max-width: min(300px, calc(100vw - 36px));
  font-size: 13px;
  box-shadow: 0 10px 30px rgba(17, 17, 17, .13);
  /* 入场：从右上淡入 + 轻微下移；出场反向。
     多条堆叠用 --toast-i 向下排（见下方），过渡带上 top 让升降平滑。 */
  opacity: 0;
  transform: translateY(-8px) scale(.97);
  transition: opacity .26s ease,
              transform .26s cubic-bezier(.22, 1, .36, 1),
              top .26s ease;
}
.toast.is-in { opacity: 1; transform: none; }
.toast.is-out { opacity: 0; transform: translateY(-4px) scale(.98); }
/* 多条同时出现时向下堆叠（PC 从右上往下排） */
.toast {
  top: calc(78px + var(--toast-i, 0) * 60px);
}

/* 状态图标：从「小圆点」改为「圆底图标块」，更易辨识 */
.toast-dot {
  width: 22px; height: 22px;
  border-radius: var(--r-ctl);
  background: #e8f0ff; color: #2a2a2a;
  box-shadow: none;
  font-size: 11px; font-weight: 800; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  text-align: center;
}
.toast-dot::before { content: "i"; }
.toast--success .toast-dot { background: #dcfce7; color: #12b76a; }
.toast--success .toast-dot::before { content: "\2713"; }
.toast--error   .toast-dot { background: #fee2e2; color: #e5484d; }
.toast--error   .toast-dot::before { content: "!"; }
.toast--warning .toast-dot { background: #fef3c7; color: #f5a524; }
.toast--warning .toast-dot::before { content: "!"; }
.toast--info    .toast-dot { background: #e8f0ff; color: #2a2a2a; }
.toast--info    .toast-dot::before { content: "i"; }

/* 关闭按钮：改为浅色圆底（深色胶囊里的白圆底在浅色卡上不协调） */
.toast-x {
  width: 20px; height: 20px;
  background: #f1f4f9;
  color: #8b97ab;
}
.toast-x:hover { background: #e5eaf4; color: #3a4254; }
.toast-x svg { width: 11px; height: 11px; }

/* 旧版实底色类覆盖（app.css 遗留）也换成浅色，否则会透出脏色 */
.toast.success, .toast.error, .toast.warning, .toast.info {
  background: rgba(255, 255, 255, .88);
  color: var(--ink, #1b2438);
  border-color: rgba(255, 255, 255, .75);
}

/* 深色主题：整体反转成深色毛玻璃 */
[data-theme="dark"] .toast,
[data-theme="dark"] .toast.success,
[data-theme="dark"] .toast.error,
[data-theme="dark"] .toast.warning,
[data-theme="dark"] .toast.info {
  background: rgba(30, 34, 42, .9);
  border-color: rgba(255, 255, 255, .14);
  color: #e8ecf4;
}
[data-theme="dark"] .toast-x { background: rgba(255, 255, 255, .1); color: rgba(255,255,255,.75); }
[data-theme="dark"] .toast-x:hover { background: rgba(255, 255, 255, .18); color: #fff; }

/* ---------- 移动端：方案 E 底部居中品牌浅色胶囊 ---------- */
@media (max-width: 900px) {
  .toast {
    /* 底部居中；⚠️ bottom 必须 > TAB 栏高度，否则被压到 TAB 后面看不见。
       84px = TAB 栏(约66px) + 18px 呼吸，实测验证过。 */
    top: auto;
    bottom: calc(84px + env(safe-area-inset-bottom, 0px));
    left: 50%;
    right: auto;
    width: max-content;
    max-width: min(90vw, 420px);
    /* 品牌浅色胶囊 */
    background: rgba(255, 255, 255, .86);
    -webkit-backdrop-filter: saturate(180%) blur(18px);
    backdrop-filter: saturate(180%) blur(18px);
    border: 1px solid rgba(17, 17, 17, .22);
    color: var(--ink, #1b2438);
    border-radius: 999px;
    padding: 9px 8px 9px 15px;
    font-size: 12.5px;
    box-shadow: 0 8px 26px rgba(17, 17, 17, .14);
    /* 用 translateX 居中：left:50% 后向左收自身一半宽 */
    transform: translate(-50%, 10px) scale(.97);
    transition: opacity .26s ease,
                transform .26s cubic-bezier(.22, 1, .36, 1),
                bottom .26s ease;
  }
  .toast.is-in { opacity: 1; transform: translate(-50%, 0); }
  .toast.is-out { opacity: 0; transform: translate(-50%, 6px) scale(.98); }
  /* 多条堆叠：向上排（更靠近拇指，也更符合"越新越靠上"的直觉） */
  .toast {
    bottom: calc(84px + env(safe-area-inset-bottom, 0px) + var(--toast-i, 0) * 58px);
  }
  /* 移动端状态点回归小圆点（胶囊里圆底图标块会显得笨重） */
  .toast-dot {
    width: 7px; height: 7px; border-radius: 999px;
    font-size: 0; box-shadow: 0 0 0 3px rgba(96, 165, 250, .22);
  }
  .toast-dot::before { content: "" !important; }
  .toast--success .toast-dot { background: #12b76a; box-shadow: 0 0 0 3px rgba(18, 183, 106, .2); }
  .toast--error   .toast-dot { background: #e5484d; box-shadow: 0 0 0 3px rgba(229, 72, 77, .2); }
  .toast--warning .toast-dot { background: #f5a524; box-shadow: 0 0 0 3px rgba(245, 165, 36, .2); }
  .toast--info    .toast-dot { background: #2a2a2a; box-shadow: 0 0 0 3px rgba(17, 17, 17, .2); }
  [data-theme="dark"] .toast,
  [data-theme="dark"] .toast.success,
  [data-theme="dark"] .toast.error,
  [data-theme="dark"] .toast.warning,
  [data-theme="dark"] .toast.info {
    background: rgba(30, 34, 42, .9);
    border-color: rgba(255, 255, 255, .14);
    color: #e8ecf4;
  }
  [data-theme="dark"] .toast-dot { box-shadow: none; }
}

/* ==========================================================================
   X61 · 认证整页（#/login）消除纵向溢出（滚动条 + 底部白块）
   --------------------------------------------------------------------------
   现象（2026-10-04 用户反馈，截图 127.0.0.1:61398/#/login?mode=register）：
     窗口较矮时页面出现纵向滚动条，页脚下方露出一段白色空白 + 残留色带。

   实测根因（1280x720）：
     文档总高恒为 **997px** = #app 841 + 页脚 76 + 间距 80，
     构成是 #app(padding 96/40) + .authpage(727, margin-top -22) + footer(76)。
     只要视口 < 997px 就溢出 → 出现滚动条；
     滚动到底时页脚之下没有内容填充，露出 body 的白底 —— 即"白色区域"。
     之所以"有时候"出现：1920x1080（视口 1080 > 997）不滚动，1280x720/1440x900 等会。

   修法选择：不隐藏顶栏/页脚（页内导航已证明能提升可用性），改为**按视口高度自适应**：
     · 视口够高时：认证页占满剩余空间，页脚自然在首屏内，不滚动；
     · 视口很矮时：让 .authpage 用**内容高度**（不再强制 min-height），
       页面只在必要时滚动，且滚动到底时页脚紧贴内容尾、不露白。
   用 min-height:min(100vh, calc(100vh - 300px)) 等价于"上限 100vh"，
   这里改用 height:auto + min-height 由内容决定，配合负margin 精确吃掉 #app 的 padding。
   ========================================================================== */

/* 认证整页：不再用 min-height 撑高，改为**内容自适应**。
   min-height 固定值（哪怕 max(...,700px)）是本次溢出的直接来源。 */
.authpage {
  /* 只保证"至少能放下卡片 + 一屏"的下限，不制造额外高度。
     clamp(560px, 100vh - 300px, 1000px) 的含义：
       · 视口高 → 取 100vh-300（把顶栏/底栏空间让出来，页脚进首屏）
       · 视口矮 → 取下限 560px（够放卡片 600px 左右，超出则自然滚动）
       · 视口极高 → 取上限 1000px（不让光晕区无限拉长） */
  /* 恢复稳定高度：固定 calc，不用 clamp/dvh ——
     容器高度必须可预测，否则绝对定位的光晕会随高度变化被推出边界（露白底）。
     calc(100vh - 300px) 中 300 = 顶栏 64 + 底部 TAB/页脚留白，与全站口径一致。 */
  min-height: calc(100vh - 300px);
}
/* 认证页内的卡片：视口很矮时收紧上下留白，减少溢出量 */
@media (max-height: 700px) {
  .authpage { padding: 20px 20px 24px; }
  .authpage__card { padding: 24px 26px 22px; }
}

/* --------------------------------------------------------------------------
   认证整页隐藏页脚 —— 消除溢出的**根本**手段
   --------------------------------------------------------------------------
   为什么可以隐藏（与顶栏不同）：
     · 顶栏是全局导航，隐藏会让用户迷路（历史上已验证过，故保留）；
     · 页脚在认证页是**纯冗余**：协议入口在登录卡片下方已有（.login-gate__terms）
       与登录页勾选框（.terms-row）都已覆盖，页脚再放一遍是重复内容。
   为什么必须隐藏：
     文档总高 = #app(padding-top 96 - margin -22=74 + authpage 727 + padding-bottom 40)
              + 页脚 76 = 997px。
     这 997px 与视口无关（内容撑出来的），只要视口 < 997 就必然滚动；
     滚动到底页脚之后无内容，露出 body 白底 —— 即用户看到的"底部白色区域 + 残留色带"。
     认证页是"一屏完成"的整页，不需要滚动。
   实现：用 :has() 命中「body 里有 .authpage」即认证路由（Chromium/Safari/Firefox 均已支持）。
   ========================================================================== */
/* 页脚保持显示（用户明确要求）。此处不隐藏任何全局元素。 */

/* ⚠️ 不要再对 #app 的 padding 或 .authpage 的 margin-top 做通栏破格调整：
   那会让认证容器的高度与位置随视口变化，而 .glow 是 position:absolute
   定位在容器内的 —— 容器一变，光晕就会被推出容器边界，
   在页面底部露出 body 的白色区域（用户反馈"好像和光晕流动位置有关系"）。
   容器高度必须稳定，光晕才有确定的绘制范围。 */

/* ==========================================================================
   X62 · 注册成功过渡页（.auth-success）
   --------------------------------------------------------------------------
   2026-10-04 用户需求：新用户注册成功后不要把人丢回登录页重新输一遍，
   给一个"点击即登录"的过渡页。整个卡片可点，符合直觉。
   视觉沿用认证页语言：品牌蓝对勾徽章 + 胶囊按钮。
   ========================================================================== */
.auth-success { text-align: center; padding: 6px 0 2px; }
.auth-success__badge {
  width: 78px; height: 78px; margin: 0 auto 16px; border-radius: 50%;
  background: linear-gradient(135deg, #12b76a, #34d399);
  display: flex; align-items: center; justify-content: center;
  color: #fff; box-shadow: 0 12px 30px rgba(18, 183, 106, .32);
  animation: authSuccessPop .5s cubic-bezier(.22, 1, .36, 1) both;
}
.auth-success__badge .icon { width: 38px; height: 38px; stroke-width: 2.4; }
@keyframes authSuccessPop {
  0%   { opacity: 0; transform: scale(.5); }
  60%  { opacity: 1; transform: scale(1.08); }
  100% { opacity: 1; transform: scale(1); }
}
.auth-success__tip { margin: 0 0 20px; font-size: 13.5px; color: var(--ink-2); }
/* 主按钮：加大点击热区，整卡可点时它是视觉焦点 */
.auth-success__btn { width: 100%; padding: 13px 20px; font-size: 15px; }
/* 次要出口：去登录页（避免自动登录失败时无路可走） */
.auth-success__link {
  display: block; margin: 14px auto 0; background: none; border: 0;
  font-size: 12.5px; color: var(--ink-3); cursor: pointer; padding: 4px 8px;
  font-family: inherit;
}
.auth-success__link:hover { color: var(--brand); text-decoration: underline; }
/* 整卡可点的光标反馈（按钮/链接自身已有 pointer，容器给 default 避免误导） */
.authpage__card:has(.auth-success) { cursor: default; }

/* 尊重「减少动态效果」 */
@media (prefers-reduced-motion: reduce) {
  .auth-success__badge { animation: none; }
}

/* ==========================================================================
   X63 · 账号可用性实时校验（注册第一步）
   --------------------------------------------------------------------------
   2026-10-04 用户反馈："账号应该也验证是否已经注册过"。
   原来只有点「下一步」才由服务端报「该账号已被使用」——填完整页才被拦。
   这里在输入框下方实时提示，三态：检查中 / 可用 / 被占用 / 格式不符。
   ========================================================================== */
/* 挂在 form-row 内的状态行，紧跟输入框与 hint */
.ucheck {
  display: flex; align-items: center; gap: 6px;
  margin: 6px 0 0; font-size: 12px; line-height: 1.5;
  color: var(--ink-3); min-height: 18px;
  animation: ucheckIn .18s ease both;
}
@keyframes ucheckIn { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: none; } }
/* 状态图标：纯 CSS 画圆点，避免额外请求 */
.ucheck__dot {
  flex: none; width: 12px; height: 12px; border-radius: 50%;
  position: relative; background: #cbd5e1;
}
.ucheck__dot::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
}
/* 检查中：灰点 + 旋转环 */
.ucheck.is-checking .ucheck__dot { background: transparent; border: 2px solid #cbd5e1; border-top-color: #111111; animation: ucheckSpin .7s linear infinite; }
@keyframes ucheckSpin { to { transform: rotate(360deg); } }
/* 可用：绿点+ 对勾（用 box-shadow 画） */
.ucheck.is-ok { color: #12b76a; }
.ucheck.is-ok .ucheck__dot { background: #12b76a; }
.ucheck.is-ok .ucheck__dot::after {
  inset: 2px 1px auto 3px; width: 3px; height: 6px; border-radius: 1px;
  background: #fff; transform: rotate(45deg);
}
/* 被占用 / 格式不符：红点 + 叹号 */
.ucheck.is-taken, .ucheck.is-bad { color: #e5484d; }
.ucheck.is-taken .ucheck__dot, .ucheck.is-bad .ucheck__dot { background: #e5484d; }
.ucheck.is-taken .ucheck__dot::after, .ucheck.is-bad .ucheck__dot::after {
  content: "!"; position: absolute; inset: 0; color: #fff;
  font-size: 9px; font-weight: 800; line-height: 12px; text-align: center;
}

/* ==========================================================================
   X195 · 全局流动光场背景 .bgflow（2026-10-04 推翻重写，取代旧 .glow 随机游走体系）
   --------------------------------------------------------------------------
   用户指令（旧体系全部推翻重写）：
   ① 背景盛满整屏 —— fixed + inset:0，任何页面、任何滚动位置都不露死白；
   ② 流动**不间断** —— 旧 glow.js「缓动到目标→停顿→换目标再缓动」的节奏被否定。
      新方案：每团光拆成 X 轴（外层元素）与 Y 轴（内层元素）两条**不同周期**的
      ease-in-out infinite alternate 动画。两条轴相位错开，任意时刻至少一条轴
      在运动，合成轨迹是一条永不停的利萨茹式曲线 —— 没有「到位停顿」，
      叠加透明度呼吸后就是持续流动的活光场。
   ③ 各颜色不扎堆 —— 五团光锚定「左上蓝 / 右上紫 / 左下橙 / 右下浅蓝 / 中部淡紫」，
      漂移幅度有限且互相错开，永远保持分散。
   ④ 永不超出底栏 —— 图层 overflow:hidden 且裁剪边就是视口边框，
      光在物理上出不了屏；移动端悬浮底栏背后及其下方间隙透出的都是
      光场底色而非 body 纯白 → 「底栏下方白块」从机制上消失。

   兼容性：不用 CSS 独立变换属性（translate/scale property，旧内核不支持），
   而是外层动 X、内层动 Y —— 两层 transform 天然叠加，全浏览器可用。
   只动 transform / opacity，全部走合成器，零重排零重绘。
   ========================================================================== */
.bgflow {
  /* 默认隐藏 —— 光场只用于「首页首屏」与「登录相关页」（见下方 display:block 规则）。
     2026-10-04 用户要求：其余页面（社区/固件/协议/升级查询…）不要光晕背景。
     这些页面恢复 body 的纯色底（见文件头 body 规则），不显示任何流动光。 */
  display: none;
  position: fixed;
  inset: 0;
  /* ⚠️ z-index 必须是 0（不是 -1）：body 无定位/z-index 时其背景会传播到
     根画布，负层级图层会沉到画布底色之下被完全遮住（实测五团光全不可见）。 */
  z-index: 0;
  overflow: hidden;                  /* ⚠️ 裁剪边=视口边：光永不出屏、永不超底栏 */
  pointer-events: none;
  /* 基底：**白色**（2026-10-04 用户要求「光晕的背景色采用白色」）。
     纯白底让下方光团的高饱和色不被压暗 —— 之前偏蓝的底色(#eaf1ff)会把
     蓝/紫光团"吃掉"，显得灰蒙蒙。光晕本身带色，白底上最鲜明。 */
  background: #fff;
}
[data-theme="dark"] .bgflow {
  background: #0b0b0c;
}

/* --------------------------------------------------------------------------
   光场的适用范围（display:block 的几处）
   --------------------------------------------------------------------------
   ① 首页：只在**第一屏**。首页是 5 屏scroll-snap 长页，第 2~5 屏有自己的
      区块底色（见下方 .home > section），光场用 absolute + 100vh 随文档滚走。
   ② 认证页（#/login 登录/注册/找回 + 未登录引导页）：整页即一屏，
      用 fixed + inset:0 铺满，顶栏毛玻璃背后恒有光可模糊。 */
body:has(.home) .bgflow,
body:has(.authpage) .bgflow,
body:has(.login-gate) .bgflow {
  display: block;
}
body:has(.home) .bgflow {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: auto;
  height: 100vh;
}
/* 内容层统一压在光场之上（z-index:0 的 fixed 层会盖住静态流内容）。
   ⚠️ 顶栏/底栏/加载层本身已是 fixed，**不能**被降级成 relative，
   否则顶栏会随页面滚走、毛玻璃失效 —— 故这三个只给 z-index。
   body 设为 relative：首页 absolute 光场需要定位祖先（body 在文档流位置为 0，
   relative 化不改变任何布局）。 */
body { position: relative; }
/* #noticeBar 必须给回 z-index:89（它自身样式里就是 89，位于顶栏 90 之下）。
   之前被并进下面这条 z-index:1 的规则 → 公告被 hero 等内容层盖住，
   关闭按钮点不到（用户反馈「PC 首页公告无法关闭」）。 */
#noticeBar { z-index: 89; }
#app, footer, #modalRoot { position: relative; z-index: 1; }
#masthead, #tabbar, .boot { z-index: 90; }
/* 首页区块底色（参照 E:\difansclub 参考版布局）：
   灰白交替**由 HTML 的 class="alt" 表达**（第 2、4 区块带 alt），
   CSS 只有一条 .home section.alt 规则；非 alt 区块保持**透明**，
   直接露出 body 的纯白底。

   ⚠️ 不要再写 `.home > section:not(.hero){background:var(--paper)}` 这类
   「统一刷白」规则 —— 那会把 alt 的灰底盖掉，交替节奏失效
   （2026-10-04 曾因此让迪粉分享区变白底，底部露出下一区块）。
   唯一需要显式兜底的是首屏 Hero：它透明好让 .bgflow 光场透上来。 */
.bgflow .bf { position: absolute; will-change: transform; }
.bgflow .bf > i {
  display: block; width: 100%; height: 100%;
  border-radius: 50%;
  will-change: transform, opacity;
}
@media (prefers-reduced-motion: reduce) {
  .bgflow .bf, .bgflow .bf > i { animation: none !important; }
}

/* ==========================================================================
   五团光：锚点、颜色与运动
   --------------------------------------------------------------------------
   两层结构，各司其职（这是"随机 + 不停顿"能同时成立的关键）：
     · 外层 .bf   —— 承载 JS 随机游走位移（--bx/--by），**不挂 CSS 动画**
                     （若挂上，transform 会被动画覆盖，JS 就白写了）；
     · 内层 .bf>i —— 承载 CSS 持续漂移动画（bfx*/bfy*）与呼吸（bfo*），
                     速度恒不为零 → 任何时刻都在流动，JS 到位时也不停顿。

   颜色（2026-10-04 用户要求「光晕的色彩再明显一些」）：
     白底下颜色要够"浓"才看得见，故把主色不透明度整体提高、
     渐变中段收紧（色带更集中）、外圈透明起点后移（减少衰减）；
     主色也轻微提纯，避免 blur(58px) 把边缘混成灰。
     配色沿用原色系：品牌蓝 / 品牌紫 / 暖橙 / 浅蓝 / 淡紫。
   ========================================================================== */

/* 外层统一：承载 JS 随机游走位移。
   ⚠️ transform 只能写在这里，且**绝不能**给 .bf 挂 animation ——
   CSS 动画与 JS 写内联transform 会互相覆盖（animation 优先级更高，
   会把 JS 的随机位移直接顶掉，退化成固定循环）。 */
.bgflow .bf {
  transform: var(--gt, translate(0, 0));
  will-change: transform;
}

/* 蓝左上（最大团）：垫在毛玻璃顶栏背后，顶栏毛玻璃恒有内容可模糊 */
.bf1 {
  width: 780px; height: 600px; left: -200px; top: -180px;
  /* ⚠️ 不挂 animation：transform 留给 JS 随机游走 */
}
.bf1 > i {
  background: radial-gradient(closest-side, rgba(38,96,255,.85), rgba(120,172,255,.5), transparent 70%);
  filter: blur(58px);
  animation: bfx1 13s ease-in-out infinite,
             bfy1 9s ease-in-out infinite,
             bfo1 7s ease-in-out infinite;
}
/* 折线路径：4 段走一个不规则闭合圈 */
@keyframes bfx1 {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(300px, 90px); }
  50%  { transform: translate(190px, 330px); }
  75%  { transform: translate(-120px, 200px); }
  100% { transform: translate(0, 0); }
}
@keyframes bfy1 {
  0%   { transform: translate(0, 0); }
  30%  { transform: translate(60px, 190px); }
  60%  { transform: translate(-90px, 260px); }
  100% { transform: translate(0, 0); }
}
@keyframes bfo1 {
  0%, 100% { opacity: .72; }
  50%      { opacity: 1; }
}

/* 紫右上 */
.bf2 {
  width: 620px; height: 500px; right: -180px; top: -150px;
  /* 位置由 bgflow.js 随机游走写 --bx/--by，transform 留给它 */
}
.bf2 > i {
  background: radial-gradient(closest-side, rgba(112,50,240,.72), rgba(158,110,255,.42), transparent 70%);
  filter: blur(58px);
  animation: bfx2 11s ease-in-out infinite,
             bfy2 14s ease-in-out infinite,
             bfo2 8s ease-in-out infinite;
}
@keyframes bfx2 {
  0%   { transform: translate(0, 0); }
  30%  { transform: translate(-280px, 120px); }
  65%  { transform: translate(-120px, 340px); }
  100% { transform: translate(0, 0); }
}
@keyframes bfy2 {
  0%   { transform: translate(0, 0); }
  40%  { transform: translate(-70px, 200px); }
  75%  { transform: translate(80px, 120px); }
  100% { transform: translate(0, 0); }
}
@keyframes bfo2 {
  0%, 100% { opacity: .68; }
  50%      { opacity: 1; }
}

/* 橙左下 */
.bf3 {
  width: 560px; height: 460px; left: -160px; top: 54vh;
  /* 位置由 bgflow.js 随机游走写 --bx/--by，transform 留给它 */
}
.bf3 > i {
  background: radial-gradient(closest-side, rgba(255,150,30,.7), rgba(255,196,120,.4), transparent 70%);
  filter: blur(58px);
  animation: bfx3 10s ease-in-out infinite,
             bfy3 13s ease-in-out infinite,
             bfo3 6s ease-in-out infinite;
}
@keyframes bfx3 {
  0%   { transform: translate(0, 0); }
  30%  { transform: translate(320px, -80px); }
  70%  { transform: translate(140px, -300px); }
  100% { transform: translate(0, 0); }
}
@keyframes bfy3 {
  0%   { transform: translate(0, 0); }
  35%  { transform: translate(80px, -160px); }
  70%  { transform: translate(-60px, -240px); }
  100% { transform: translate(0, 0); }
}
@keyframes bfo3 {
  0%, 100% { opacity: .6; }
  50%      { opacity: .95; }
}

/* 浅蓝右下 */
.bf4 {
  width: 640px; height: 520px; right: -210px; top: 58vh;
  /* 位置由 bgflow.js 随机游走写 --bx/--by，transform 留给它 */
}
.bf4 > i {
  background: radial-gradient(closest-side, rgba(48,102,255,.6), rgba(126,178,255,.36), transparent 70%);
  filter: blur(58px);
  animation: bfx4 15s ease-in-out infinite,
             bfy4 8s ease-in-out infinite,
             bfo4 11s ease-in-out infinite;
}
@keyframes bfx4 {
  0%   { transform: translate(0, 0); }
  30%  { transform: translate(-300px, -100px); }
  70%  { transform: translate(-150px, -320px); }
  100% { transform: translate(0, 0); }
}
@keyframes bfy4 {
  0%   { transform: translate(0, 0); }
  40%  { transform: translate(-90px, -180px); }
  80%  { transform: translate(60px, -90px); }
  100% { transform: translate(0, 0); }
}
@keyframes bfo4 {
  0%, 100% { opacity: .66; }
  50%      { opacity: 1; }
}

/* 淡紫中部（最弱）：填补四团之间的空档，避免中部过素 */
.bf5 {
  width: 540px; height: 440px; left: calc(50% - 270px); top: 30vh;
  /* 位置由 bgflow.js 随机游走写 --bx/--by，transform 留给它 */
}
.bf5 > i {
  background: radial-gradient(closest-side, rgba(124,72,255,.42), rgba(140,172,255,.28), transparent 70%);
  filter: blur(64px);
  animation: bfx5 9s ease-in-out infinite,
             bfy5 12s ease-in-out infinite,
             bfo5 10s ease-in-out infinite;
}
@keyframes bfx5 {
  0%   { transform: translate(0, 0); }
  35%  { transform: translate(240px, 140px); }
  70%  { transform: translate(-160px, 220px); }
  100% { transform: translate(0, 0); }
}
@keyframes bfy5 {
  0%   { transform: translate(0, 0); }
  45%  { transform: translate(-100px, 150px); }
  100% { transform: translate(0, 0); }
}
@keyframes bfo5 {
  0%, 100% { opacity: .5; }
  50%      { opacity: .85; }
}

/* --- 移动端：等比缩小（视口小，同尺寸光团会挤成一坨） --- */
@media (max-width: 900px) {
  .bgflow .bf > i { filter: blur(34px); }          /* 小屏少模糊，省GPU */
  .bf1 { width: 440px; height: 340px; left: -130px; top: -110px; }
  .bf2 { width: 350px; height: 290px; right: -130px; top: -90px; }
  .bf3 { width: 330px; height: 270px; left: -110px; top: 56vh; }
  .bf4 { width: 370px; height: 300px; right: -140px; top: 60vh; }
  .bf5 { width: 310px; height: 250px; left: calc(50% - 155px); top: 32vh; }
}
@media (max-width: 420px) {
  .bf1 { width: 380px; height: 300px; }
  .bf2 { width: 300px; height: 250px; }
  .bf3 { width: 280px; height: 230px; }
  .bf4 { width: 320px; height: 260px; }
  .bf5 { width: 270px; height: 220px; }
}

/* ==========================================================================
   X217 · 首页第 3 区块（固件资源）卡片：两行布局 + 高度对齐第 5 区块
   --------------------------------------------------------------------------
   用户要求（2026-10-04）：
     · PC 端两行、一行 4 个；移动端两行、一行 2 个；
     · 分 2 页自动轮播（圆点可点，5 秒间隔，悬停暂停）；
     · 卡片高度调整到本区块上下留白与第 5 区块一致；
     · 缩略图只保留**车型标签**（移到左上角），去掉文件类型标签（压缩包/文档）。

   本段放在文件**末尾**的原因：文件中部有多条 .card .body 规则
   （1047/1264/2421/2520/2914 行，特异性相同或更高）会覆盖前面写的值，
   实测 1047 行的 112px 被 2520 行的 104px 压掉。
   ========================================================================== */
@media (min-width: 901px) {
  /* 正文区 90px：卡高 208px，上留白 141px —— 与第 5 区块的 141px 完全一致。
     用 height 而非 min-height，保证「文件名一行/两行」的卡片等高、底部对齐。 */
  html.page-snap .home section:nth-of-type(3) .card .body { height: 90px; min-height: 0; }
  /* 文件名给两行空间（固件名很长，一行放不下会被裁）；
     .meta 用 align-self:end 吸底，多余高度不会挤压标题。 */
  html.page-snap .home section:nth-of-type(3) .card h4 {
    -webkit-line-clamp: 2;
    font-size: 13.5px;
    line-height: 1.45;
    margin-bottom: 6px;
  }
}
@media (max-width: 900px) {
  /* 移动端两行 × 2 列，每页 4 张 = 2 页。 */
  .home section:nth-of-type(3) .grid,
  .hot-dl .grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
}

/* ==========================================================================
   X222 · 认证整页布局：顶栏 + 卡片 + 底栏 一屏内、上下留白均等
   --------------------------------------------------------------------------
   用户要求（2026-10-04）：
     · PC 与移动端都要「卡片上下到顶栏/底栏的留白一样大」；
     · 顶栏 + 卡片 + 底栏能装进一屏时**不触发滚动**；
     · 三者之间必须有留白，不能贴在一起；
     · 卡片太大装不下时，允许在顶栏与底栏之间居中（可滚动）。

   改前实测（1440×900 / 390×844）：
     桌面：需滚动(930>900)、上留白 40 / 下留白 206（差 166px）
     移动：无需滚动、上留白 22 / 下留白 97（差 75px）

   做法：
     ① 高度基准从 `min-height: calc(100vh - 300px)`（魔法数字，随内容漂移）
        改为 **视口高度 - 顶栏 - 底栏**（用 CSS 变量，两端各自准确）；
     ② #app 在认证页上去掉 padding（padding 会被算进高度导致溢出滚动），
        改由 .authpage 自己用 padding 控制上下留白；
     ③ 上下 padding 取同一个值 → 卡片在「顶栏与底栏之间」精确居中，
        上下留白天然相等；
     ④ max-height + overflow-y:auto 兜底：卡片太高时容器内滚动而不是整页滚动。

   放在文件**末尾**：中部有多条 .authpage 规则（5541/5966 行等）会覆盖。
   ========================================================================== */

:root {
  --auth-topbar-h: 64px;   /* PC 顶栏高（#masthead） */
  --auth-tabbar-h: 0px;   /* PC 无底部 TAB */
}
@media (max-width: 900px) {
  :root {
    --auth-topbar-h: 60px;                              /* 移动顶栏 */
    --auth-tabbar-h: 66px;                              /* 移动底栏 #tabbar */
  }
}

/* 认证页：#app 去掉上下 padding，交给 .authpage 精确控制，避免双重留白 */
body:has(.authpage) #app { padding-top: 0; padding-bottom: 0; }
body:has(.authpage) #app:has(+ footer) { padding-bottom: 0; }

/* 认证整页：占满**整个视口**，用 padding-top/bottom 让开顶栏与底栏。
   ⚠️ 容器高度不能用「100dvh - 顶栏 - 底栏」：
   顶栏/底栏是 position:fixed 浮层（不占文档流），.authpage 自身仍从 y=0 开始，
   减掉顶栏高度会让容器整体上移、卡片撞到顶栏背后（实测上留白 -1px），
   叠加页脚后还会多出滚动（实测 992 > 900）。
   正确做法：容器高= 视口高，padding-top = 顶栏高 + 留白，
   padding-bottom = 底栏高 + 留白，两者相等 → 卡片精确居中。 */
.authpage {
  /* ⚠️ 用 height（不是 min-height）：min-height 只保证下限，
     卡片比可视区高时容器会被**撑到超过一屏** → 整页滚动，
     且 justify-content:center 失效导致上下留白不等。
     固定 height + overflow-y:auto后：容器恒为一屏，
     卡片放得下就居中（留白均等），放不下就在容器内滚动。 */
  height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;      /* 上下留白均等的关键 */
  /* 上下留白 = 顶栏/底栏高度 + 32px 呼吸，卡片不贴任何一方 */
  padding: calc(var(--auth-topbar-h) + 32px) 20px calc(var(--auth-tabbar-h) + 32px);
  margin: 0 -16px 0;
  box-sizing: border-box;
  /* 卡片过高时**容器内滚动**，整页保持一屏不滚动 */
  overflow-y: auto;
  /* 矮视口收紧呼吸值，保证小屏也能放下大部分卡片 */
  scrollbar-width: thin;
}
/* 认证页隐藏页脚：它只是冗余（协议入口已在卡片下方），留着会撑出滚动 */
body:has(.authpage) footer { display: none; }
/* 不支持 dvh 的老内核回落到 vh */
@supports not (height: 100dvh) {
  .authpage { height: 100vh; }
}
/* 矮视口（小屏手机 / 笔记本）：收紧呼吸值 + 压缩卡片内边距，
   让「顶栏 + 卡片 + 底栏」尽量挤进一屏。放不下时由上面的 overflow-y:auto 兜底。 */
@media (max-height: 760px) {
  .authpage {
    padding-top: calc(var(--auth-topbar-h) + 14px);
    padding-bottom: calc(var(--auth-tabbar-h) + 14px);
  }
  .authpage__card { padding: 20px 22px 18px; }
}
@media (max-height: 680px) {
  .authpage { padding-top: calc(var(--auth-topbar-h) + 8px); padding-bottom: calc(var(--auth-tabbar-h) + 8px); }
  .authpage__card { padding: 16px 18px 14px; }
  .authpage__title { font-size: 20px; }
  .authpage__sub { margin-bottom: 12px; }
  /* Tab 胶囊与标题区一起收紧 */
  .authtabs { margin-bottom: 14px; }
}

/* 卡片 + 协议区作为一个整体居中；卡片本身不再自带外边距 */
.authpage__card { flex: none; }


/* ==========================================================================
   内容审核：详情页「审核中」提示条（2026-10-07）
   --------------------------------------------------------------------------
   自动审核把疑似内容置为 state = pending；此时内容仅作者本人与管理员可见，
   需要在详情页给出明确、不刺眼的说明，避免作者以为「发出去了没人看」。
   颜色全部走主题变量，浅色 / 深色两套主题自动适配。
   ========================================================================== */
.cb-modbar {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  margin: 14px 0 0; padding: 12px 16px;
  background: var(--brand-wash); border: 1px solid var(--rule);
  border-left: 3px solid var(--brand); border-radius: var(--r-ctl);
  font-size: 13px; color: var(--ink-2); line-height: 1.6;
}
.cb-modbar b { color: var(--brand-ink); font-size: 13.5px; font-weight: 700; }
.cb-modbar .cb-modbar-rs { color: var(--ink-3); font-size: 12.5px; }
.cb-modbar .cb-modbar-sub { flex: 1 1 100%; color: var(--ink-3); font-size: 12.5px; margin-top: 1px; }
/* 评论上的「审核中」角标（.cb-cmt-badge 基类已有，这里只补配色） */
.cb-cmt-badge--wait { background: var(--brand-wash); color: var(--brand-ink); }

/* ==========================================================================
   X218. 应用资源（/apps）—— 方案 A：双栏文件管理器
   --------------------------------------------------------------------------
   结构：Hero 标题区 → 白卡（左目录树 238px + 右面包屑/排序/搜索 + 文件列表）
   视觉：与固件资源页 .dk-* 同源（白卡 24px 圆角、胶囊按钮、柔和阴影），
        但独立命名空间 .ap-*，避免与固件目录页互相牵连。
   断点：<=900px 目录树改为可折叠面板（点工具栏「目录」展开）。
   ========================================================================== */
/* 宽度/内边距一律交给 #app（max-width: --measure 1200 - 28*2 = 1144），
   这里不再自建 max-width 与 24px 内边距 —— 那会让白卡比固件资源页窄 48px，
   且 padding-bottom 与「全站统一底部留白」规则叠加，页脚间距忽大忽小。 */
.ap-page { padding: 0; }

/* ---------- Hero（尺寸/间距与 .dk-hero 逐项对齐） ---------- */
.ap-hero { text-align: center; margin-bottom: 30px; }
.ap-hero-ico {
  display: inline-grid; place-items: center; width: 60px; height: 60px; margin-bottom: 16px;
  border-radius: var(--r-panel); background: var(--grad-gold); color: #fff;
  box-shadow: 0 10px 28px rgba(217, 132, 7, .22);
}
.ap-hero-ico svg { width: 28px; height: 28px; }
.ap-hero h1 {
  font-family: var(--font-display); font-size: 34px; font-weight: 800;
  letter-spacing: -.5px; color: var(--ink); margin: 0 0 12px;
}
.ap-hero p {
  font-size: 15.5px; color: var(--ink-2); line-height: 1.75;
  max-width: 780px; margin: 0 auto; text-wrap: balance;
}
.ap-hero-tags { display: flex; justify-content: center; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
/* 与 .dk-tag 同款：浅灰底、胶囊、无描边 */
.ap-tag {
  display: inline-flex; align-items: center; font-size: 12.5px; font-weight: 600;
  color: var(--ink-2); background: var(--paper-2); border-radius: var(--r-btn);
  padding: 5px 14px;
}
.ap-tag.b { background: var(--brand-wash); color: var(--brand); }

/* ---------- 白卡 + 双栏骨架 ---------- */
/* 与 .dk-panel 同款外层：同描边、同 24px 圆角、同阴影、同 18/22/20 内边距。
   内边距的作用是让左侧目录树成为「卡内的一块面」，而不是顶到卡片边缘的整列，
   这样两张页面切换时卡片边框、内缩量完全一致。 */
.ap-card {
  background: #fff; border: 0;
  border-radius: var(--r-card); padding: 18px 22px 20px;
  box-shadow: none;
}
.ap-layout { display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 18px; align-items: start; }

/* ---------- 左：目录树（卡内浅灰面） ---------- */
.ap-tree {
  background: var(--paper-2); border-radius: var(--r-panel);
  padding: 10px; min-width: 0;
}
.ap-tree-h {
  font-size: 11px; font-weight: 700; color: var(--ink-3);
  letter-spacing: .8px; padding: 4px 10px 8px; text-transform: uppercase;
}
.ap-tree-a {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 10px; border-radius: var(--radius-sm);
  font-size: 13px; font-weight: 500; color: var(--ink-2);
  text-decoration: none; margin-bottom: 1px; transition: .15s;
}
.ap-tree-a svg { width: 16px; height: 16px; flex: 0 0 16px; color: var(--ink-3); }
.ap-tree-a span {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ap-tree-a:hover { background: #fff; color: var(--ink); }
.ap-tree-a:hover svg { color: var(--brand); }
.ap-tree-a.on { background: #fff; color: var(--brand); font-weight: 600; box-shadow: 0 1px 3px rgba(0, 0, 0, .06); }
.ap-tree-a.on svg { color: var(--brand); }
.ap-tree-cnt {
  margin-left: auto; font-style: normal; font-size: 11px; font-weight: 700;
  color: var(--ink-3); background: var(--gray-wash); border: 0;
  border-radius: var(--radius-pill); padding: 1px 7px;
}
.ap-tree-a.on .ap-tree-cnt { color: var(--brand); border-color: transparent; background: var(--brand-wash); }
.ap-tree-ph { font-size: 12px; color: var(--ink-3); padding: 10px; }

/* 移动端才出现的「目录」按钮 */
.ap-tree-toggle {
  display: none; align-items: center; gap: 6px; padding: 6px 12px;
  border: 1px solid var(--rule); border-radius: var(--radius-pill);
  background: var(--paper); color: var(--ink-2); font-size: 12.5px; font-weight: 600;
}
.ap-tree-toggle svg { width: 15px; height: 15px; }

/* ---------- 右：工具栏 + 列表 ---------- */
.ap-main { display: flex; flex-direction: column; min-width: 0; }
/* 与 .disk-toolbar 同节奏：底部细线 + 14px 下留白 */
.ap-toolbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 2px 0 12px; border-bottom: 1px solid var(--line-soft); margin-bottom: 12px;
}
.ap-grow { flex: 1; }
.ap-crumb { display: flex; align-items: center; gap: 5px; font-size: 13px; flex-wrap: wrap; min-width: 0; }
.ap-crumb a {
  display: inline-flex; align-items: center; gap: 5px; text-decoration: none;
  color: var(--ink-2); padding: 3px 8px; border-radius: var(--radius-sm); transition: .15s;
}
.ap-crumb a svg { width: 14px; height: 14px; }
.ap-crumb a:hover { background: var(--paper-2); color: var(--brand); }
.ap-crumb a.cur { color: var(--ink); font-weight: 600; }
.ap-sep { color: var(--ink-3); font-size: 11px; }

.ap-seg {
  display: inline-flex; background: var(--paper-2); border: 0;
  border-radius: var(--radius-pill); padding: 3px;
}
.ap-seg button {
  border: none; background: none; cursor: pointer; padding: 5px 14px;
  border-radius: var(--radius-pill); font-size: 12.5px; font-weight: 600;
  color: var(--ink-3); font-family: inherit; transition: .16s;
}
.ap-seg button.on { background: var(--select-solid); color: var(--select-solid-ink); box-shadow: none; }
/* 升降序箭头只给可排序的三项，「默认」保持纯文字 */
.ap-seg button.on.desc:not([data-k="default"])::after { content: " ↓"; font-size: 10px; }
.ap-seg button.on:not(.desc):not([data-k="default"])::after { content: " ↑"; font-size: 10px; opacity: .55; }

.ap-search {
  display: flex; align-items: center; gap: 8px; min-width: 190px;
  background: var(--paper-2); border: 0;
  border-radius: var(--radius-pill); padding: 6px 14px;
}
.ap-search svg { width: 15px; height: 15px; color: var(--ink-3); flex: 0 0 15px; }
.ap-search input {
  border: none; background: none; outline: none; width: 100%;
  font-size: 13px; color: var(--ink); font-family: inherit;
}
.ap-search input::placeholder { color: var(--ink-3); }

/* ---------- 文件行（对齐 .dk-row：独立白卡、14px 圆角、渐变图标块） ---------- */
.ap-list { display: flex; flex-direction: column; gap: 8px; }
.ap-row {
  display: flex; align-items: center; gap: 14px;
  background: #fff; border: 0; border-radius: var(--r-card);
  padding: 13px 16px; box-shadow: none;
  text-decoration: none; color: inherit; min-width: 0;
  transition: transform .18s, box-shadow .18s, border-color .18s, background-color .18s;
}
.ap-row:hover {
  transform: translateX(2px);            /* 与 .dk-row 一致：右移暗示「进入」，不做上浮 */
  background: var(--paper-2);
  border-color: rgba(17, 17, 17, .28);
  box-shadow: 0 4px 12px rgba(17, 17, 17, .08);
}
/* 图标块：渐变底 + 白色图形（原来是浅色底 + 彩色图形，与固件资源页相反） */
.ap-ico {
  display: grid; place-items: center; width: 40px; height: 40px; flex: 0 0 40px;
  border-radius: var(--r-card); color: #fff;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .08);
}
.ap-ico svg { width: 21px; height: 21px; }
.ap-ico.folder { background: linear-gradient(135deg, #5b8def, #7aa8f5); }
.ap-ico.blue   { background: var(--grad); }
.ap-ico.violet { background: linear-gradient(135deg, #7c5cf0, #a78bfa); }
.ap-ico.teal   { background: linear-gradient(135deg, #0e9aa7, #34c3cf); }
.ap-ico.gold   { background: linear-gradient(135deg, #d98407, #f0a92e); }
.ap-ico.gray   { background: linear-gradient(135deg, #7c8b9e, #9aa8b8); }
.ap-info { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.ap-name {
  font-size: 14.5px; font-weight: 600; color: var(--ink); line-height: 1.45;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ap-desc {
  font-size: 12px; color: var(--ink-3); line-height: 1.5;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* 右侧元信息按列对齐（体积 / 时间 / 下载次数），避免长短不一时挤成一团 */
.ap-meta {
  display: flex; align-items: center; gap: 16px; flex: 0 0 auto;
  font-size: 12.5px; color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.ap-meta b { min-width: 60px; text-align: right; font-weight: 600; color: var(--ink-2); }
.ap-meta span { min-width: 118px; text-align: right; }
.ap-meta em { min-width: 66px; text-align: right; font-style: normal; color: var(--ink-3); }
.ap-acts { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.ap-copy {
  display: grid; place-items: center; width: 32px; height: 32px; padding: 0;
  border: 1px solid transparent; border-radius: var(--r-ctl); background: var(--bg-gray);
  color: var(--ink-2); cursor: pointer; transition: .18s;
}
.ap-copy svg { width: 16px; height: 16px; }
.ap-copy:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
.ap-dl {
  display: inline-flex; align-items: center; gap: 5px; padding: 7px 14px;
  border-radius: var(--radius-pill); background: var(--brand); color: #fff;
  font-size: 12.5px; font-weight: 600; text-decoration: none; transition: .16s;
}
.ap-dl svg { width: 14px; height: 14px; }
.ap-dl:hover { background: var(--brand-ink); }
.ap-go {
  display: grid; place-items: center; width: 26px; height: 26px;
  border-radius: 50%; background: var(--bg-gray); color: var(--ink-3); transition: .16s;
}
.ap-go svg { width: 14px; height: 14px; }
.ap-row-dir:hover .ap-go { background: var(--brand); color: #fff; }

/* ---------- 空态 / 骨架 ---------- */
.ap-empty { padding: 56px 20px; text-align: center; }
.ap-empty-ico {
  display: grid; place-items: center; width: 52px; height: 52px; margin: 0 auto 12px;
  border-radius: var(--radius-lg); background: var(--paper-2); color: var(--ink-3);
}
.ap-empty-ico svg { width: 26px; height: 26px; }
.ap-empty p { font-size: 13.5px; font-weight: 600; color: var(--ink-2); margin: 0 0 5px; }
.ap-empty small { font-size: 12px; color: var(--ink-3); }
.ap-retry {
  margin-top: 14px; padding: 7px 18px; border-radius: var(--radius-pill);
  border: 1px solid var(--rule-2); background: var(--paper); color: var(--ink-2);
  font-size: 12.5px; font-weight: 600; cursor: pointer; font-family: inherit;
}
.ap-retry:hover { border-color: var(--brand); color: var(--brand); }
.ap-skel {
  height: 66px; border-radius: var(--r-card);
  background: var(--paper-2); animation: apPulse 1.4s ease-in-out infinite;
}
@keyframes apPulse { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }

/* ---------- 响应式 ---------- */
@media (max-width: 900px) {
  .ap-hero { margin-bottom: 22px; }
  .ap-hero h1 { font-size: 26px; }
  .ap-hero p { font-size: 14px; }
  .ap-card { padding: 14px 15px 16px; border-radius: var(--r-panel); }
  .ap-layout { grid-template-columns: 1fr; gap: 12px; }
  .ap-tree { display: none; max-height: 300px; overflow: auto; }
  .ap-tree.open { display: block; }
  .ap-tree-toggle { display: inline-flex; order: -1; }
  .ap-toolbar { padding: 0 0 10px; gap: 9px; }
  /* 窄屏下搜索框独占一行：与 4 个排序按钮挤在同一行会把 placeholder 截成「搜索」 */
  .ap-search { min-width: 0; flex: 1 1 100%; order: 3; }
  .ap-seg { margin-left: auto; }
  .ap-meta { display: none; }
  .ap-row { padding: 12px 13px; gap: 12px; }
  .ap-dl span { display: none; }
  .ap-dl { width: 34px; height: 34px; padding: 0; justify-content: center; }
  .ap-seg button { padding: 5px 11px; }
}

/* ---------- 深色模式 ---------- */
/* 卡片/行/目录树三层面在暗色下要拉开明度差：底 0d1014 < 卡 16191e < 行 1d2127 */
[data-theme="dark"] .ap-card { background: #1e1e1e; border-color: var(--rule-2); box-shadow: none; }
[data-theme="dark"] .ap-tree { background: #0b0b0c; }
[data-theme="dark"] .ap-tree-a:hover { background: rgba(255, 255, 255, .06); }
[data-theme="dark"] .ap-tree-a.on { background: rgba(255, 255, 255, .09); box-shadow: none; }
[data-theme="dark"] .ap-tree-cnt { background: rgba(255, 255, 255, .06); border-color: var(--rule-2); }
[data-theme="dark"] .ap-row { background: #242424; border-color: var(--rule-2); box-shadow: none; }
[data-theme="dark"] .ap-row:hover { background: rgba(255, 255, 255, .04); }
[data-theme="dark"] .ap-desc { color: var(--ink-3); }

/* ==========================================================================
   X219. 固件资源 · 更新时间徽标（/disk 列表行内）
   --------------------------------------------------------------------------
   主题里的 .badge 是「首屏胶囊」（padding 7px 16px / 13px 字号 / 玻璃阴影），
   直接套到列表行会把行高撑起来、显得笨重，故在 .dk-row-sub 作用域内收窄尺寸。
   四档配色走主题令牌：今日=绿、近3日=橙、近7日=紫、近14日=粉，深色模式自动跟随；
   紫 / 粉没有现成令牌，单独给一条深色覆盖保证对比度。
   档位类名由 app.js 的 updTier() 产出（upd-today / upd-3d / upd-7d / upd-14d）。
   ========================================================================== */
.dk-row-sub .badge.upd-today,
.dk-row-sub .badge.upd-3d,
.dk-row-sub .badge.upd-7d,
.dk-row-sub .badge.upd-14d {
  padding: 1px 8px;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.65;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  box-shadow: none;
  gap: 0;
  white-space: nowrap;
}
.dk-row-sub .badge.upd-today {
  color: var(--green);
  background: var(--green-wash);
  border-color: rgba(21, 127, 61, .22);
}
.dk-row-sub .badge.upd-3d {
  color: var(--amber);
  background: var(--amber-wash);
  border-color: rgba(180, 83, 9, .22);
}
.dk-row-sub .badge.upd-7d {
  color: #6d4bd8;
  background: rgba(124, 92, 240, .12);
  border-color: rgba(124, 92, 240, .22);
}
.dk-row-sub .badge.upd-14d {
  color: #c62a76;
  background: rgba(244, 114, 182, .13);
  border-color: rgba(214, 42, 118, .22);
}
[data-theme="dark"] .dk-row-sub .badge.upd-7d {
  color: #b39bff;
  background: rgba(124, 92, 240, .18);
  border-color: rgba(124, 92, 240, .32);
}
[data-theme="dark"] .dk-row-sub .badge.upd-14d {
  color: #f78cb4;
  background: rgba(244, 114, 182, .18);
  border-color: rgba(244, 114, 182, .32);
}

/* ==========================================================================
   X220. 首页资源榜单（固件 / 应用资源）
   --------------------------------------------------------------------------
   两个区块从「4 列缩略卡 + 序号攻略卡」统一成 .dk-list + .dk-row，
   与 /disk、/apps 列表同一套语言：白卡行、渐变图标、类型标签、时效徽标。
   行组件本身完全复用，这里只补首页特有的间距与「近 7 天 N 次下载」小注。
   ========================================================================== */
/* 区块头（.sec-head）自带下边距，行列表别再叠 .dk-list 默认的 16px */
.home .dk-list.home-res { margin-top: 2px; }

/* 翻页淡入：原来挂在 .hot-dl .grid 上，改版后容器是 .dk-list */
.hot-dl .dk-list { animation: hotDlFade .4s ease; }

/* 「近 7 天 N 次下载」：跟在时效徽标后面，弱化但不至于看不见 */
.dk-row-stat {
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.dk-row-stat::before { content: '·'; margin-right: 7px; opacity: .5; }

/* 补齐项（最近更新）的徽标与下载量不并排时，行高保持一致 */
.home-res .dk-row { padding-top: 12px; padding-bottom: 12px; }

@media (max-width: 900px) {
  /* 移动端每页 3 行，行距略收，两页高度接近一屏 */
  .home .dk-list.home-res { gap: 8px; }
  .home-res .dk-row { padding-top: 11px; padding-bottom: 11px; }
}

/* 深色：通用次级按钮不能白底白字 */
[data-theme="dark"] .btn:not(.primary):not(.danger):not(.ghost) { background: var(--panel); color: var(--ink); }
/* ==========================================================================
   X36. 认证页（登录 / 注册 / 找回 / 强制改密）· 方案 A 规范化（2026-11-03）
   --------------------------------------------------------------------------
   独立整页（.authpage 一屏铺满）；卡片合规：零边框零阴影、圆角 Card(14)、
   纯白卡；头部改全站统一「kicker + 4×14 竖条标题 + 说明」；分段走全站标准
   （组底深一档 + Control 项 + 实心反相选中）；主按钮实心反相不上浮；
   输入框灰面 / 焦点白面 + 1.5px 内描边（不用 border）。
   本段位于文件末尾，压过 X18 / X62 与既有认证覆盖段。
   ========================================================================== */
.authpage .authpage__card {
  border: 0; border-radius: var(--r-card);
  background: var(--paper);
  box-shadow: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
  padding: 20px;
}
.authpage__hd { text-align: left; margin: 0 0 16px; }
.authpage__kicker {
  display: block; color: var(--ink-3);
  font-size: 11px; font-weight: 600; line-height: 1.4;
  letter-spacing: .08em; text-transform: uppercase;
}
.authpage__title {
  display: flex; align-items: center; gap: 8px;
  margin: 4px 0 8px; color: var(--ink);
  font-size: 20px; font-weight: 700; line-height: 1.3;
}
.authpage__title::before {
  content: ""; flex: none; width: 4px; height: 14px;
  border-radius: 2px; background: var(--ink);
}
.authpage__sub { margin: 0; color: var(--ink-2); font-size: 13px; line-height: 1.65; }

.authpage .authtabs {
  display: inline-flex; gap: 2px; padding: 3px;
  border-radius: calc(var(--r-ctl) + 2px); background: var(--seg-bg);
  margin-bottom: 16px;
}
.authpage .authtabs__item {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  height: 30px; padding: 0 12px; border: 0; border-radius: var(--r-ctl);
  background: transparent; color: var(--ink-2);
  font-size: 12.5px; font-weight: 400; text-align: center; text-decoration: none;
  transition: background-color .12s, color .12s;
}
.authpage .authtabs__item:hover { background: var(--seg-hover); color: var(--ink); }
.authpage .authtabs__item.is-on { background: var(--select-solid); color: var(--select-solid-ink); font-weight: 600; }

.authpage__body .form-row input,
.authpage__body .form-row select {
  border: 0; border-radius: var(--r-ctl);
  background: var(--gray-wash); color: var(--ink);
  box-shadow: none;
}
.authpage__body .form-row input:focus {
  background: var(--paper); box-shadow: inset 0 0 0 1.5px var(--ink);
}
.authpage__body .pwd-eye:hover { background: var(--seg-hover); }
.authpage__body .code-row .btn {
  border: 0; border-radius: var(--r-ctl);
  background: var(--gray-wash); color: var(--ink-2);
}
.authpage__body .code-row .btn:hover:not(:disabled) { background: var(--seg-hover); color: var(--ink); }

.authpage__actions { gap: 8px; margin-top: 16px; }
.authpage__actions .btn {
  border-radius: var(--r-ctl); padding: 11px 16px; font-size: 14px; font-weight: 600;
  box-shadow: none; transform: none;
}
.authpage__actions .btn.primary {
  background: var(--select-solid); color: var(--select-solid-ink); border: 0; box-shadow: none;
}
.authpage__actions .btn.primary:hover:not(:disabled) {
  background: var(--select-solid-hover); color: var(--select-solid-ink); transform: none; box-shadow: none;
}
.authpage__actions .btn:not(.primary) { background: var(--gray-wash); color: var(--ink-2); }
.authpage__actions .btn:not(.primary):hover:not(:disabled) { background: var(--seg-hover); color: var(--ink); }
.authpage__alt { font-size: 12.5px; }
.authpage__alt a { color: var(--ink-2); }
.authpage__alt a:first-child { color: var(--ink); font-weight: 600; }

.authpage .auth-success__badge {
  border-radius: var(--r-card); background: var(--select-solid); color: var(--select-solid-ink);
  box-shadow: none;
}
.authpage .auth-success__tip { font-size: 13px; }
.authpage .auth-success__link { color: var(--ink-3); }
.authpage .auth-success__link:hover { color: var(--ink); }
/* 账号可用性指示点 / 协议勾选行的旧蓝灰残留 → 中性灰（绿/红状态色保留） */
.authpage .ucheck__dot { background: var(--rule); }
.authpage .ucheck.is-checking .ucheck__dot { border-color: var(--rule); border-top-color: var(--ink); }
.authpage .terms-row.is-required { color: var(--ink-2); }
