@charset "utf-8";
/* ==========================================================================
   QiuQuan's Blog — PbootCMS 前端模板样式
   主题：专业蓝 · 柔和琥珀 · 简洁通透
   全站视觉的唯一来源 = 下面的 :root；改主题只改这一块 + 少数组件级派生值。
   ========================================================================== */

/* ---------- 1. 设计令牌 ----------
   ★ 对比度约定（WCAG 2.2 AA），**别凭好看乱用**：
     · --c-primary  #007BFF  白底 3.98:1 → **只能用于非文本角色**
       （色块 / 描边 / 激活图形 / 图标），满足 SC 1.4.11 的非文本 3:1。
     · 一切**文字**（链接、强调、实心按钮底）用 --c-primary-dark #0B63D7，白底 5.56:1。
       把 --c-primary 拿去写 13~14px 的链接会直接踩 AA 4.5:1 的红线。
     · --c-text-body #55616F（页底 5.82:1）/ --c-text-muted #64717F（页底 4.60:1）——
       两级都过 AA，muted 承载 12px 的元信息文字，不是「装饰灰」。
   ★ **色相轴取自参考图 `_ref/ref-anchor-blue.png`（纯色蓝锚点）**：
     主体 H211° 蔚蓝、文字级 H214° 深靛蓝、点缀 H38° 柔和琥珀。
     参考图是 43×40 的**纯色块**（全图只有 1 个颜色，占比 100%），
     `tools/analyze_anchor_blue.py` 量化得 `#007BFF` —— 「什么蓝」由它定；
     「多深」由 WCAG 二分求解定（`tools/derive_blue_palette.py`）。
     完整色值表、对比度证明与组件映射见根目录 `PALETTE-anchor-blue.md`。
     ★ 参考图只有**一个蓝色、没有任何暖色**，所以点缀色是**设计选定**的柔和琥珀：
       冷蓝主体 + 一点暖色是编辑部式的经典搭配，且置顶 / 推荐徽标不会与链接蓝混淆。
       **警示红是语义色，独立保留**。
   ★ 阴影一律用低透明度**深靛蓝** rgba(11,99,215,·)，不要用灰色投影 ——
     灰投影压在浅蓝底上会显脏、显重，与「简洁通透」正相反。
   ★ 栅格（--container / --sidebar-w / --gap）保持与参考站一致，动一格全站错位。
   ★ **交互状态和颜色一样，只能有一个来源**：过渡时长走 --t-fast、按压幅度走 --press、
     禁用走 [disabled] 属性、表单组高亮走 :focus-within，不要在组件里另造一套。
     覆盖率由 tools/audit_interaction_states.py 体检 —— 它**展开 @media**，
     断点里的状态同样在检查范围内。 */
:root {
  /* 页面背景 —— 底色并非纯色，而是一层极淡的亚麻纹理（实测 mean=238.7 std=2.10）。
     纹理是灰阶低透明度噪声，会自动透出新底色，因此换主题不必重做纹理。
     完全不想要纹理时把 --bg-image 置为 none 即可。 */
  --bg-image: url(../images/bg-texture.png);
  /* 二维码中心的小圆标（打赏弹窗用）。与 --bg-image 同理写成令牌：
     预览渲染器会把 `url(../images/` 整体改写成 `url(preview-assets/`，写死路径就漏改了。 */
  --qr-logo: url(../images/logo.svg);

  /* ---------- 1.1 图标（内联 SVG + mask + currentColor，零字体零图片依赖） ----------
     全站图标必须是同一套「细线条」语言。
     ★ 曾经用 emoji（🏠🖥📱💻🎮📄❤）：彩色、由系统字体渲染，与低饱和配色放一起极跳脱，
       其中 ℹ️ 在 Windows 下更是渲染成一块实心蓝方块。已全部改为下面的线性 SVG。 */
  --ico-cat: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M17 3H7a2 2 0 0 0-2 2v16l7-3 7 3V5a2 2 0 0 0-2-2z'/%3E%3C/svg%3E");
  --ico-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M16.5 16.5 21 21'/%3E%3C/svg%3E");
  --ico-home: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 10.5 12 3.5l9 7M5.5 9.5V20h13V9.5M10 20v-5.5h4V20'/%3E%3C/svg%3E");
  --ico-monitor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='10.5' rx='1.5'/%3E%3Cpath d='M9.5 20h5M12 15.5V20'/%3E%3C/svg%3E");
  --ico-phone: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='7' y='2.5' width='10' height='19' rx='2.5'/%3E%3Cpath d='M10.5 18.5h3'/%3E%3C/svg%3E");
  --ico-laptop: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4.5' y='4.5' width='15' height='11' rx='1.5'/%3E%3Cpath d='M2 19.5h20l-1.6-3.5H3.6z'/%3E%3C/svg%3E");
  --ico-gamepad: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.5' y='7.5' width='19' height='10' rx='4.5'/%3E%3Cpath d='M8 10.8v3.4M6.3 12.5h3.4M16 11.6h.01M18 13.6h.01'/%3E%3C/svg%3E");
  --ico-doc: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 3h7l4.5 4.5V21h-11.5z'/%3E%3Cpath d='M13.5 3v4.5H18M9.5 12.5h5M9.5 16h5'/%3E%3C/svg%3E");
  --ico-heart: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20.5S3.5 15.2 3.5 9.7A4.7 4.7 0 0 1 12 6.9a4.7 4.7 0 0 1 8.5 2.8c0 5.5-8.5 10.8-8.5 10.8z'/%3E%3C/svg%3E");
  /* 卡片元信息「赞」/ 内容页按钮 / 404 空状态，同一套 mask 手法 */
  --ico-thumb: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.3a2 2 0 0 0 2-1.7l1.4-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3'/%3E%3C/svg%3E");
  /* 「已赞」态用的实心版本：与上面**同一个 path**，只把 stroke 换成 fill。
     用途见 .btn-primary.is-liked —— 状态不能只靠颜色区分（SC 1.4.1），
     而「线性 → 实心」是零尺寸变化的形变，不会让按钮宽度跳一下。 */
  --ico-thumb-on: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Cpath d='M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.3a2 2 0 0 0 2-1.7l1.4-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3'/%3E%3C/svg%3E");
  --ico-compass: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9.2'/%3E%3Cpath d='M16 8l-2.2 6.6L7.2 16.8 9.4 10.2z'/%3E%3C/svg%3E");
  --ico-close: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E");

  /* ---------- 1.2 色彩 ----------
     ★ 本段色阶**不是手挑的**：色相照抄参考图 `_ref/ref-anchor-blue.png`（H211° 蔚蓝），
       文字级再冷 3°（H214° 深靛蓝），点缀为设计选定的 H38° 柔和琥珀；
       明度用二分搜索解到与**上一版相同的对比度**（脚本 tools/derive_blue_palette.py）。
       所以观感是「换了颜色」，层次与可读性一分没动 —— 换色不改调。
       完整色值表 / 对比度证明 / 组件映射见根目录 PALETTE-anchor-blue.md。 */
  --c-primary: #007BFF;         /* 主色 蔚蓝（装饰/图形，3.98:1 —— 非文本角色专用） */
  --c-primary-bright: #4EA4FF;  /* 再亮一档：标题竖条 / 圆点等纯装饰 */
  --c-primary-dark: #0B63D7;    /* 深主色 深靛蓝：文字级强调 / 链接 / 实心按钮底（5.56:1） */
  --c-primary-light: #E3EBF5;   /* 浅主色：标签底 / 标题分隔线 / 占位图底 */
  --c-primary-soft: #F6F9FC;    /* 极浅主色：hover 底 / 区块底 */

  --c-btn: #0B63D7;             /* 主按钮底（白字 5.56:1） */
  --c-btn-hover: #0950AE;

  --c-accent-light: #FBF2E1;    /* 柔和琥珀（点缀色）：浅底 —— 参考图只有单一蓝色，点缀色为设计选定 */
  --c-accent-dark: #895D11;     /* 琥珀：浅底上的深色文字（5.19:1） */
  --c-accent: #DA9B2F;          /* 琥珀：纯装饰（设计选定的暖点缀 —— 只配图标，不承载文字） */
  --c-accent-hover: #F5E2C2;    /* 琥珀浅底的 hover：比 --c-accent-light 深一档 */

  --c-danger: #C34242;          /* 柔玫瑰红：只为「警示」，不做装饰；语义色独立于主题，本次仅修对比度 */
  --c-danger-bg: #FCF4F4;
  /* 刻意不设 --c-success / --c-warning：全站目前没有任何「成功 / 警告」语义的元素，
     不预先造空令牌。将来要用，请连同 verify_* 的对比度清单一起加。 */

  --c-bg: #F3F6F9;              /* 页面底色（极淡蓝灰） */
  /* --c-card = 全站**所有白色表面**的唯一来源：卡片、页头、下拉面板、分页页码、
     搜索框、二维码白底…… 组件里一律写 var(--c-card)，**不要再写字面量 #fff**
     （写了就等于绕开令牌，改主题时这一处会漏掉）。 */
  --c-card: #ffffff;
  /* --c-on-dark = 压在任何**深色实底**上的白色前景（主按钮底 / 深主色块 / 警示块）。
     与 --c-card 分开：一个是「白面」，一个是「深底上的白字」，将来把按钮换成浅底时只改这一处。 */
  --c-on-dark: #ffffff;
  /* ★ 这里原本是 --c-overlay（模态弹窗背后那层「压暗背景」的深靛蓝半透明）。
     2026-09-22 按需求「去除背景遮罩」**删除**：三处弹窗（打赏 / 点赞提示 / 会员登录）
     打开时页面不再被压暗，分离层次改由对话框自身的 --shadow-modal 承担。
     ★ 别加回来：check_palette_sync.py 有一条防回潮断言（三处遮罩必须不着色），
       加了就会红。 */
  --c-border: #E1E8EF;          /* 常规描边（极淡蓝灰 —— 分层靠它，不靠阴影） */
  --c-border-light: #F0F3F6;    /* 更浅：列表分隔线 */
  --c-border-strong: #CCD6E1;   /* 深一档：需要明确「有框」时（下拉面板 / 输入框） */

  --c-text: #333B44;            /* 标题（白底 11.35:1） */
  /* 正文 / 次要文字 —— 两级都按「正文语义」要求过 WCAG AA 4.5:1。
     ★ 约束面取**页面底色 #F3F6F9**（比纯白更暗，是这两个色实际承载的最不利浅底）：
         --c-text-body  #55616F → 页底 5.82:1 / 白底 6.31:1
         --c-text-muted #64717F → 页底 4.60:1 / 白底 4.99:1
       ★ 为什么 muted 不再更浅：它承载的是 12px 的**信息性文字**（元信息 / 时间 / 页脚 / 面包屑），
         属正文语义，不能拿 3.x:1 蒙混。上一版 #7C8C87（白底 3.52 / 页底 3.29）以及更早的 #999，
         都不到线。要更浅的灰只能用于**纯装饰**（分隔线 / 描边），不要拿来写字。
       ★ 两级之间用 ΔL≈0.059 拉开层次：正文与次要文字的区分靠**这一档色差 + 字号**，
         不要为了「更淡」把 muted 调回去 —— 那会直接踩 AA 红线。
       ★ 换色时这两级的明度是**分别解到上一版（绿色鱼）的实测比值**的 —— 具体数字不写死在这里，
         见 `_ref/palette-history/green-fish.txt` 与 `tools/derive_blue_palette.py` 的 `OLD` 字典。
         若两级都只要求「≥4.5」，会解出两个几乎同色的蓝，把正文与次要文字的层次压平。 */
  --c-text-body: #55616F;
  --c-text-muted: #64717F;
  /* 刻意不设 --c-link：链接色统一取 --c-primary-dark，避免同一件事有两个来源。 */

  /* ---------- 1.3 栅格（与参考站一致，不要动） ----------
     参考站：.container{max-width:1250px}（站点自定义 CSS 覆盖了主题的 1240）
             .content{margin-right:380px} / .sidebar{width:370px}
             → 主栏 1250-380 = 870，主栏与侧栏的净间隙 = 380-370 = 10 */
  --container: 1250px;
  --sidebar-w: 370px;
  --gap: 10px;
  --card-gap: 12px;             /* 卡片/模块之间的纵向间距（原 10px，本主题放宽一档） */
  --topbar-h: 36px;
  /* 侧栏卡片内统一水平内边距：栏目标题 / 列表项 / 搜索框 / 卡片体全部对齐到这条线。
     ★ 只有这一条基准线 —— 绝不要在同一卡片里给标题和列表项写两个不同的水平内边距。 */
  --side-pad: 24px;

  /* ---------- 1.4 圆角（分层，别到处写死像素） ---------- */
  --radius-sm: 6px;             /* 小元素：标签 / 缩略图 / 输入框 / 页码 */
  --radius: 10px;               /* 默认：卡片 / 按钮 / 面板 */
  --radius-lg: 14px;            /* 大块：正文容器 / 下拉浮层 */
  --radius-pill: 999px;         /* 胶囊 */

  /* ---------- 1.5 字体刻度（中文正文 14px 基准） ----------
     ★ 刻度必须**闭合**：文件里每一个 font-size 都要能指回下面某一档。
       「这个位置 15px 正好」写成一个字面量看似无害，代价是下一轮想整体调档时
       只能 grep 逐个猜，而「谁比谁大一级」也再没人能一眼看懂。
       守这条的是 tools/audit_interaction_states.py 的【4】：裸 px 字号必须为 0。 */
  --fs-2xs: 11px;               /* 窄屏徽标下限（中文 11px 是可读下限；参考站原值 10px 已过低） */
  --fs-xs: 12px;
  --fs-sm: 13px;
  --fs-base: 14px;
  --fs-md: 15px;                /* 正文与标题之间：搜索输入框 / 侧栏栏目标题 */
  --fs-lg: 16px;
  --fs-title: 18px;             /* 卡片标题（.article-title）与站点字标 */
  --fs-xl: 20px;
  --fs-2xl: 22px;               /* 独立页（登录 / 注册）主标题 */
  --fs-h1: 24px;                /* 内容页 / 单页 h1 */
  --fs-icon: 18px;              /* **图形字符**的字号（返回顶部的 ↑）——
                                   它定的是一个 18×18 的图形，不是一段 18px 的句子，
                                   所以单列一档，不并进标题刻度里。 */
  /* 本主题的「轻」靠行高与留白，不是靠把字号调大。
     ★ 标题字重统一 500：微软雅黑只有 Regular/Bold 两档，500 会匹配到 Regular，
       比 700 轻一档 —— 这正是要的效果，别改回 700。 */
  --fw-title: 500;
  --lh-base: 1.7;
  --lh-loose: 1.9;

  /* ---------- 1.6 动效与阴影 ---------- */
  --t-fast: .18s ease;
  /* 按压反馈的**唯一**幅度：所有盒子型控件共用同一个 scale。
     手感不一致最常见的来源，就是「每个组件各自挑一个按下去的比例」。
     （文本型链接不用它，用 1px 下压 —— 见 .nav-menu > li > a:active） */
  --press: .96;
  /* 二级下拉的原始时长（参考站 .site-nav .sub-menu 的 transition: all .3s ease-in-out）。
     下拉带 25px 位移，比通用微交互慢一档才不显生硬，故单列一个令牌。 */
  --t-slow: .3s ease-in-out;
  /* 阴影一律用**主题色相的深靛蓝** rgba(11,99,215,·)，不用灰色 ——
     灰投影压在浅蓝底上会显脏显重，与「简洁通透」正相反。改主题时这三条必须跟着走。 */
  --shadow-sm: 0 1px 2px rgba(11, 99, 215, .04);      /* 「近乎无阴影」，只给一点点体积感 */
  --shadow-md: 0 6px 20px rgba(11, 99, 215, .08);     /* 浮层 */
  --shadow-lg: 0 10px 30px rgba(11, 99, 215, .10);    /* 返回顶部等悬浮件 */
  /* ★ --shadow-modal 只给模态对话框用（打赏 / 点赞提示 / 会员登录三处）。
     为什么必须比 --shadow-lg 重得多：这三处弹窗**没有压暗背景的遮罩**（见上方 :root 里的说明），
     对话框是直接浮在正文与白卡片上的 —— 白底压白底，本来就看不出边界，
     只靠 --shadow-lg 那 10% 的投影会像「贴」在页面上而不是「浮」在上面。
     现在两层：① 一圈 1px 的 hairline 交代边界；② .22 的主题色深投影拉开高度差。
     ★ 第一段 `0 0 0 1px` 是**描边**，刻意用 box-shadow 而不是 border：
       border 会占宽高 —— 390px 窄屏下对话框内容宽少 2px，两个收款码会正好被挤到
       100px 以下，verify_reward_modal.js 组 7 的那条「≥100px 才扫得动」会红。
       box-shadow 不参与布局，和 .rq-logo 的白圈是同一个理由。 */
  --shadow-modal: 0 0 0 1px rgba(11, 99, 215, .10), 0 24px 60px rgba(11, 99, 215, .22), 0 4px 14px rgba(11, 99, 215, .10);
}

/* ---------- 2. 基础重置 ---------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background-color: var(--c-bg);
  background-image: var(--bg-image);
  background-repeat: repeat;
  background-attachment: scroll;
  color: var(--c-text-body);
  font-family: "Microsoft YaHei", "微软雅黑", "PingFang SC", "Hiragino Sans GB", "Helvetica Neue", Arial, sans-serif;
  font-size: var(--fs-base);
  /* 中文正文行高从 1.6 放到 1.7；本主题的「松」主要来自这里 */
  line-height: var(--lh-base);
  /* 中文略微放宽字距，是「清新通透」观感的重要来源 */
  letter-spacing: .3px;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 { margin: 0; font-weight: var(--fw-title); color: var(--c-text); }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img { max-width: 100%; vertical-align: middle; border: 0; }
a { color: var(--c-text); text-decoration: none; transition: color var(--t-fast); }
a:hover { color: var(--c-primary-dark); }
button { font-family: inherit; cursor: pointer; border: 0; background: none; }
input, textarea { font-family: inherit; font-size: var(--fs-base); }

:focus-visible { outline: 2px solid var(--c-primary); outline-offset: 2px; }

/* ---------- 3. 布局容器 ---------- */
/* 参考站 .container 无横向内边距（内容宽 = 1250），窄屏才补上留白 */
.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
}

.main-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--sidebar-w);
  gap: var(--gap);
  align-items: start;
  margin-top: 10px;
  padding-bottom: 20px;
}

.main-content { min-width: 0; }
.sidebar { min-width: 0; }

/* ---------- 4. 顶部工具条 ---------- */
.top-bar {
  height: var(--topbar-h);
  background: var(--c-primary-soft);
  border-bottom: 1px solid var(--c-border-light);
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}
.top-bar .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 100%;
}
.tb-left, .tb-right { display: flex; align-items: center; gap: 14px; }
.top-bar a { color: var(--c-text-muted); }
.top-bar a:hover { color: var(--c-primary-dark); }
.tb-hi { color: var(--c-text-muted); }

/* ---------- 5. 头部与导航 ---------- */
/* position:relative 是给「全宽搜索面板」当定位锚点的（面板用 top:100% 贴在页头下沿） */
.site-header { position: relative; background: var(--c-card); border-bottom: 1px solid var(--c-border); }

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 74px;
  gap: 20px;
}

.site-logo { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.logo-img { width: 42px; height: 42px; display: block; border-radius: var(--radius); }
.logo-text { display: flex; flex-direction: column; line-height: 1.25; }
.logo-text strong {
  font-size: var(--fs-title);
  font-weight: var(--fw-title);
  color: var(--c-text);
  letter-spacing: .2px;
}
.logo-text em {
  font-style: normal;
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}

.main-nav { display: flex; align-items: center; gap: 4px; position: relative; }

.nav-menu { display: flex; align-items: center; }
.nav-menu > li { position: relative; }
/* ★ 栏目字号 16px（原 15px）、左右内边距 15px（原 14px）—— 需求：导航文字放大一档。
   与图标一起算，导航行总增约 +52px；由「移除页头登录入口」省下的宽度抵消后仍有余量
   （992px 实测留白 61.5px、溢出 0，见 tools/_measure_nav_width.js）。 */
.nav-menu > li > a {
  display: block;
  padding: 0 15px;
  height: 74px;
  line-height: 74px;
  font-size: var(--fs-lg);
  color: var(--c-text-body);  /* 比 --c-text 轻一档，让导航不抢标题的注意力 */
  white-space: nowrap;
  /* ★ 必须**连 color 一起**声明：transition 不是继承属性，而本规则比全局的
     `a { transition: color }` 更具体 —— 只写 transform 会把那条颜色过渡整个顶掉，
     导航文字的 hover 就会从「渐变」退回「瞬变」。 */
  transition: color var(--t-fast), transform var(--t-fast);
}
.nav-menu > li > a:hover { color: var(--c-primary-dark); }
/* 文本型链接的按压反馈是**下压 1px**，不是 scale —— 这条链接是撑满 74px 行高的块，
   整体缩放看起来是「整行在缩」；1px 下压才像手指按下去。
   它与盒子型控件的 scale(var(--press)) 是同一套手感语言的两半。 */
.nav-menu > li > a:active { transform: translateY(1px); }
.nav-menu > li.active > a { color: var(--c-primary-dark); font-weight: var(--fw-title); }

/* ---------- 导航图标 ----------
   参考站是「每个菜单项自带 FontAwesome 类」：
     首页 fa-home · 电脑软件 fa-windows · 安卓软件 fa-android · 单机游戏 fa-gamepad · 赞助 fa-heart
   本模板没有图标字体，改为**内联 SVG + mask** 的线性图标（与 --ico-search / --ico-cat 同一套手法）：
   零字体、零图片依赖，且上色取 currentColor —— 于是**图标会跟着链接颜色一起变**（hover 变主色）。
   这是本主题观感提升最大的一步：全站图标共用一套细线条语言。

   ★ 配色规则：图标是「非文本角色」，受 WCAG SC 1.4.11 非文本 3:1 约束。
     常态跟随链接色 --c-text-body(#55616F，白底 6.31:1)，hover 变 --c-primary-dark。
   ★ 不要改回 `:nth-child` 按位置匹配 —— 后台增删/排序栏目时图标会整体错位
     （实测：在「安卓软件」后插入一个栏目，「单机游戏」就丢掉图标、新栏目反而拿到）。
   ★ 用 `*=`（包含）而不是 `=`（全等）匹配：后台栏目名常见的「尾随空格 / 后缀词」
     （如「操作系统 」「操作系统教程」）在 `=` 下会静默不命中 → 该栏目裸奔没图标。
   ★ **未配图标的栏目必须完全不可见且不占位**。做法是把尺寸也做成变量：
     --ico-size 缺省为 0 → 盒子 0×0、--ico-gap 缺省 0 → 无外边距，于是「什么都不生成」。
     ⚠️ 不要改成「给所有项都画 18×18 再用空 SVG 遮掉」—— 那样未配图标的栏目会在文字前
       留出 25px 空档，线上看起来就是「这个栏目莫名缩进了」。
   ★ 尺寸 18px / 间距 7px（原 16px / 6px）—— 与栏目标题字号一起放大的那一档。
   ★ 想给新栏目配图标：只加一行「--ico 指向哪个图形 + 尺寸 + 间距」，不要重复整套 ::before。 */
.nav-menu > li > a::before {
  content: "";
  display: inline-block;
  width: var(--ico-size, 0);
  height: var(--ico-size, 0);
  margin-right: var(--ico-gap, 0);
  vertical-align: -3px;
  background-color: var(--ico-color, currentColor);
  -webkit-mask: var(--ico) center / contain no-repeat;
  mask: var(--ico) center / contain no-repeat;
}
.nav-menu > li > a[data-nav*="首页"]     { --ico: var(--ico-home);    --ico-size: 18px; --ico-gap: 7px; }
.nav-menu > li > a[data-nav*="电脑软件"] { --ico: var(--ico-monitor); --ico-size: 18px; --ico-gap: 7px; }
.nav-menu > li > a[data-nav*="安卓软件"] { --ico: var(--ico-phone);   --ico-size: 18px; --ico-gap: 7px; }
.nav-menu > li > a[data-nav*="操作系统"] { --ico: var(--ico-laptop);  --ico-size: 18px; --ico-gap: 7px; }
.nav-menu > li > a[data-nav*="单机游戏"] { --ico: var(--ico-gamepad); --ico-size: 18px; --ico-gap: 7px; }
/* 「关于」同时覆盖后台可能出现的「关于本站 / 关于我们」两种命名。
   参考站的「赞助」是非栏目项也给了图标（fa-heart）→ 非栏目项并非不能有图标。 */
.nav-menu > li > a[data-nav*="关于"]     { --ico: var(--ico-doc);     --ico-size: 18px; --ico-gap: 7px; }
/* 唯一保留色彩的图标：琥珀心形，作为整条导航里的一点暖色停顿。
   图标是「唯一可见内容」时不许这么干（那时受 3:1 约束），但这里文字才是主要内容，
   图标纯装饰 → 允许低对比，与正文色并列反而是点睛。 */
.nav-menu > li > a[data-nav*="赞助"]     { --ico: var(--ico-heart);   --ico-size: 18px; --ico-gap: 7px;
                                           --ico-color: var(--c-accent); }

.nav-menu .caret::after {
  content: "";
  display: inline-block;
  width: 0; height: 0;
  margin-left: 5px;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  vertical-align: middle;
  /* 展开时翻转 180°（参考站 .site-nav>li.menu-item-has-children:hover a::after 同款） */
  transition: transform var(--t-slow);
}

/* 二级下拉（桌面 ≥992px：hover 展开的绝对定位浮层）
   ★ 数值有两个来源，**不要混用**：
     · 布局（定位 / 内边距 / 条目节拍 / 展开动画）沿用参考站线上样式表
       （_ref/ref-dux.css 的 `.site-nav .sub-menu`），并与参考站截图交叉校验一致：
       条目节拍 33.6px（= 14×1.4 行高 + 7×2 内边距），两处严丝合缝。
     · 面板「外观」（描边 / 圆角 / 字色）已改由**本主题令牌**接管：
       --c-border-strong / --radius-lg / --c-text-body。宽度保持 140px（上一轮按用户
       给出的参考图实测确定）。
       ⚠️ 下拉框是页面的一部分，**全站换主题时不能把它落下** —— 否则浅蓝底色的页面里
       会孤零零飘着一块灰色直角浮层。
       ⚠️ 这里曾按那张参考图做过「直角 + #ccc 描边」；「全站统一为本主题」的指令已覆盖它。
   量新截图：`python tools/measure_subnav_ref.py <图> --panel-left N --panel-right M` */
.sub-menu {
  position: absolute;
  top: 100%;
  left: 50%;
  /* 水平居中 + 6.5px 左偏（参考站原式是写死的 `margin-left: -86.5px` = -(160/2) - 6.5）。
     拆成「translateX(-50%) 居中 + margin-left 补偏移」：视觉与参考站一致，
     面板宽度改过（160 → 140）也不会静默失准。 */
  margin-left: -6.5px;
  width: 140px;
  padding: 6px 0;
  background: var(--c-card);
  /* 全局 `box-sizing: border-box`，所以这 140px 已含左右各 1px 描边，内层 138px */
  /* 本主题：描边改用浅蓝灰、圆角放大到 --radius-lg。
     上一轮按用户给的参考图做过「直角 + #ccc 描边」，本轮的「全站统一」指令已覆盖它。 */
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  font-size: var(--fs-base);
  line-height: 1.4;
  text-align: center;
  list-style: none;
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, -25px);
  transition: opacity var(--t-slow), transform var(--t-slow), visibility var(--t-slow);
  z-index: 60;
}
/* 面板顶部的小尖角：双层伪元素叠出「描边 + 白色填充」的箭头（参考站同款手法，仅换描边色）。
   ★ 面板有 1px 描边时，`top:-5px` 是相对 **padding box** 的，于是白色那层正好落在那条描边上、
     把描边「切开」—— 参考图实测就是这样（描边行在三角处是纯白 255）。
   ★ 三角中心比面板中心偏右约 2px，由 `left:50%; margin-left:-3px` 天然得到，别再手动加偏移。 */
.sub-menu::before,
.sub-menu::after {
  content: "";
  position: absolute;
  top: -5px;
  left: 50%;
  margin-left: -3px;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
}
.sub-menu::before { border-bottom: 5px solid var(--c-border-strong); }
.sub-menu::after { border-bottom: 5px solid var(--c-card); margin-top: 1px; }

.sub-menu li { display: block; }
.sub-menu li > a {
  display: block;
  padding: 7px 10px;
  font-size: var(--fs-base);
  /* 条目字色 = --c-text-body。实测参考图为 (102,102,102)=#666，本主题统一到 #55616F：
     白底 6.31:1、蔚蓝 hover 底上 4.62:1，均满足正文 4.5:1。 */
  color: var(--c-text-body);
  /* 只声明 background：本条的 hover 只换底色、文字色刻意不动（见下一条）。
     少了它，浅蓝底会「啪」地出现 —— 整条导航里最容易被察觉的毛刺就在这里。 */
  transition: background var(--t-fast);
}
/* 「当前栏目」高亮 = 参考站 `.site-nav li.current-menu-item > a { color: var(--tb--main) }`。
   ★ 必须写在 hover 规则**之前**：参考站里 hover 的选择器权重更高（.site-nav .sub-menu a:hover），
     hover 时会把颜色压平，只留浅灰底。顺序反了就会「hover 当前项仍然发蓝」。 */
.sub-menu li.active > a { color: var(--c-primary-dark); }
/* hover 只加一层**极浅蓝底**、文字色不变（参考站原本是 #f4f4f4 灰底 + 文字保持常态色）。
   文字变主色是留给「当前栏目」的，不是 hover 态 —— 别顺手改成 hover 变色。 */
.sub-menu li:hover > a,
.sub-menu li > a:hover { color: var(--c-text-body); background: var(--c-primary-soft); }
/* 按压再深一档（--c-primary-soft → --c-primary-light）。
   ★ 用 :active 而不是 JS 加类：鼠标按下与键盘 Enter 都会触发它，零 JS 成本。 */
.sub-menu li > a:active { background: var(--c-primary-light); }

/* ★ hover 展开必须限定在 ≥992px。折叠态（≤991px）改走「.sub-toggle 点按展开」，
   若不限定，触摸端 tap 会触发 :hover 把 visibility 强制成 visible —— 折叠当场失效。 */
@media (min-width: 992px) {
  .nav-menu > li:hover > .sub-menu {
    opacity: 1;
    visibility: visible;
    transform: translate(-50%, 0);
  }
  /* 展开时触发项的 ▾ 翻上去（参考站同款反馈） */
  .nav-menu > li:hover > .caret::after { transform: rotate(180deg); }
}

/* 折叠态二级栏目的展开按钮：桌面端不出现（那一档用 hover），≤991px 才显示。
   隐藏用 display:none 而非 visibility —— 视觉与 Tab 顺序同时移除，不留可聚焦的空按钮。 */
.sub-toggle { display: none; }

/* 导航最右侧的搜索入口：一个纯图标按钮（参考站 .navto-search 同款），
   点击展开页头下方的全宽面板 .site-search。 */
.nav-search-toggle {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius);
  /* 图标是按钮唯一可见内容 → 受 WCAG 2.2 SC 1.4.11 非文本对比 3:1 约束。
     --c-text-muted 如今也过 AA（页底 4.60:1），但这枚图标是按钮唯一可见内容、
     受 SC 1.4.11 非文本 3:1 约束且希望更「实」，故仍取正文色 --c-text-body(#55616F) = 6.31:1。 */
  color: var(--c-text-body);
  transition: color var(--t-fast), background-color var(--t-fast);
}
.nav-search-toggle:hover { color: var(--c-primary-dark); background: var(--c-primary-light); }
.nav-search-toggle i {
  width: 17px;
  height: 17px;
  background: currentColor;
  -webkit-mask: var(--ico-search) center / contain no-repeat;
  mask: var(--ico-search) center / contain no-repeat;
}
/* 展开态：图标变主题蓝（颜色对齐参考站 `.search-on .site-navbar li.navto-search a{color:var(--tb--main)}`）；
   淡蓝底是本模板额外加的，用来强化「已展开」的状态反馈，与 hover 态同一套视觉语言 */
.search-on .nav-search-toggle { color: var(--c-primary-dark); background: var(--c-primary-light); }

/* ---------- 全宽搜索面板 ----------
   参考站 .site-search：绝对定位、left/right 都 0 铺满整宽、白底、整条滑出，
   且 **height 是硬编码的 120px**（不是靠 padding 撑出来）。
   本模板把它挂在 .site-header 内部并用 top:100% 锚定页头下沿 ——
   这样不依赖「页面有没有顶部工具条」，也不用像参考站那样写 top:107px/72px 这类硬编码偏移。
   注意：页头自身有 1px 下边框，绝对定位的包含块是页头的 padding box，
   所以 top:100% 落在 y = 页头 border-box 底边 - 1px，面板正好盖住那条 1px 分隔线（同为白色，视觉无缝）。 */
.site-search {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 120px;              /* 参考站原值，三档：120 / 96 / 66 */
  background: var(--c-card);
  border: 0;                  /* 参考站 .site-search 无边框，高度必须正好 120 */
  box-shadow: var(--shadow-lg);
  z-index: 65;
  /* 关闭态：透明 + 轻微上移 + visibility:hidden。
     visibility 这一项是关键 —— 它让收起时的输入框无法被 Tab 聚焦。
     ★ visibility 的过渡只在「关闭」方向延迟到淡出结束后再生效；
       打开方向必须瞬时（0s）—— 否则展开瞬间它的计算值仍是 hidden，
       脚本里的 focus() 会被浏览器静默忽略（实测踩过这个坑）。 */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity var(--t-fast), transform var(--t-fast), visibility 0s var(--t-fast);
}
.search-on .site-search {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity var(--t-fast), transform var(--t-fast), visibility 0s;
}

/* 表单：参考站用 float + 85%/15% 宽度，这里改用 flex 拼排，效果一致但更稳。
   内缩 20% 是参考站桌面端取值：37×2 + 46 输入框 = 120，正好等于面板高度。 */
.site-search-form {
  display: flex;
  padding: 37px 20%;
}

.site-search-form .search-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 46px;
  padding: 4px 15px;
  border: 1px solid var(--c-border-strong);
  border-right: 0;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  background: var(--c-card);
  /* 参考站此处取 #999（白底 2.85:1，录进去的字偏淡）→ 改为正文色 --c-text-body（6.31:1） */
  color: var(--c-text-body);
  font-size: var(--fs-md);
  outline: none;
}
.site-search-form .search-input::placeholder { color: var(--c-text-muted); }
.site-search-form .search-input:focus { border-color: var(--c-primary-dark); }
/* 去掉 WebKit 自带的搜索清除/装饰按钮，避免与自定义图标挤在一起 */
.site-search-form .search-input::-webkit-search-decoration,
.site-search-form .search-input::-webkit-search-cancel-button,
.site-search-form .search-input::-webkit-search-results-button {
  -webkit-appearance: none;
  appearance: none;
}

/* 提交按钮占 15%，与输入框拼成一条完整控件。
   底色用 --c-btn(深靛蓝 #0B63D7)：白图标落在上面是 5.56:1，远超非文本 3:1 的要求。 */
.site-search-form .search-btn {
  flex: 0 0 15%;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 46px;
  background: var(--c-btn);
  color: var(--c-on-dark);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  transition: opacity var(--t-fast);
}
.site-search-form .search-btn:hover { opacity: .85; }
/* 按压只压不透明度、**不加 scale** —— 它与左边的输入框是拼成一条的整体控件，
   一缩放就会在接缝处裂开一道缝，那比没有反馈更糟。 */
.site-search-form .search-btn:active { opacity: .7; }
.site-search-form .search-btn i {
  width: 18px;
  height: 18px;
  background: currentColor;
  -webkit-mask: var(--ico-search) center / contain no-repeat;
  mask: var(--ico-search) center / contain no-repeat;
}

/* 屏幕阅读器专用文本：视觉隐藏但仍参与可访问性树（供 <label for> 关联） */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.nav-toggle {
  display: none;
  width: 38px; height: 38px;
  font-size: var(--fs-xl);
  color: var(--c-text-body);
  border-radius: var(--radius);
  /* 折叠态下整个导航只靠这一个按钮进出，而它此前**连 hover 都没有** ——
     这是本次精修里最实在的一处补齐。 */
  transition: background-color var(--t-fast), color var(--t-fast), transform var(--t-fast);
}
.nav-toggle:hover { background: var(--c-primary-soft); color: var(--c-primary-dark); }
.nav-toggle:active { transform: scale(var(--press)); }

/* ---------- 通用图标（mask 工具类） ----------
   全站所有「图标」都走这两条规则，图标色一律 currentColor → 自动跟随文字颜色。
   ★ 用法：`<i class="ico ico-thumb"></i>`（**必须**带一个 ico-xxx 修饰类）。
     漏了修饰类 → --ico 未定义 → mask 解析失败 → 会画出一块实心方块，所以别单独用 .ico。 */
.ico {
  display: inline-block;
  flex: none;
  width: 1em;
  height: 1em;
  background-color: currentColor;
  -webkit-mask: var(--ico) center / contain no-repeat;
  mask: var(--ico) center / contain no-repeat;
}
.ico-thumb { --ico: var(--ico-thumb); }
.ico-heart { --ico: var(--ico-heart); }
.ico-compass { --ico: var(--ico-compass); }
.ico-close { --ico: var(--ico-close); }

/* ---------- 6. 面包屑 ---------- */
.breadcrumb {
  padding: 14px 0;
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
  line-height: var(--lh-base);
}
.breadcrumb a { color: var(--c-text-muted); }
.breadcrumb a:hover { color: var(--c-primary-dark); }
.breadcrumb .sep { margin: 0 8px; color: var(--c-border-strong); }
.breadcrumb .current { color: var(--c-text-muted); }

/* ---------- 7. 栏目标题（统一组件） ---------- */
.sec-title {
  display: flex;
  align-items: center;
  min-height: 48px;
  padding: 0 16px;
  background: var(--c-card);
  border-bottom: 1px solid var(--c-border-light);
  font-size: var(--fs-lg);
  font-weight: var(--fw-title);
  color: var(--c-text);
}
/* 竖条用「更亮一档的主色 + 胶囊圆角」：它是纯装饰，取装饰色才不会把标题压沉。
   宽度 4 → 3px 是为了配合更细的线条语言。 */
.sec-title::before {
  content: "";
  flex: 0 0 auto;
  width: 3px; height: 16px;
  margin-right: 10px;
  background: var(--c-primary-bright);
  border-radius: var(--radius-pill);
}
/* ★ 参考站在标题右下方有个 5px 小方块（压在分隔线上），属参考站特有的拐角装饰；
   本主题要「干净」，已移除。若要还原，把它作为 ::after 加回来即可。 */
.sec-title .more-link {
  margin-left: auto;
  font-size: var(--fs-xs);
  font-weight: 400;
  color: var(--c-text-muted);
  /* ★ 本类当前**没有任何模板在用**（侧栏标题都是纯文字）。留着它是作为
     「栏目名 + 更多 →」这个组件的契约；过渡补齐，免得将来第一个用它的人拿到半成品。 */
  transition: color var(--t-fast);
}
.sec-title .more-link:hover { color: var(--c-primary-dark); }

/* 页面主标题（列表页栏目名） */
.page-head {
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  overflow: hidden;             /* 让内部 sec-title 的白底被外层圆角裁掉，不必单独写内圆角 */
  margin-bottom: var(--card-gap);
}
.page-head .sort-desc {
  padding: 12px 16px 16px;
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
  line-height: 1.7;
}

/* ---------- 8. 文章卡片（列表） ---------- */
/* 卡片：缩略图 180×120 固定在左（**不要动**，这是参考站的栅格契约）。
   内边距 20 → 24、圆角 0 → 10px、卡片间距 10 → 12px —— 是「本主题 / 简洁通透」的主要来源。 */
.article-list { display: block; }

.article-card {
  display: flex;
  gap: 24px;
  padding: 24px;
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  margin-bottom: var(--card-gap);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
/* 悬停只把描边提亮一档 + 一点几乎看不见的绿阴影。
   **不要加位移/放大** —— 列表卡片一抖，滚动手感立刻就「塑料」了。 */
.article-card:hover { border-color: var(--c-primary-bright); box-shadow: var(--shadow-sm); }

.article-thumb {
  flex: 0 0 180px;
  width: 180px;
  height: 120px;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: var(--c-primary-soft);   /* 图未加载时也应是主题色，不要灰块 */
}
.article-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.article-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* 标题 18px/1.5（参考站 body line-height:1.5，h2 font-size:18px → 行距 27px）
   标题色由后台「标题颜色」字段驱动（[list:titlecolor]），留空时 style 被浏览器丢弃 */
/* ★ 文章标题单独加粗到 700，其余标题仍是 --fw-title(500)。
   依据：参考图里同级标题的墨迹覆盖率 45.8%，与「微软雅黑 Bold @18px」的 45.0% 吻合，
   而 Regular 只有 28.5%（= 本模板 500 在无 Bold 字面时的实际渲染）。字号本就一致，差的只是字重。
   ★ 这条会**连带**作用到详情页的 `.article-header .article-title` ——
     那条规则只覆盖了 font-size/line-height/color，没写 font-weight，
     所以「文章标题」在列表页与详情页同时加粗，语义上是一致的（不是漏改）。
   ★ 不要改成 var(--fw-bold) 之类的令牌：这是唯一一处需要 700 的标题，
     立令牌反而让人以为全站标题都可能变粗。 */
.article-title { font-size: var(--fs-title); line-height: 1.55; margin-bottom: 10px; font-weight: 700; }
.article-title a { color: var(--c-text); }
.article-title a:hover { color: var(--c-primary-dark); }

.article-excerpt {
  font-size: var(--fs-sm);   /* 12 → 13px：12px 中文偏挤，本主题要「松」 */
  color: var(--c-text-body);
  line-height: 1.7;
  max-height: 48px;
  margin-bottom: auto;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* 元信息（通用） */
.article-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 10px;
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}
.article-meta a { color: var(--c-text-muted); }
.article-meta a:hover { color: var(--c-primary-dark); }
.meta-author { display: inline-flex; align-items: center; gap: 8px; }
.meta-avatar { width: 20px; height: 20px; border-radius: 50%; background: var(--c-primary-light); display: inline-block; }
.card-like { margin-left: auto; display: inline-flex; align-items: center; gap: 4px; }
/* 「赞」图标：原来是彩色 emoji 👍（颜色由系统字体决定、无法随主题变），
   现改为 1em 的 mask 图标，跟随 .card-like 的文字色。 */
.card-like .ico { width: 13px; height: 13px; vertical-align: -2px; margin-right: 2px; }

/* 列表卡片内的元信息（对齐参考站 .excerpt .meta：12px / 与摘要间距 20px / 行高固定 24px
   条目间距 15px；头像 24×24） */
.article-card .article-meta {
  gap: 16px;
  margin-top: 20px;
  height: 24px;
  overflow: hidden;
  font-size: var(--fs-xs);
}
.article-card .meta-avatar { width: 24px; height: 24px; flex: 0 0 24px; }

/* 所属栏目（首页专用，参考站 <a class="cat">：小图标 + 栏目名，链接到栏目页） */
.meta-cat { display: inline-flex; align-items: center; gap: 6px; }
.meta-cat i {
  width: 12px; height: 12px;
  flex: 0 0 12px;
  background-color: currentColor;
  -webkit-mask: var(--ico-cat) center / 12px 12px no-repeat;
  mask: var(--ico-cat) center / 12px 12px no-repeat;
}

/* ---------- 8.1 置顶 / 推荐 徽标 ----------
   参考站是实心红块（.sticky-icon / #ff5e52 / padding 5px 8px 6px / radius 4px，实测 40×23）。
   本主题改**柔和胶囊**：浅底 + 同色系深字 + 胶囊圆角，体积更轻、不再抢标题。
   ★ 两者语义不同，故配色分开：置顶 = 琥珀（设计选定的暖色相，与主蓝 H211° 相差 173°，冷暖对立最醒目），
     推荐 = 蔚蓝（正向、平静）。
   ★ 浅底 + 深字是刻意的：这样轻松就能做到 4.5:1 以上；而白字压在饱和色上很难过 AA。
   ★ 改配色后必须同步 tools/verify_tag_badges.js（它逐项断言了底色与尺寸）。 */
.sticky-icon {
  display: inline-block;
  line-height: 1.6;
  padding: 0 9px;
  font-size: var(--fs-xs);
  font-weight: 400;
  border-radius: var(--radius-pill);
  margin-right: 8px;
  /* 用 px 偏移而不是 top:2px —— 不受 position 影响，也不会把标题行盒撑高 */
  vertical-align: 1px;
  color: var(--c-accent-dark);
  background-color: var(--c-accent-light);
}
.sticky-icon--rec { color: var(--c-primary-dark); background-color: var(--c-primary-light); }

/* ---------- 9. 分页 ----------
   参考站是「圆形页码 + 灰底 #f3f3f3 + 灰边 #c8c8c8 + 蓝底激活」。
   本主题改：白底 + 极浅描边 + 小圆角（方形比圆形更「轻」，也更贴合细线条语言）。
   激活态必须用**深主色**底 + 白字 —— 白字压在浅主色上只有 3.98:1，13px 页码过不了 AA。 */
.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 26px 0 14px;
  font-size: 0; /* 抵消模板中 if 标签留下的空白文本节点造成的额外间隙 */
}
.pager .pg-item,
.pager .page-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;          /* 不参与伸缩，避免窄屏被压扁导致文字竖排 */
  white-space: nowrap;
  width: 34px;
  height: 34px;
  padding: 0;
  background: var(--c-card);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  font-size: var(--fs-sm);
  line-height: 1;
  color: var(--c-text-body);
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast),
              transform var(--t-fast);
}
.pager .pg-pill { width: auto; padding: 0 16px; border-radius: var(--radius-pill); color: var(--c-text); }
.pager .pg-total { color: var(--c-text-muted); }
.pager a.pg-item:hover,
.pager a.page-num:hover {
  background: var(--c-primary-light);
  border-color: var(--c-primary-bright);
  color: var(--c-primary-dark);
}
.pager .page-num-current,
.pager .page-num-current:hover {
  background: var(--c-primary-dark);
  border-color: var(--c-primary-dark);
  color: var(--c-on-dark);
  font-weight: var(--fw-title);
}
/* 页码是全站最小的可点目标（桌面 34px / 窄屏 30px）——共用同一个 --press 幅度，
   在小目标上「按下去」的观感反而更明确。 */
.pager a.pg-item:active,
.pager a.page-num:active { transform: scale(var(--press)); }
.pager .pg-empty { color: var(--c-text-muted); font-size: var(--fs-sm); }

/* ---------- 10. 侧栏模块 ---------- */
/* 侧栏卡片：极浅描边负责分层，阴影只留一点点体积感（0 1px 2px / 4% 透明度）。
   两张侧栏片段（sidebar.html 与 sidebar-simple.html）用的是同一套类名，改这里两边都生效。 */
.widget {
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  margin-bottom: var(--card-gap);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
/* 15px 与页面级 .sec-title(16px) 差一档是刻意的层次区分：侧栏标题不该与主栏标题同重。 */
.widget .sec-title { min-height: 44px; font-size: var(--fs-md); padding: 0 var(--side-pad); }
/* 侧栏标题：竖条与文字的间距（参考站实测 13px，文字左沿与下方列表内容错开一条竖条宽度） */
.widget .sec-title::before { margin-right: 13px; }
.widget-body { padding: 14px var(--side-pad); }

/* 搜索 */
.search-form { display: flex; gap: 8px; }
.search-form input {
  flex: 1;
  min-width: 0;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  color: var(--c-text-body);
  outline: none;
}
.search-form input:focus { border-color: var(--c-btn); }
.search-form input::placeholder { color: var(--c-text-muted); }
.search-form button {
  flex: 0 0 auto;
  height: 38px;
  padding: 0 20px;
  background: var(--c-btn);
  color: var(--c-on-dark);
  border-radius: var(--radius-sm);
  font-size: var(--fs-base);
  transition: background var(--t-fast), transform var(--t-fast);
}
.search-form button:hover { background: var(--c-btn-hover); }
.search-form button:active { transform: scale(var(--press)); }

/* 会员中心 */
/* 16px 的水平内边距会破坏「侧栏只有一条 --side-pad 基准线」的约定，改回 var(--side-pad)。 */
.member-box { padding: 24px var(--side-pad); text-align: center; }
.member-box p { font-size: var(--fs-base); color: var(--c-text-body); margin-bottom: 18px; }
.member-btns { display: flex; gap: 12px; justify-content: center; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 36px;
  padding: 0 22px;
  border-radius: var(--radius);
  font-size: var(--fs-sm);
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast),
              transform var(--t-fast), opacity var(--t-fast);
}
/* 按钮族三档，语义与视觉都分开：
     primary = 实心深靛蓝（唯一的主行动，白字 5.56:1）
     default = 白底描边幽灵按钮（次行动；**不要用灰底** —— 灰底在蓝底色上显脏、显重）
     accent  = 琥珀浅底胶囊（打卡这类「软行动」，浅底深字轻松过 AA）
   ★ 按钮里的图标用 .ico（1em，跟着按钮文字色走），不要塞 emoji。 */
.btn .ico { margin-right: 6px; }
.btn-primary { background: var(--c-btn); color: var(--c-on-dark); }
.btn-primary:hover { background: var(--c-btn-hover); color: var(--c-on-dark); }
.btn-default { background: var(--c-card); color: var(--c-text-body); border: 1px solid var(--c-border-strong); }
.btn-default:hover { background: var(--c-primary-soft); border-color: var(--c-primary-bright); color: var(--c-primary-dark); }
.btn-accent { background: var(--c-accent-light); color: var(--c-accent-dark); border: 1px solid var(--c-accent-hover); }
.btn-accent:hover { background: var(--c-accent-hover); color: var(--c-accent-dark); }

/* —— 按压态：三档按钮共用一个幅度（--press）。手感一致比「各调各的」重要得多 ——
   ★ 只动 transform（GPU 合成、零布局位移）：不会把 .action-bar 里 min-width:108px 的
     格子撑开，也不会带着旁边的按钮一起抖。 */
.btn:active { transform: scale(var(--press)); }

/* —— 禁用态 ——
   ★ 真实场景有两处（见 js/main.js）：① 表单提交在途（`btn.disabled = true`）
     ② 短信验证码的 10 秒倒计时。两者都只设**原生 disabled 属性**，不额外加类名。
   ★ 所以样式必须挂在属性上（.btn[disabled]），不要另造 .is-disabled ——
     原生属性自带「不聚焦 + 不派发点击」，样式若另立一套，迟早与行为脱节。
   ★ 禁用态**不给 hover / active 任何反应**：那会让人以为还能点。
   ★ 文字对比度在 0.6 不透明度下必然低于 4.5:1，这是 SC 1.4.3 明确豁免的
     「inactive user interface component」，属预期结果，别为了凑比值把灰调深。 */
.btn[disabled],
.btn[disabled]:hover,
.btn[disabled]:active {
  background: var(--c-primary-light);
  border-color: var(--c-border-strong);
  color: var(--c-text-muted);
  opacity: .6;
  transform: none;
  cursor: not-allowed;
}

/* 影视推荐挂件（.rec-item / .rec-badge）已从模板移除（sidebar.html 里不再有），
   对应的 34 行样式一并删除 —— 留着它只会让「要不要跟着换主题」变成一道无谓的选择题。
   参考站原值备查：徽标 78×31（padding 6px 15px 7px / 12px）、标题 18px、条目节拍 109px、
   三条轮换 紫 #c35bff / 红 #ff5e52 / 蓝 #428bca。 */

/* 内容页评论头部 */
.cmt-head-meta { font-size: var(--fs-xs); line-height: 1.5; }
.cmt-head-meta .comment-author { color: var(--c-primary-dark); }
.cmt-head-meta .comment-time { color: var(--c-text-muted); margin-left: 8px; }

/* 热门文章 */
.hot-item {
  display: flex;
  gap: 10px;
  padding: 12px var(--side-pad);
  border-bottom: 1px solid var(--c-border-light);
}
.hot-item:last-child { border-bottom: 0; }
.hot-thumb {
  flex: 0 0 100px;
  width: 100px;
  height: 66px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--c-primary-soft);
}
.hot-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hot-info { flex: 1; min-width: 0; }
.hot-title {
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--c-text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.hot-title:hover { color: var(--c-primary-dark); }
.hot-meta { margin-top: 6px; font-size: var(--fs-xs); color: var(--c-text-muted); }
.hot-meta span + span { margin-left: 12px; }

/* 最新评论 */
.cmt-item {
  display: flex;
  gap: 10px;
  padding: 12px var(--side-pad);
  border-bottom: 1px solid var(--c-border-light);
}
.cmt-item:last-child { border-bottom: 0; }
.cmt-avatar {
  flex: 0 0 36px;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--c-primary-light);
}
.cmt-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cmt-body { flex: 1; min-width: 0; }
.cmt-head { font-size: var(--fs-xs); line-height: 1.5; }
.cmt-name { color: var(--c-primary-dark); }
.cmt-time { color: var(--c-text-muted); margin-left: 6px; }
.cmt-text {
  margin-top: 3px;
  font-size: var(--fs-sm);
  color: var(--c-text-body);
  line-height: 1.6;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-all;
}
/* cmt-text 在侧栏渲染为指向所属文章的 <a> */
a.cmt-text { text-decoration: none; }
a.cmt-text:hover { color: var(--c-primary-dark); }
/* 无评论占位 */
.cmt-empty {
  padding: 16px var(--side-pad);
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  text-align: center;
}

/* 全站「最新评论」挂件与「最新发布」兜底挂件，二选一显示：
   - 未安装扩展标签（apps/home/controller/ExtLabelController.php）时：
     .widget-comments 隐藏，页面用内置标签的「最新发布」兜底，不会把标签原文露给访客。
   - 安装了扩展时：扩展会删除兜底挂件并注入样式把 .widget-comments 打开。 */
.widget-comments { display: none; }

/* 支付宝红包卡：全站唯一的高饱和色块，必须在主题里。
   ★ 历史：最初是饱和红渐变，后降饱和成「暖陶色」（#BE4C40→#9E362D）。
     但它既不是蔚蓝主色、也不是琥珀点缀色 —— 在一片蓝灰的侧栏里，
     它成了**唯一一个跳出配色体系的色块**，视觉上最重、最抢眼，与「全站统一」相悖。
   ★ 现在改用**深主色渐变**（--c-primary-dark → --c-btn-hover）：
     既保留了「这是一张要你扫码的强 CTA」的重量，又落在同一套蓝色系里。
     白字在两端分别 5.56:1 / 7.58:1，稳过 AA。 */
.alipay-body { padding: 12px var(--side-pad); }
.alipay-card {
  background: linear-gradient(180deg, var(--c-primary-dark) 0%, var(--c-btn-hover) 100%);
  border-radius: var(--radius);
  padding: 18px 16px 14px;
  text-align: center;
  color: var(--c-on-dark);
}
/* 17px → --fs-lg(16px)：它是全站唯一的 17px，而刻度里根本没有这一档。
   并到 16px 后与 .sec-title 同级，这张品牌卡自身的 16/12 两级比例也更干净。 */
.alipay-card .ac-title { font-size: var(--fs-lg); font-weight: var(--fw-title); letter-spacing: 1px; }
/* 副标题原本用 opacity .92 压淡白字 —— 那会把对比度从 5.56 拉到约 4.2:1，踩 AA 红线。
   改用固定的浅主色（#E3EBF5，在深主色底上 4.62:1），既「淡」又达标。 */
.alipay-card .ac-sub { margin-top: 4px; font-size: var(--fs-xs); color: var(--c-primary-light); line-height: 1.5; }
.alipay-card .ac-qr {
  width: 168px;
  height: 168px;
  margin: 12px auto 8px;
  background: var(--c-card);
  border-radius: var(--radius-sm);
  padding: 6px;
}
.alipay-card .ac-qr img { width: 100%; height: 100%; display: block; }
.alipay-card .ac-foot {
  font-size: var(--fs-xs);
  color: var(--c-primary-light);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.alipay-card .ac-logo {
  display: inline-block;
  padding: 1px 8px;
  background: var(--c-card);
  color: #1677ff;      /* 支付宝品牌蓝：品牌标识不跟着站点主题改。
                          （白底 4.10:1，低于 4.5；但品牌字标属 SC 1.4.3 的 logotype 豁免。） */
  border-radius: var(--radius-sm);
  font-weight: 700;
  font-size: var(--fs-xs);
}

/* ---------- 11. 内容页 ---------- */
.article-detail {
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  padding: 30px 32px 34px;
  box-shadow: var(--shadow-sm);
  margin-bottom: var(--card-gap);
}

.article-header { text-align: center; padding-bottom: 4px; }
.article-header .article-title {
  font-size: var(--fs-h1);
  line-height: 1.45;
  color: var(--c-text);
  margin-bottom: 12px;
}
.article-header .article-meta {
  justify-content: center;
  gap: 18px;
  color: var(--c-text-muted);
}
.article-header .article-meta .val { color: var(--c-primary-dark); }

/* 摘要框 */
.summary-box {
  margin: 24px 0 10px;
  padding: 18px 18px 14px;
  border: 1px dashed var(--c-border-strong);
  border-radius: var(--radius);
  position: relative;
}
.summary-box .sum-label {
  position: absolute;
  top: -10px;
  left: 14px;
  padding: 0 6px;
  background: var(--c-card);
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
}
.summary-box .sum-label::before {
  content: "";
  display: inline-block;
  width: 4px; height: 4px;
  margin-right: 5px;
  background: var(--c-primary-bright);
  border-radius: 50%;
  vertical-align: 2px;
}
.summary-box .sum-text { font-size: var(--fs-sm); color: var(--c-text-body); line-height: var(--lh-loose); }

/* 正文段落标题（常见问题 / 游客下载 / 登录下载 …） */
.article-content { font-size: var(--fs-base); color: var(--c-text-body); line-height: var(--lh-loose); }
.article-content img { max-width: 100%; height: auto; }
.article-content p { margin: 10px 0; }

/* 正文段落标题（常见问题 / 游客下载 / 登录下载 …）
   与 .sec-title 用同一套语言：亮主色细竖条 + 极浅分隔线 + 字重 500，去掉参考站那个拐角小方块。 */
.body-title {
  display: flex;
  align-items: center;
  min-height: 44px;
  margin: 26px 0 14px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--c-border-light);
  font-size: var(--fs-lg);
  font-weight: var(--fw-title);
  color: var(--c-text);
}
.body-title::before {
  content: "";
  flex: 0 0 auto;
  width: 3px; height: 16px;
  margin-right: 10px;
  background: var(--c-primary-bright);
  border-radius: var(--radius-pill);
}

/* 截图 */
.shot-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
.shot-grid img {
  width: 100%;
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  display: block;
}

/* FAQ */
.faq-item { margin-bottom: 12px; font-size: var(--fs-sm); line-height: 1.9; }
.faq-item .q { color: var(--c-primary-dark); }
.faq-item .q b, .faq-item .a b { color: var(--c-text); font-weight: 700; }
.faq-item .a { color: var(--c-text-body); }

/* 下载链接列表 */
.dl-links { display: block; }
.dl-links a {
  display: block;
  font-size: var(--fs-sm);
  color: var(--c-primary-dark);
  line-height: 2.2;
  word-break: break-all;
}
.dl-links a:hover { text-decoration: underline; }

/* 登录提示框（柔玫瑰虚线）：--c-danger 是低饱和玫瑰红，在本主题里只承担「警示」语义，
   不做装饰。 */
.login-tip {
  margin: 8px 0 20px;
  padding: 20px 22px;
  border: 1px dashed var(--c-danger);
  border-radius: var(--radius);
  background: var(--c-danger-bg);
  text-align: center;
  font-size: var(--fs-base);
  color: var(--c-text);
}
.login-tip .tip-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--c-danger);
  color: var(--c-on-dark);
  font-size: var(--fs-xs);
  font-weight: 700;
  vertical-align: -3px;
}
/* 提示里的「登录」是入口而不是普通内文链接：跟着整句一起读得通，所以就地下划线强调，
   不做成按钮 —— 免得一句提示里冒出第二套视觉重量。点击开登录浮层（data-sign-open）。 */
.login-tip a { color: var(--c-primary-dark); text-decoration: underline; }
.login-tip a:hover { color: var(--c-btn-hover); }

/* 操作按钮组 */
.action-bar { display: flex; justify-content: center; gap: 16px; margin: 4px 0 20px; }
.action-bar .btn { min-width: 108px; }

/* 已赞态（.is-liked，由 main.js 按服务端 do/isLikes 的答复 + 本地 cookie 回填）。
   ★ 状态**不能只靠底色**（SC 1.4.1：不得仅用颜色传达信息），所以同时把图标由
     线性换成实心（--ico-thumb-on）—— 换的是「形」，宽高完全相同，**零布局位移**。
   ★ 再叠加 aria-pressed="true"，读屏用户能听到「已按下」。
   ★ 不置 disabled、不降不透明度：置灰会让按钮看起来「坏了」，但它其实仍应可点
     （再点一次给一句「你已赞！」的提示，这也正是用户要的反馈）。 */
.btn-primary.is-liked { background: var(--c-btn-hover); }
.btn-primary.is-liked .ico-thumb { --ico: var(--ico-thumb-on); }

/* ---------- 打赏弹窗（模态对话框） ----------
   ★ 结构：.modal（全屏容器）> .modal-mask（遮罩层）+ .modal-dialog（对话框），**两者并列、不嵌套**——
     并列是为了让遮罩层的变化不影响对话框内容（嵌套的话遮罩一加透明度，里面的二维码跟着一起变淡）。
   ★★ 2026-09-22「去除背景遮罩」：遮罩层**不再着任何颜色**，弹窗打开时页面不再被压暗。
     它仍然保留在 DOM 里，因为承担三件**与颜色无关**的事：
       ① 铺满视口 → 点击落在对话框之外的任意位置都算「点空白」→ 关闭；
       ② 与 .modal-dialog 并列，撑住本容器的 flex 居中；
       ③ 焦点陷阱（JS）与 body.modal-open 滚动锁的作用域基准。
     「浮起来」的层次改由对话框自己的 --shadow-modal 承担（见 .modal-dialog）。
     三处弹窗（打赏 / 点赞提示 / 会员登录）**必须一致**，否则会被当成「有时暗有时不暗」的 bug。
   ★ 显隐只认 [hidden] 属性（JS 切 hidden + 给 body 加 class 锁滚动），
     不要再在 CSS 里另造一套 .is-open 状态类，两套状态迟早不同步。
   ★ 动效只做 opacity / transform（GPU 合成，不触发重排），并在 prefers-reduced-motion 下整体关掉。 */
.modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.modal[hidden] { display: none; }

/* 弹窗打开时锁页面滚动。滚动条宽度的补偿在 JS 里用内联 padding-right 做
   （值要实时量，写不进 CSS）。 */
body.modal-open { overflow: hidden; }

/* 遮罩层：只剩「铺满视口」这一件事（不给背景色，也就不再有入场动画 ——
   透明元素的淡入是空转，留着只会让人以为这里还有一层视觉）。 */
.modal-mask {
  position: absolute;
  inset: 0;
}
.modal-dialog {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 560px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  padding: 34px 36px 30px;
  background: var(--c-card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-modal);
  animation: modal-dialog-in var(--t-fast) both;
}
.modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--c-text-muted);
  font-size: var(--fs-lg);
  cursor: pointer;
  transition: background-color var(--t-fast), color var(--t-fast), transform var(--t-fast);
}
.modal-close:hover { background: var(--c-primary-soft); color: var(--c-primary-dark); }
.modal-close:active { transform: scale(var(--press)); }

/* 入场动画只给对话框：遮罩层已不着色，透明元素再淡入是空转，keyframes 一并删了。 */
@keyframes modal-dialog-in {
  from { opacity: 0; transform: translateY(-12px); }
  to { opacity: 1; transform: none; }
}

/* 打赏弹窗内容 */
.reward-title {
  /* 左右各留 32px：标题是居中的，不留白就会被右上角的关闭按钮压住 */
  padding: 0 32px;
  font-size: var(--fs-xl);
  font-weight: var(--fw-title);
  line-height: 1.5;
  color: var(--c-text);
  text-align: center;
}
.reward-desc {
  margin-top: 10px;
  font-size: var(--fs-sm);
  line-height: var(--lh-loose);
  color: var(--c-text-muted);
  text-align: center;
}
/* QR 区收窄到 420px 并居中：两个码并排时不至于摊满整个 560px 弹窗（参考图里两个码是紧凑的一对） */
.reward-qrs {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
  max-width: 420px;
  margin: 24px auto 0;
}
.reward-qr { text-align: center; }
.rq-label { font-size: var(--fs-base); color: var(--c-text-body); }
.rq-box {
  position: relative;
  margin-top: 10px;
  padding: 12px;
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  transition: border-color var(--t-fast);
}
.rq-box:hover { border-color: var(--c-primary); }
.rq-box img { display: block; width: 100%; height: auto; }
/* 二维码中心的小圆标。白圈用 box-shadow 而不是 border —— border 会占掉宽高，
   把圆标挤得相对二维码偏位；box-shadow 不参与布局。
   圆形：logo.svg 本身是「圆角方块」，放进 50% 圆里四角被裁掉，正好是参考图那个圆形徽标的样子。 */
.rq-logo {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 34px;
  height: 34px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--c-card) var(--qr-logo) center / 100% 100% no-repeat;
  box-shadow: 0 0 0 3px var(--c-card);
}

@media (prefers-reduced-motion: reduce) {
  .modal-dialog { animation: none; }
}

/* ---------- 轻提示（toast） ----------
   点赞这类「一次性反馈」用自动消失的浮层提示，而不是 alert（会阻塞整个页面）。
   ★ 容器常驻 DOM，只用 .is-show 切可见性，**不切 [hidden]** —— 见 content.html 里的说明。
   ★ pointer-events:none：提示层永远不拦截它下面的点击。
   ★ 只动 opacity / transform；底色与文字全部走令牌；胶囊圆角与徽标同一套语言。
   ★ 层级 120：高于弹窗遮罩（.modal 是 100）与返回顶部（80），低于任何调试层。 */
.toast {
  position: fixed;
  left: 50%;
  bottom: 40px;
  z-index: 120;
  max-width: calc(100% - 32px);
  padding: 10px 22px;
  border-radius: var(--radius-pill);
  background: var(--c-card);
  border: 1px solid var(--c-primary-light);
  box-shadow: var(--shadow-lg);
  color: var(--c-text-body);
  font-size: var(--fs-sm);
  line-height: 1.5;
  text-align: center;
  opacity: 0;
  transform: translate(-50%, 12px);
  transition: opacity var(--t-fast), transform var(--t-fast);
  pointer-events: none;
}
.toast.is-show { opacity: 1; transform: translate(-50%, 0); }

@media (prefers-reduced-motion: reduce) {
  .toast { transition: none; }
}

/* ---------- 重复点赞提示弹窗（alertdialog） ----------
   参考站对「已赞过还再点」用的是一句浏览器原生 alert（正文「你已赞!」+「确定」按钮）。
   原生 alert 的标题栏是浏览器 chrome，页面里做不出来；能复刻的是它那三件事 ——
   一句文案、一个确定按钮、把后面的页面挡住。这里就用站内令牌把它们做出来，
   顺带避开原生 alert 的硬伤：它会阻塞整个 JS 线程（连页面动画都停住）。

   ★ 类名刻意与打赏弹窗的 .modal / .modal-mask / .modal-dialog **错开**：
     verify_reward_modal.js 是按「第一个匹配」取那几个选择器的，同名会互相污染。
   ★ 遮罩层与打赏弹窗同源：**不着色**（2026-09-22「去除背景遮罩」），只保留铺满视口
     那一层点击区；层次由 --shadow-modal 撑（三处弹窗必须一致）。
   ★ 层级 130：高于轻提示（120）—— 首次点赞那句「感谢点赞！」要是还没消失，也盖不住这个弹窗。 */
.tipmodal {
  position: fixed;
  inset: 0;
  z-index: 130;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.tipmodal[hidden] { display: none; }

.tipmodal-mask {
  position: absolute;
  inset: 0;
}
.tipmodal-dialog {
  position: relative;
  z-index: 1;
  width: 100%;
  /* 窄幅：原生 alert 本身就是个不大的方框，没必要撑成打赏那种 560px */
  max-width: 300px;
  padding: 26px 24px 20px;
  background: var(--c-card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-modal);
  text-align: center;
  animation: modal-dialog-in var(--t-fast) both;
}
.tipmodal-text {
  font-size: var(--fs-lg);
  font-weight: var(--fw-title);
  line-height: 1.5;
  color: var(--c-text);
}
/* 补一句「为什么」。用户点第二次，多半是不确定上一次到底成没成；
   只回一句「你已赞」不解释，反而更像出错了。 */
.tipmodal-hint {
  margin-top: 6px;
  font-size: var(--fs-xs);
  line-height: 1.6;
  color: var(--c-text-muted);
}
.tipmodal-ok { margin-top: 20px; min-width: 96px; }

@media (prefers-reduced-motion: reduce) {
  .tipmodal-dialog { animation: none; }
}

/* 转载说明 */
.reprint {
  padding: 18px 16px;
  background: var(--c-primary-soft);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  text-align: center;
  line-height: var(--lh-base);
}
.reprint a { color: var(--c-text-muted); }
.reprint a:hover { color: var(--c-primary-dark); }

/* 上一篇 / 下一篇 —— 左对齐 + 右对齐，中间一条浅灰竖线分隔 */
.article-prevnext {
  display: flex;
  align-items: flex-start;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--c-border-light);
}
.article-prevnext .pn-item { flex: 1 1 0; min-width: 0; }
.article-prevnext .pn-item.pn-next {
  border-left: 1px solid var(--c-border);
  padding-left: 20px;
  margin-left: 20px;
  text-align: right;
}
.article-prevnext .pn-label {
  display: block;
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
  margin-bottom: 7px;
}
.article-prevnext .pn-title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: var(--fs-base);
  line-height: 1.55;
  color: var(--c-text);
  transition: color var(--t-fast);
}
.article-prevnext a.pn-title:hover { color: var(--c-primary-dark); }
.article-prevnext .pn-none { color: var(--c-text-muted); }
/* 无上/下篇时 PbootCMS 输出 javascript:; —— 置灰并禁点 */
.article-prevnext .pn-title[href="javascript:;"] {
  color: var(--c-text-muted);
  pointer-events: none;
  cursor: default;
}

/* 相关推荐 */
.related-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.related-item {
  display: block;
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  overflow: hidden;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.related-item:hover { border-color: var(--c-primary-bright); box-shadow: var(--shadow-sm); }
.related-thumb { height: 118px; background: var(--c-primary-soft); }
.related-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.related-info { padding: 10px 12px; }
.related-title {
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--c-text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.related-meta { margin-top: 6px; font-size: var(--fs-xs); color: var(--c-text-muted); }

/* 文章目录（内容页侧栏） */
.toc-list { padding: 6px 0; }
.toc-list a {
  display: block;
  padding: 7px 12px 7px 30px;
  position: relative;
  font-size: var(--fs-sm);
  color: var(--c-text-body);
}
.toc-list a::before {
  content: "";
  position: absolute;
  left: 16px;
  top: 50%;
  width: 7px; height: 7px;
  margin-top: -4px;
  border: 2px solid var(--c-primary-bright);
  border-radius: 50%;
  background: var(--c-card);
}
.toc-list a:hover, .toc-list a.active { color: var(--c-primary-dark); }
.toc-list a.active::before { background: var(--c-primary-bright); }

/* 评论 */
.comment-form textarea {
  width: 100%;
  min-height: 100px;
  padding: 14px 16px;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  resize: vertical;
  color: var(--c-text-body);
  outline: none;
}
.comment-form textarea:focus { border-color: var(--c-btn); }
.form-bottom { display: flex; gap: 12px; margin-top: 12px; align-items: center; }
.form-bottom input.captcha-input {
  flex: 0 1 160px;
  min-width: 0;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  outline: none;
}
.form-bottom input.captcha-input:focus { border-color: var(--c-btn); }

/* 图形验证码：紧贴输入框右侧的「点一下换一张」图片按钮。
   ★ 高度必须与 .captcha-input 严格相等（38px）—— 这一行是 flex 居中对齐的，
     图片比输入框高或矮，三者就会肉眼可见地不齐，是这类表单最典型的破绽。
   ★ 宽度**不要写死**：PbootCMS 的验证码图是 120×45（core/code.php 里硬编码），
     与 38px 高不同比例。写死宽度会拉伸变形，所以只给高度、让宽度按图片原比例算出来
     （≈98px）。图换尺寸也不会变形。
   ★ 用 <button> 包住 <img>，而不是给 img 挂 onclick：这样键盘能 Tab 到、回车即刷新，
     读屏也会念 aria-label（WCAG 2.1.1）。焦点环走全局 `:focus-visible`，这里别写 outline:none。 */
.form-bottom .captcha {
  flex: 0 0 auto;
  display: block;
  height: 38px;
  padding: 0;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  background: var(--c-card);
  overflow: hidden;
  cursor: pointer;
  transition: border-color var(--t-fast);
}
.form-bottom .captcha img { display: block; height: 100%; width: auto; }
.form-bottom .captcha:hover { border-color: var(--c-primary); }
.form-bottom .btn { margin-left: auto; min-width: 110px; }

.comment-list { margin-top: 18px; }
.comment-item {
  display: flex;
  gap: 12px;
  padding: 14px 0;
  border-bottom: 1px solid var(--c-border-light);
}
.comment-item:last-child { border-bottom: 0; }
.comment-avatar {
  flex: 0 0 40px;
  width: 40px; height: 40px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--c-primary-light);
}
.comment-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.comment-main { flex: 1; min-width: 0; }
.comment-author { font-size: var(--fs-sm); color: var(--c-primary-dark); }
.comment-time { margin-left: 8px; font-size: var(--fs-xs); color: var(--c-text-muted); }
.comment-content { margin-top: 6px; font-size: var(--fs-sm); color: var(--c-text-body); line-height: var(--lh-base); word-break: break-all; }
.comment-empty { padding: 20px 0; text-align: center; color: var(--c-text-muted); font-size: var(--fs-sm); }

/* 空状态 */
.no-results {
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  padding: 60px 20px;
  text-align: center;
  color: var(--c-text-muted);
}
/* 空状态大图标：原为 🧭 emoji（彩色、不可控），改为 54px 的 mask 线条图标，
   取 --c-border-strong 一档偏淡的色 —— 它是背景性的，不该比正文更响。 */
.no-results .nr-icon {
  width: 54px;
  height: 54px;
  margin: 0 auto 14px;
  background-color: var(--c-border-strong);
  -webkit-mask: var(--ico-compass) center / contain no-repeat;
  mask: var(--ico-compass) center / contain no-repeat;
}
.no-results p { font-size: var(--fs-sm); }

/* ---------- 12. 单页 ---------- */
.single-box {
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  padding: 30px 32px 34px;
  box-shadow: var(--shadow-sm);
  margin-bottom: var(--card-gap);
}
.single-header { text-align: center; padding-bottom: 14px; border-bottom: 1px solid var(--c-border-light); margin-bottom: 20px; }
.single-header h1 { font-size: var(--fs-h1); color: var(--c-text); line-height: 1.45; }
.single-header .single-meta { margin-top: 8px; font-size: var(--fs-xs); color: var(--c-text-muted); }
.single-content { font-size: var(--fs-base); color: var(--c-text-body); line-height: var(--lh-loose); }
.single-content img { max-width: 100%; height: auto; }

/* 三端二维码：参考站是饱和绿渐变条。本主题改成**极浅蓝底 + 深字**——
   二维码本身就是黑白高对比的方块，底板再重就喧宾夺主了；浅底也让「扫码」这件事看起来更轻。 */
.qr-panel {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  background: var(--c-primary-soft);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  padding: 20px 16px;
  margin-bottom: 24px;
}
.qr-panel .qp-item { text-align: center; color: var(--c-text-body); }
.qr-panel .qp-item img {
  width: 104px; height: 104px;
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  padding: 5px;
  display: block;
  margin: 0 auto 8px;
}
.qr-panel .qp-item .qp-label { font-size: var(--fs-xs); color: var(--c-text-muted); }

/* ---------- 13. 页脚 ---------- */
.site-footer {
  padding: 28px 0 36px;
  margin-top: var(--card-gap);
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
  text-align: center;
}
.footer-copy { line-height: 2; }
.footer-copy .brand { color: var(--c-text-body); }
.footer-links { margin-top: 6px; }
.footer-links a { color: var(--c-text-muted); margin: 0 8px; }
.footer-links a:hover { color: var(--c-primary-dark); }

/* 友情链接（页脚，调用后台「友情链接」分组 1） */
.friend-links {
  margin-bottom: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--c-border-light);
  line-height: 2;
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}
.friend-links .fl-label { color: var(--c-text-body); }
/* ★ 链接文字用 --c-text-body，不用 --c-text-muted：
     友链是 12px 的**链接文字**，属正文语义，必须过 AA 4.5:1。
     旧版是 #999 on 参考站页底 #efefef = 2.48:1，上一版 #7C8C87 on 上一版页底 #F4F8F6 = 3.29:1 —— 都不到线。
     现在 --c-text-body #55616F on 页底 = 5.82:1，达标。（verify_new_modules.js 的 WCAG 段会实测） */
.friend-links a {
  color: var(--c-text-body);
  margin: 0 8px;
  transition: color var(--t-fast);
}
.friend-links a:hover { color: var(--c-primary-dark); }
.friend-links:empty { display: none; }

/* ---------- 14. 返回顶部 ---------- */
.back-to-top {
  position: fixed;
  right: 22px;
  bottom: 26px;
  width: 42px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--c-card);
  color: var(--c-primary-dark);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-icon);
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity var(--t-fast), transform var(--t-fast), visibility var(--t-fast);
  z-index: 80;
}
.back-to-top.visible { opacity: 1; visibility: visible; transform: translateY(0); }
/* 按压：它的 transform 已被「出现 / 消失」的位移动画占着，所以这里要把位移**写全**，
   否则 :active 会把显示态的 translateY(0) 顶掉，按钮会在按下瞬间跳回未展开的位置。 */
.back-to-top.visible:active { transform: translateY(2px); }

/* ---------- 15. 会员登录 / 注册（弹窗 + 独立页） ----------
   两种形态共用同一套字段与按钮样式：
     · 弹窗（comm/sign.html，挂在页脚，每页都有）—— 侧栏「立即登录 / 现在注册」、
       正文「请登录后查看」两处入口都开它，不跳页；
       （页头原本还有第三个入口，已按需求移除；样式随之删除，别在导航里重加。）
     · 独立页（html/member/login|register|retrieve.html）—— PbootCMS 的真实路由页，
       直链可用、JS 挂掉也能提交。
   ★★ 类名前缀刻意避开 .modal-*：tools/verify_reward_modal.js 用
      querySelector('.modal-dialog') 取**第一个**匹配元素，全站任何新弹窗只要叫了这个名字，
      打赏弹窗的校验就会被顶包 → 假绿。（已有的点赞提示弹窗同理，所以它叫 .tipmodal*。）
   ★ 显隐只认 [hidden]（JS 切属性 + body.modal-open 锁滚动），不另造 .is-open 状态类 ——
     两套状态迟早不同步。
   ★ 颜色一律取 :root 令牌，组件里不出现字面色（verify_palette.js 会扫）。 */

.sign {
  position: fixed;
  inset: 0;
  z-index: 110;              /* 高于打赏弹窗(100)：登录浮层应盖在所有内容之上 */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.sign[hidden] { display: none; }

/* 遮罩层与打赏 / 点赞提示同源：不着色，只做铺满视口的点击区（见 .modal-mask 的说明）。 */
.sign-mask { position: absolute; inset: 0; }

/* 卡片外壳：宽度上限 / 圆角 / 阴影 / 内滚都在这层。
   两个登入-注册面板共用同一外壳尺寸，切换时弹窗不会因内容长短不同而「跳一下」。 */
.sign-dialog {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 420px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  background: var(--c-card);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-modal);
}

.sign-close {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: 50%;
  color: var(--c-text-muted);
  transition: background-color var(--t-fast), color var(--t-fast), transform var(--t-fast);
}
/* 关闭图标用 mask 复用已有的 --ico-close，不引图标字体 */
.sign-close::before {
  content: "";
  width: 16px;
  height: 16px;
  background-color: currentColor;
  -webkit-mask: var(--ico-close) center / contain no-repeat;
  mask: var(--ico-close) center / contain no-repeat;
}
.sign-close:hover { background: var(--c-primary-soft); color: var(--c-primary-dark); }
.sign-close:active { transform: scale(var(--press)); }

.sign-card { padding: 34px 36px 30px; }
.sign-card[hidden] { display: none; }

.sign-title { font-size: var(--fs-xl); line-height: 1.4; }
.sign-sub { margin-top: 6px; font-size: var(--fs-sm); color: var(--c-text-muted); }
.sign-foot {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--c-border-light);
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  text-align: center;
}

/* ---- 15.1 独立页外壳 ---- */
.auth-page { display: flex; justify-content: center; padding: 36px 0 56px; }
.auth-card {
  width: 100%;
  max-width: 440px;
  padding: 34px 36px 30px;
  background: var(--c-card);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}
.auth-title { font-size: var(--fs-2xl); line-height: 1.4; }
.auth-sub { margin-top: 6px; font-size: var(--fs-sm); color: var(--c-text-muted); }
.auth-closed {
  margin-top: 22px;
  padding: 14px 16px;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  background: var(--c-danger-bg);
  color: var(--c-danger);
  font-size: var(--fs-sm);
  line-height: 1.7;
}
.auth-foot {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--c-border-light);
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  text-align: center;
}

/* ---- 15.2 表单字段（弹窗与独立页共用） ---- */
.auth-form { margin-top: 22px; }
.auth-field { margin-bottom: 16px; }
.auth-field > label,
.auth-field-head > label {
  display: block;
  margin-bottom: 6px;
  font-size: var(--fs-sm);
  color: var(--c-text-body);
  transition: color var(--t-fast);
}
/* 「标签 + 右侧小链接」一行（如「密码 …… 找回密码」）。
   baseline 对齐而不是 center：两者字号不同，center 会让小链接看起来偏上。 */
.auth-field-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
/* 整组高亮：输入框拿到焦点时，它上方那一行 <label> 一起转主色。
   ★ 焦点在 <input> 上、而标签是它的**兄弟**，只有带 :focus-within 的容器能一次选中整组；
     单靠 :focus 只能点亮输入框自己，用户还得再找一眼才知道「这一格填的是什么」。
   ★ 顺带覆盖「密码 …… 找回密码」那一行：两个元素跟着同一组一起亮，不会被拆成两块。 */
.auth-field:focus-within > label,
.auth-field-head:focus-within > label { color: var(--c-primary-dark); }
.auth-opt { font-size: var(--fs-xs); color: var(--c-text-muted); }
.auth-link { font-size: var(--fs-xs); color: var(--c-primary-dark); }

.ipt {
  display: block;
  width: 100%;
  height: 42px;
  padding: 0 14px;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  background: var(--c-card);
  color: var(--c-text);
  outline: none;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.ipt::placeholder { color: var(--c-text-muted); }
.ipt:focus { border-color: var(--c-btn); box-shadow: 0 0 0 3px var(--c-primary-soft); }

/* 验证码一行：输入框弹性占满，右侧是「刷新图」或「获取验证码」按钮，高度严格相等（42px）——
   这一行靠 align-items:stretch 对齐，任一侧高矮不同都会肉眼可见地不齐。
   ★ 图形验证码宽度**不要写死**：PbootCMS 的验证码图是 120×45（core/code.php 硬编码），
     与 42px 高不同比例，写死宽度会拉伸变形；只给高度、让宽度按原比例算。 */
.auth-captcha { display: flex; gap: 10px; align-items: stretch; }
.auth-captcha .ipt { flex: 1 1 auto; min-width: 0; }
.auth-code {
  flex: 0 0 auto;
  display: block;
  height: 42px;
  padding: 0;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  background: var(--c-card);
  overflow: hidden;
  transition: border-color var(--t-fast), background-color var(--t-fast), transform var(--t-fast);
}
.auth-code img { display: block; height: 100%; width: auto; }
.auth-code:hover { border-color: var(--c-primary); }
.auth-code:active { transform: scale(var(--press)); }
.auth-code--text {
  padding: 0 16px;
  font-size: var(--fs-sm);
  color: var(--c-primary-dark);
  white-space: nowrap;
}
.auth-code--text:hover { background: var(--c-primary-soft); }
.auth-code[disabled] { color: var(--c-text-muted); cursor: not-allowed; }
.auth-code[disabled]:hover { background: var(--c-card); border-color: var(--c-border-strong); }

.auth-submit { margin-top: 22px; }
/* 整宽主按钮：与上面的输入框同宽，是这类表单最强的视觉落点 */
.btn-block { display: flex; width: 100%; height: 44px; font-size: var(--fs-base); }

/* 回执区（成功 / 失败共用一块）。role=alert，读屏会朗读；空着时 [hidden] 不占位。
   ★ 失败用警示色对，成功用主色对 —— 两档都是已有的 :root 令牌，
     不新造 --c-success（全站当前只有这一处「成功」语义，按需再立令牌）。 */
.auth-msg {
  margin-top: 14px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--c-danger-bg);
  color: var(--c-danger);
  font-size: var(--fs-sm);
  line-height: 1.6;
}
.auth-msg[hidden] { display: none; }
.auth-msg.is-ok { background: var(--c-primary-soft); color: var(--c-primary-dark); }

/* ---------- 16. 响应式 ---------- */

@media (max-width: 1199px) {
  .container { padding: 0 16px; }
}

/* 992~1023px：桌面导航仍然在场（折叠阈值是 ≤991）。这一档把栏目左右内边距收到 11px。
   ★ 来历与现状（实测数据见 tools/_measure_nav_width.js）：
     历史上登录入口还挂在导航行末时，992px 的 scrollWidth 是 1009（溢出 +17px），
     这条规则是**补丁**；登录入口移除、导航字号/图标放大一档之后重新量过 —— 现在不溢出：
       · 992px（本规则生效，padding 11px）：留白 61.5px、溢出 0
       · 992px（临时关掉本规则，padding 15px）：留白 20.0px、溢出 0
     于是它从「补丁」变成了**余量**，保留着把最窄那一档的安全垫从 20px 拉到 61.5px。
   ★ 基础值（≥1024px）的 `padding: 0 15px` 才是与参考站对齐的口径（参考站原值 14px，
     随「导航放大一档」+1px）—— 别改基础规则来做窄屏适配（改了两边都变，且再也没法还原）。 */
@media (max-width: 1023px) {
  .nav-menu > li > a { padding: 0 11px; }
}

@media (max-width: 991px) {
  .main-wrap { grid-template-columns: minmax(0, 1fr); }
  .sidebar { margin-top: 4px; }

  .nav-toggle { display: flex; align-items: center; justify-content: center; }
  .nav-menu {
    position: absolute;
    top: 100%;
    right: 0;
    width: 200px;
    display: none;
    flex-direction: column;
    align-items: stretch;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-md);
    overflow: hidden;
    padding: 6px 0;
    z-index: 70;
  }
  .nav-menu.open { display: flex; }
  .nav-menu > li > a { height: 42px; line-height: 42px; padding: 0 16px; }

  /* —— 折叠态二级栏目：手风琴（点按 .sub-toggle 展开，不再常驻展开）——
     · li 改为 flex 行：父链接 flex:1、展开按钮 44px、子菜单 flex-basis:100% 换行占满整宽
     · 子菜单折叠用 max-height:0 + visibility:hidden：既不可见，也不进 Tab 顺序
       （只用 max-height 的话，折叠区域里的 <a> 仍可被 Tab 聚焦到，属于典型的隐藏内容陷阱）
     · visibility 走「展开立即 / 收起延迟」，与 .site-search 面板同一套写法 */
  .nav-menu > li { display: flex; flex-wrap: wrap; align-items: center; }
  .nav-menu > li > a { flex: 1 1 auto; min-width: 0; }
  /* 父链接自带的 ▼ 与展开按钮的箭头重复，折叠态只保留按钮那一个 */
  .nav-menu .caret::after { display: none; }

  .sub-toggle {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 42px;
    color: var(--c-text-body);
    transition: color var(--t-fast), transform var(--t-fast);
  }
  .sub-toggle::before {
    content: "";
    width: 0; height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid currentColor;
    transition: transform var(--t-fast);
  }
  .sub-toggle[aria-expanded="true"] { color: var(--c-primary-dark); }
  .sub-toggle[aria-expanded="true"]::before { transform: rotate(180deg); }
  .sub-toggle:active { transform: scale(var(--press)); }

  .nav-menu .sub-menu {
    flex: 0 0 100%;
    width: 100%;
    min-width: 0;
    position: static;
    /* 逐条抵消桌面浮层那套（居中定位 / 固定 140 / 描边 / 圆角 / 居中文字 / 位移 / 阴影）——
       折叠态是「内联铺开的手风琴」，不是浮层，任何一条漏掉都会跑偏 */
    left: auto;
    margin-left: 0;
    transform: none;
    border-radius: 0;
    box-shadow: none;
    border: 0;
    text-align: left;
    opacity: 1;
    visibility: hidden;
    padding: 0 0 0 14px;
    max-height: 0;
    overflow: hidden;
    transition: max-height var(--t-fast), visibility 0s var(--t-fast);
  }
  /* 顶部那个小尖角是浮层的装饰，内联展开时要去掉 */
  .nav-menu .sub-menu::before,
  .nav-menu .sub-menu::after { display: none; }
  /* 折叠态条目缩进 14px（父链接 padding 16px + 缩进 14px），比桌面浮层宽一点更好点 */
  .nav-menu .sub-menu li > a { padding: 7px 16px; }
  /* 展开上限取 70vh 而不是写死像素：参考站的「电脑软件」下面挂了 **16 个**子栏目
     （16 × 33.6 ≈ 538px），写死 420px 会把末尾几个直接裁掉 —— 而 overflow:hidden 之下
     被裁掉的条目不只是看不见，是点都点不到（内容真的丢了）。
     70vh 兼顾「动画不至于太空跑」与「够高」，再配 overflow-y:auto 兜底：
     万一某个栏目子项多到超过视口，也能滚动看全，不会静默丢内容。 */
  .nav-menu .sub-menu.open {
    visibility: visible;
    max-height: 70vh;
    overflow-y: auto;
    transition: max-height var(--t-fast), visibility 0s;
  }
  /* 导航折叠为下拉后，搜索图标仍留在头部（无需展开菜单即可搜索），☰ 紧随其后贴右边缘。
     此时 .nav-menu 是绝对定位、已脱离文档流，流内只剩搜索图标与 ☰ 两项，
     顺序与 DOM 一致（搜索在前、☰ 在后），因此不需要 order 反转。 */
  .main-nav { flex: 1 1 auto; justify-content: flex-end; min-width: 0; }

  /* 搜索面板去掉 20% 内缩、占满容器宽（对应参考站 ≤1024px 的 padding:37px 0） */
  .site-search-form { padding: 37px 0; }
}

@media (max-width: 767px) {
  .header-inner { min-height: 62px; }
  .logo-img { width: 36px; height: 36px; }
  .logo-text strong { font-size: var(--fs-lg); }

  /* 搜索面板降到中档（对应参考站 ≤768px：面板高 96px = 25×2 + 46） */
  .site-search { height: 96px; }
  .site-search-form { padding: 25px 0; }

  .article-card { gap: 12px; padding: 12px; }
  .article-thumb { flex: 0 0 118px; width: 118px; height: 84px; }
  .article-title { font-size: var(--fs-md); }
  .article-card .article-meta { gap: 10px; height: auto; overflow: visible; margin-top: 12px; }
  /* 小屏徽标：参考站是 font-size:10px / padding:3px 4px —— 10px 中文已低于可读下限，
     这里放宽到 11px 并按新胶囊模型重写（不再有 position:relative + top）。 */
  .sticky-icon { font-size: var(--fs-2xs); padding: 0 7px; margin-right: 6px; }

  .article-detail, .single-box { padding: 18px 16px 22px; }
  .article-header .article-title { font-size: var(--fs-xl); }
  .related-grid { grid-template-columns: repeat(2, 1fr); }
  .shot-grid { grid-template-columns: 1fr; }
  .qr-panel { grid-template-columns: 1fr; }
  .tb-right { display: none; }

  /* 分页：缩小尺寸，允许换行 */
  .pager { gap: 5px; padding: 16px 0 8px; }
  .pager .pg-item { height: 30px; font-size: var(--fs-xs); }
  .pager .page-num { width: 30px; height: 30px; font-size: var(--fs-xs); }
  .pager .pg-pill { width: auto; padding: 0 10px; border-radius: var(--radius-pill); }

  /* 登录/注册：窄屏把内边距从 36px 收到 20px。
     460px 视口下卡片只剩约 420px，沿用桌面内边距会让输入框窄得难填；
     弹窗同理，且外层 padding 也要收，否则卡片被挤到贴着视口边缘。 */
  .auth-page { padding: 22px 0 36px; }
  .auth-card, .sign-card { padding: 26px 20px 22px; }
  .sign { padding: 14px; }
}

@media (max-width: 479px) {
  /* 小屏：隐藏站点文字，把省下的宽度让给导航
     （logo 图标与它的 alt 文案仍保留站点标识，不影响可访问性） */
  .logo-text { display: none; }
  .header-inner { gap: 10px; }

  /* 搜索面板缩到最小档（对应参考站 ≤600px：面板高 66px = 15×2 + 36） */
  .site-search { height: 66px; }
  .site-search-form { padding: 15px 0; }
  .site-search-form .search-input { height: 36px; padding: 4px 10px; font-size: var(--fs-xs); }
  .site-search-form .search-btn { height: 36px; }

  .article-thumb { flex: 0 0 104px; width: 104px; height: 76px; }
  .article-excerpt { display: none; }
  .related-grid { grid-template-columns: 1fr; }
  .form-bottom { flex-wrap: wrap; }
  /* 小屏：输入框自己收缩（基准 160px + min-width:0），验证码与它同行；只有按钮独占一行 */
  .form-bottom .btn { margin-left: 0; width: 100%; }
  .action-bar { flex-direction: column; }
  .action-bar .btn { width: 100%; }

  /* 小屏打赏弹窗：内边距收紧、两个码的间距收窄 ——
     479px 下弹窗只有约 350px 宽，沿用桌面的 36px 内边距会把二维码压到 100px 以下，扫不动 */
  .modal { padding: 14px; }
  .modal-dialog { padding: 26px 20px 22px; }
  .reward-title { padding: 0 26px; font-size: var(--fs-lg); }
  .reward-qrs { gap: 14px; max-width: none; }
  .rq-box { padding: 9px; }
  .rq-logo { width: 28px; height: 28px; }

  /* 小屏：页码圆点换行，「共 N 页」与上下篇改为单列 */
  .pager .pg-total { display: none; }
  .article-prevnext { flex-direction: column; }
  .article-prevnext .pn-item.pn-next {
    border-left: 0;
    border-top: 1px solid var(--c-border);
    padding-left: 0;
    padding-top: 12px;
    margin-left: 0;
    margin-top: 12px;
    text-align: left;
  }
}
