/**
 * 资料目录（阅读 / 下载）· 前台样式
 *
 * 视觉沿用给客户看的那版 HTML 预览（`.workbuddy/预览-搜索栏独立与级联合并.html`）：
 * **工程蓝主色 + 平面化**（不堆阴影、不做渐变装饰）、文件行表格化对齐、
 * 额度条用浅底徽章、关键词用记号笔黄底。
 *
 * ⚠️ 与预览稿**有意保留的差异**（客户确认过）：
 *   1. 图标用**子比主题自带的 Font Awesome 4**（彩色底 + 白图标），
 *      预览稿用的是 FA6 —— 子比只有 FA4，且不额外加载以免跟主题抢类名。
 *   2. 字体跟随子比主题（不写死），否则跟整站风格脱节。
 *   3. 宽度占满页面内容区（由主题模板决定），预览稿是固定 1060px。
 *   4. 字号以 14px 为基准，且可被后台「目录面板」设置覆盖。
 *
 * 字号可以在后台设置（「目录面板 → 文件名大小」），这里只放**默认值**：
 * 后台填了值时，会由 PHP 追加一段内联样式覆盖下面这几个变量。
 */

.hfpan-cat,
/* ⚠️ ★ 0.13.15：**浮层也要带上这套 token** ─────────────────────────
   「目录搜索」的候选下拉（`.hfpan-cat__sdd`）被挂到了 `<body>` 上
   （为了躲开祖先的 `overflow: hidden`，见下面那段说明）——
   它**不再在 `.hfpan-cat` 子树里**，所以取不到这些变量，
   表现成「下拉透明、底下的内容透出来」。
   修法：把 token 块的选择器**并列**上它（**不复制色值** —— 改色仍然只改这一处）。
   ⚠️ 只并列 token，**不要**把下面的 margin / font-size 一起带过去 ——
      那些是容器自己的布局属性，浮层另有定义。
   ⚠️⚠️ ★ 0.13.51：**字号弹出层（`.hfpan-cat__fontdd`）也是挂 body 的**
      （同样为了躲 `overflow:hidden`），所以一并列进来 —— 漏了它，
      那个面板就是**一片透明**、底下的字透出来（老板实测：「没有背板 一片透明」）。
      ⚠️ 以后新加"挂 body 的浮层"，记得往这一串里加类名（浅色 + 深色两处共三处）。 */
.hfpan-cat__sdd,
.hfpan-cat__fontdd,
/* ⚠️⚠️★ 0.13.69：**视图模式菜单也挂 body** —— 同样取不到 `--hfpan-*`，
   不并列进来它就是**一片透明**（真机实测：菜单项白字浮在页面上，看不清）。
   ⚠️ 以后再加"挂 body 的浮层"，记得往这一串里加类名（浅色 + 深色两处）。 */
.hfpan-cat__viewmenu,
/* ⚠️⚠️★ 0.13.81：**权限额度说明弹窗也挂 body**（JS 把它搬到 `<body>` 下，
   躲开左栏抽屉的 `transform` 与祖先的 `overflow:hidden`，理由同上面几个）——
   同样取不到 `--hfpan-*`，不并列进来它就是**一片透明**。
   ⚠️ 这是**第四次**踩同一个坑（0.13.15 / 0.13.51 / 0.13.69）——
      以后再加"挂 body 的浮层"，往这一串里加类名（浅色 + 深色两处共三处）。 */
.hfpan-cat__qmodal,
/* ⚠️⚠️★ 0.14.22：**A~Z 放大气泡也挂 body**（`azBubble()` 里建的）——
   这是**第五次**踩同一个坑。表现和老板报的一模一样：
   气泡取不到 `--hfpan-blue` → `background: var(--hfpan-blue)` **整条失效**（背景透明），
   而 `color: #fff` 是**字面量**照常生效 → **白字浮在透明底上，看不见**。
   ⚠️ 教训：凡是"挂 body 的浮层"，**色值不许混用**（要么全变量、要么全字面量）——
      混用时变量那条静默失效、另一半还在，看起来就像"样式坏了一半"。
   ⚠️⚠️ 这条坑已经踩了 5 次（0.13.15 / 0.13.51 / 0.13.69 / 0.13.81 / 0.14.22），
      所以 0.14.22 起 `tools/check.php` **加了一条断言自动守它**：
      JS 里挂到 body 的类名，必须出现在这一串里（浅色 + 深色两处）。 */
.hfpan-cat__azbub {
    /* ══ 配色 token（改色只改这一处）══════════════════════════════
       ★ 0.8.0 起**整套跟随子比主题的浅色 / 深色模式**：
         · 浅色是默认值（写在下面这个块里）；
         · 深色在文件靠下那段「深色模式覆盖」里重新赋值（`.dark-theme .hfpan-cat`）。
       所以**下面这些变量在业务样式里一律不许再写死色值** —— 写死了深色模式就不生效。

       ⭐ 主色：老板 0.8.0 要求把原来的**深蓝**（#1e4e8c 工程蓝）换成
          **参考图那种浅蓝**（`#3199f8` → `#4eb7fa`，取自老板给的按钮截图）。
       ⭐ 命名沿用 `--hfpan-blue*`（历史原因），但它现在指的是「主题强调色」，
          不是「蓝色」—— 改色时改这一组就行。 */

    /* ── 强调色（浅色模式：参考图的亮蓝）── */
    --hfpan-blue: #3199f8;          /* 主色（按钮底 / 强调文字 / 选中描边） */
    --hfpan-blue-2: #4eb7fa;        /* 亮一档（渐变起点 / 悬停） */
    --hfpan-blue-dark: #1f7fd8;     /* 深一档（按下 / 描边加深） */
    --hfpan-blue-soft: #eaf4fe;     /* 极淡底（选中行 / 提示条） */
    --hfpan-blue-line: #b3d9fb;     /* 主色描边（浅） */
    --hfpan-blue-ink: #0b5ca8;      /* **浅蓝底上的深蓝文字**（保证对比度够读） */
    --hfpan-on-blue: #fff;          /* 主色块上的文字色 */

    /* ── ★★ 0.14.55：「当前：xxx」指示条前面那个定位图标的颜色 ──
       老板原话：「那个 fa-map-marker 图标改为**粉红色（固定的）**」。
       ⚠️⚠️ **故意写死、故意不跟主色走**（老板要的就是"固定"）：
          它不参与 `--hfpan-blue*` 那一组，所以**后台改全局颜色 / 勾跟随子比
          都不会影响它** —— 它在任何配色下都是这个粉。
       ⚠️ 深色模式**也不用单独覆盖**（这个粉在深底上照样看得清，
          所以下面那段深色覆盖里**故意没有它** —— 别"顺手补齐"）。 */
    --hfpan-pin: #f04494;

    /* ── 抬头（目录面板那条）──
       浅色模式用参考图的**浅蓝渐变**；深色模式会换成深蓝（见下方覆盖块），
       否则亮蓝底在深色页面里会亮得刺眼。 */
    --hfpan-head-bg: linear-gradient(90deg, var(--hfpan-blue-2), var(--hfpan-blue));
    --hfpan-head-fg: #fff;
    --hfpan-head-line: var(--hfpan-blue-dark);

    /* ── 中性色（表面 / 文字 / 线）── */
    --hfpan-surface: #fff;          /* 卡片底 */
    --hfpan-surface-2: #fbfcfd;     /* 次级底（面板内部） */
    --hfpan-surface-3: #f4f6f8;     /* 三级底（chip / 徽章） */
    --hfpan-ink: #1a1d21;           /* 正文 */
    --hfpan-ink-2: #5b6470;         /* 次要文字 */
    --hfpan-ink-3: #9aa0a6;         /* 弱化文字 / 占位符 */
    --hfpan-line: #dcdfe6;          /* 常规描边 */
    --hfpan-line-2: #eef0f2;        /* 更淡的分隔线 */

    /* ── 状态色（标记红 / 记号笔黄）── */
    --hfpan-mark: #c8102e;          /* 标记红（关键词 / 命中） */
    --hfpan-mark-soft: #fdecee;     /* 红底（命中行 / 搜索提示条） */
    --hfpan-mark-line: #f0c2c9;     /* 红描边 */
    --hfpan-pen: #e8a33d;           /* 记号笔黄（关键词黄底 / 搜索命中竖条） */
    --hfpan-pen-soft: rgba(232, 163, 61, .45);  /* 黄底（半透明，叠在任意底色上） */

    /* ── 额度卡（暖色系，与蓝色区分开）── */
    --hfpan-quota-bg: linear-gradient(#fffcf4, #fff7e6);
    --hfpan-quota-line: var(--hfpan-line);
    --hfpan-quota-pts: #8a6412;     /* 积分数字（暖棕） */
    --hfpan-vip1-bg: #fdf6e3;       /* 一级会员徽章 */
    --hfpan-vip1-line: #e2c88a;
    --hfpan-vip1-fg: #8a6412;
    --hfpan-vip2-bg: #fdeef2;       /* 二级会员徽章 */
    --hfpan-vip2-line: #d9a9b6;
    --hfpan-vip2-fg: #8e2f49;

    /* ── 阴影（深色模式下要弱化，否则像发光的黑块）── */
    --hfpan-shadow: 0 1px 2px rgba(26, 29, 33, .05);
    --hfpan-shadow-2: 0 8px 22px -14px rgba(26, 29, 33, .22);
    --hfpan-shadow-3: 0 1px 6px rgba(0, 0, 0, .12);
    --hfpan-shadow-4: 0 8px 28px rgba(0, 0, 0, .16);
    --hfpan-veil: rgba(255, 255, 255, .97);  /* 浮层底（翻译浮层等） */

    /* ── 卡片圆角（★ 0.14.27 抽出来的）────────────────────────────────
       原来这个值在几处各写各的（`.hfpan-cat__search` / 面板 / 弹出层都是 6px）。
       0.14.27 要求「手机端搜索框和上方的类型**保持同样的卡片样式和圆角角度**」——
       要"同样"就必须有**唯一来源**，所以抽成变量。
       ⚠️ 是**圆角**（radius）不是边框色，深色模式不需要覆盖它（值一样）。 */
    /* ⚠️★ 0.14.27：把「搜索」按钮的宽度**抽成变量** ——
       手机端「类型」那张小卡片的宽度要从它**推导**（见 ≤640px 那段）。
       写死 65 的话，将来改按钮文案/字号，对齐就又崩了（刚踩过一次）。 */
    --hfpan-radius-card: 6px;
    --hfpan-sgo-w: 65px;            /* = 「搜索」按钮的 padding 0 18px ×2 + 两字 */

    /* ── 文件类型图标底色（按类型分色，**不跟随主题色**）──
       这些是"文件类型"的语义色（PDF 红、Excel 绿…），深色模式只微调亮度。 */
    --hfpan-ico-dir: #f0b429;
    --hfpan-ico-pdf: #d9534f;
    --hfpan-ico-img: #4a90d9;
    --hfpan-ico-vid: #7b61c9;
    --hfpan-ico-aud: #e08a3c;
    --hfpan-ico-zip: #c9a227;
    --hfpan-ico-doc: #4a7fd9;
    --hfpan-ico-xls: #3fa06a;
    --hfpan-ico-ppt: #d9643a;
    --hfpan-ico-code: #5f6b7a;
    --hfpan-ico-other: var(--hfpan-ink-3);

    /* ── 预览区 / 工具条 ── */
    --hfpan-viewer-bg: #f1f2f4;     /* 预览画布底色（放文档的那块） */
    --hfpan-tool-bg: var(--hfpan-surface);
    --hfpan-tool-hover: var(--hfpan-surface-3);

    /* ══ 可自定义的字号（★ 0.13.48：**挪到前台**，每个访客自己调、只影响自己）══
       · `--hfpan-fname-size` → 左栏文件夹名 + 文件名 + 搜索结果
       · `--hfpan-azl-size`   → 品牌悬浮 A~Z 首字母
       值由「前台字号控件」写（localStorage + cookie 双写），
       并且**首次请求就由 PHP 从 cookie 读出来提前应用**（防闪一下）。
       ⚠️ 0.7.7 去掉了 `--hfpan-fsize-size`（文件大小已不在前台显示）。
       ⚠️ 0.13.48 去掉了 `--hfpan-panehead-size` —— 老板只要两项，
          「面板标题」那项连同后台那一组一起撤了。 */
    --hfpan-fname-size: 14px;
    --hfpan-azl-size: 10.5px;
}

/* ⚠️ 只属于**容器**的布局属性（浮层不参与，所以单独一条规则） */
.hfpan-cat {
    margin: 0 0 22px;

    /* ⚠️ 字号必须显式定：不设就会继承主题正文的字号，
       子比的正文偏大 —— 左栏文件名会被放得很大、把版面压得很难看。
       整块以 14px 为基准，内部元素按需在这个基础上微调。 */
    font-size: 14px;
    line-height: 1.55;
    color: var(--hfpan-ink);
}

/* ══ ★ 0.8.0 深色模式覆盖 ══════════════════════════════════════════
   子比切深色时会给 `body` 加 `dark-theme` 类（`js/main.js` 的 `.toggle-theme`），
   深色变量在主题的 `.dark-theme{...}` 里（css/main.css）。

   ⚠️ 三种选择器都要覆盖，缺一种就有场景漏掉：
      · `body.dark-theme`  —— 子比手动切换（PC 导航 / 移动菜单的切换按钮）
      · `html.dark`        —— 主题切换时也会给 html 加 `dark`（防闪烁）
      · `prefers-color-scheme: dark` —— 系统级深色（用户没手动切时）

   ⚠️ 选择器必须写成 `.dark-theme .hfpan-cat`（后代），
      **不能写 `.hfpan-cat.dark-theme`** —— 那个类是加在 body 上的，不在我们容器上。
   ⚠️ 特异性：`.dark-theme .hfpan-cat` 是 (0,2,0)，高于 `.hfpan-cat` 的 (0,1,0)，
      所以能盖住上面的默认值，**不需要 !important**。 */
body.dark-theme .hfpan-cat,
html.dark .hfpan-cat,
[data-theme="dark"] .hfpan-cat,
/* ⚠️ ★ 0.13.15：浮层挂到 body 上了，深色覆盖也要带上它，否则深色站上是个白块 */
body.dark-theme .hfpan-cat__sdd,
html.dark .hfpan-cat__sdd,
[data-theme="dark"] .hfpan-cat__sdd,
/* ⚠️ ★ 0.13.51：字号弹出层同样挂 body，深色覆盖一样要带上 */
body.dark-theme .hfpan-cat__fontdd,
html.dark .hfpan-cat__fontdd,
[data-theme="dark"] .hfpan-cat__fontdd,
/* ★ 0.13.69：视图菜单同样挂 body，深色覆盖也要带上 */
body.dark-theme .hfpan-cat__viewmenu,
html.dark .hfpan-cat__viewmenu,
[data-theme="dark"] .hfpan-cat__viewmenu,
/* ⚠️ ★ 0.13.81：说明弹窗同样挂 body，深色覆盖也要带上它 */
body.dark-theme .hfpan-cat__qmodal,
html.dark .hfpan-cat__qmodal,
[data-theme="dark"] .hfpan-cat__qmodal,
/* ⚠️⚠️★ 0.14.22：A~Z 放大气泡同样挂 body（第五次踩同一个坑）——
   深色覆盖不带上的话，深色站上它会拿到**浅色**的 `--hfpan-blue`（亮蓝），
   虽然不是"透明"了，但和深色主题不搭。两处都要加。 */
body.dark-theme .hfpan-cat__azbub,
html.dark .hfpan-cat__azbub,
[data-theme="dark"] .hfpan-cat__azbub {
    /* ── 强调色：深色底上要用**更亮**的蓝才看得清 ── */
    --hfpan-blue: #4aa8f5;
    --hfpan-blue-2: #6cbcf8;
    --hfpan-blue-dark: #2f8ade;
    --hfpan-blue-soft: #16304a;     /* 深底上的"淡蓝底"＝深蓝 */
    --hfpan-blue-line: #2b567f;
    --hfpan-blue-ink: #9ed0fd;      /* 深底上强调色文字＝亮蓝 */
    --hfpan-on-blue: #0b1a26;       /* 亮蓝底上用深字（白字对比度不够） */

    /* ── 抬头：深色模式换成**深蓝底 + 亮字** ──
       （亮蓝底在深色页面里太刺眼；深蓝底才压得住，也还看得出是"主色区"） */
    --hfpan-head-bg: linear-gradient(90deg, #1d4a78, #163a5f);
    --hfpan-head-fg: #d6e9fb;
    --hfpan-head-line: #0d2740;

    /* ── 中性色（对齐子比的深色变量，见 css/main.css 的 `.dark-theme`）──
       子比：--main-bg-color #323335 / --body-bg-color #292a2d /
             --muted-bg-color #2d2e31 / --main-color #e5eef7 / --muted-color #b4b6bb */
    --hfpan-surface: #323335;
    --hfpan-surface-2: #2d2e31;
    --hfpan-surface-3: #37383a;
    --hfpan-ink: #e5eef7;
    --hfpan-ink-2: #b4b6bb;
    --hfpan-ink-3: #888a8f;
    --hfpan-line: #43454a;
    --hfpan-line-2: #3a3c40;

    /* ── 状态色：深底上要降饱和 / 提亮，否则红得刺眼 ── */
    --hfpan-mark: #ff7b8f;
    --hfpan-mark-soft: #3a2228;
    --hfpan-mark-line: #5c2f38;
    --hfpan-pen: #e8a33d;
    --hfpan-pen-soft: rgba(232, 163, 61, .32);

    /* ── 额度卡：深色版暖调（原来是米黄，深底上要压成暗棕）── */
    --hfpan-quota-bg: linear-gradient(#3a352a, #333026);
    --hfpan-quota-pts: #e8c56a;
    --hfpan-vip1-bg: #3a3524;
    --hfpan-vip1-line: #6b5a2e;
    --hfpan-vip1-fg: #e8c56a;
    --hfpan-vip2-bg: #3a2830;
    --hfpan-vip2-line: #6b3d4c;
    --hfpan-vip2-fg: #f0a8bd;

    /* ── 阴影：深色下要更重更散，否则看不出层次 ── */
    --hfpan-shadow: 0 1px 2px rgba(0, 0, 0, .3);
    --hfpan-shadow-2: 0 8px 22px -14px rgba(0, 0, 0, .6);
    --hfpan-shadow-3: 0 1px 6px rgba(0, 0, 0, .4);
    --hfpan-shadow-4: 0 8px 28px rgba(0, 0, 0, .5);
    --hfpan-veil: rgba(45, 46, 49, .97);

    /* ── 文件类型图标：深色下略降亮度，免得跳出来 ── */
    --hfpan-ico-dir: #d9a125;
    --hfpan-ico-img: #4a86c4;
    --hfpan-ico-doc: #4472bf;
    --hfpan-ico-xls: #3a8f60;
    --hfpan-ico-code: #6b7686;
    --hfpan-ico-other: var(--hfpan-ink-3);

    /* ── 预览区底色：深色下用更深的一档 ── */
    --hfpan-viewer-bg: #292a2d;
    --hfpan-tool-bg: var(--hfpan-surface);
    --hfpan-tool-hover: var(--hfpan-surface-3);
}

/* 系统级深色（用户没手动切、也没配过 Cookie 时）——
   与上面那份**值完全一致**，只是选择器不同，所以用变量复用避免写两遍。
   ⚠️ 放在 `@media` 里，特异性同 (0,2,0)，靠顺序覆盖默认值。 */
@media (prefers-color-scheme: dark) {
    body:not(.dark-theme) .hfpan-cat,
    /* ⚠️ ★ 0.13.15：同上 —— 浮层在 body 下，也要跟系统级深色 */
    body:not(.dark-theme) .hfpan-cat__sdd,
    /* ⚠️ ★ 0.13.51：字号弹出层同样 */
    body:not(.dark-theme) .hfpan-cat__fontdd,
    /* ★ 0.13.69：视图菜单同样 */
    body:not(.dark-theme) .hfpan-cat__viewmenu,
    /* ★ 0.13.81：说明弹窗同样（挂 body） */
    body:not(.dark-theme) .hfpan-cat__qmodal {
        --hfpan-blue: #4aa8f5;
        --hfpan-blue-2: #6cbcf8;
        --hfpan-blue-dark: #2f8ade;
        --hfpan-blue-soft: #16304a;
        --hfpan-blue-line: #2b567f;
        --hfpan-blue-ink: #9ed0fd;
        --hfpan-on-blue: #0b1a26;

        --hfpan-head-bg: linear-gradient(90deg, #1d4a78, #163a5f);
        --hfpan-head-fg: #d6e9fb;
        --hfpan-head-line: #0d2740;

        --hfpan-surface: #323335;
        --hfpan-surface-2: #2d2e31;
        --hfpan-surface-3: #37383a;
        --hfpan-ink: #e5eef7;
        --hfpan-ink-2: #b4b6bb;
        --hfpan-ink-3: #888a8f;
        --hfpan-line: #43454a;
        --hfpan-line-2: #3a3c40;

        --hfpan-mark: #ff7b8f;
        --hfpan-mark-soft: #3a2228;
        --hfpan-mark-line: #5c2f38;
        --hfpan-pen-soft: rgba(232, 163, 61, .32);

        --hfpan-quota-bg: linear-gradient(#3a352a, #333026);
        --hfpan-quota-pts: #e8c56a;
        --hfpan-vip1-bg: #3a3524;
        --hfpan-vip1-line: #6b5a2e;
        --hfpan-vip1-fg: #e8c56a;
        --hfpan-vip2-bg: #3a2830;
        --hfpan-vip2-line: #6b3d4c;
        --hfpan-vip2-fg: #f0a8bd;

        --hfpan-shadow: 0 1px 2px rgba(0, 0, 0, .3);
        --hfpan-shadow-2: 0 8px 22px -14px rgba(0, 0, 0, .6);
        --hfpan-shadow-3: 0 1px 6px rgba(0, 0, 0, .4);
        --hfpan-shadow-4: 0 8px 28px rgba(0, 0, 0, .5);
        --hfpan-veil: rgba(45, 46, 49, .97);

        --hfpan-ico-dir: #d9a125;
        --hfpan-ico-img: #4a86c4;
        --hfpan-ico-doc: #4472bf;
        --hfpan-ico-xls: #3a8f60;
        --hfpan-ico-code: #6b7686;

        --hfpan-viewer-bg: #292a2d;
    }
}

/* ── 搜索栏（0.5.2：**独立成一条**，不再与面板连成一张卡片）──────
   老板参考图：搜索栏单独一条坐在最上面（左「类型」/ 中关键词 / 右搜索），
   面板另起一张卡片。
   ⚠️ 0.5.0 曾把它做成「整块的第一行」（border-bottom:0 连体写法），
      0.5.2 按老板要求拆开 —— 别再改回去。 */
.hfpan-cat__search {
    display: flex;
    align-items: stretch;
    margin-bottom: 12px;              /* 与下方面板拉开距离，视觉上独立成条 */
    border: 1px solid var(--hfpan-line);
    border-radius: 6px;
    background: var(--hfpan-surface);
    box-shadow: var(--hfpan-shadow);
    overflow: hidden;
}

.hfpan-cat__searchtype {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 12px;
    border-right: 1px solid var(--hfpan-line);
    flex: none;
}

/* ⚠️⚠️ 0.14.37：类型卡"拉伸到与二级目录左边对齐"的规则**放在文件末尾**了 ——
   原因：第 353 行这条基础规则**本身就在 `@media (prefers-color-scheme: dark)`
   块里面**（那个块从第 276 行开始）。我第一版把新的 `@media (min-width: 641px)`
   写在它下面 → **`@media` 嵌 `@media` 是无效 CSS，整块被浏览器丢掉**，
   规则只在夜间模式（误打误撞）生效，白天完全没效果。
   → 现在挪到**文件最末尾的顶层**，见文件最后那一段（搜 `0.14.37`）。 */

.hfpan-cat__searchlbl {
    color: var(--hfpan-ink-2);
    white-space: nowrap;
}

.hfpan-cat__skind {
    border: 1px solid var(--hfpan-blue-line);
    border-radius: 4px;
    background: var(--hfpan-surface);
    color: var(--hfpan-blue-ink);
    font-weight: 600;
    padding: 6px 8px;
    cursor: pointer;
    /* ★ 0.5.4：类型下拉的宽度**按内容自适应**。
       原来写死 min-width:96px，客户把大类名改长（如「自定义占位符（仅下载）」）后
       会被截成「自定义占位符（仅下…」，站长看不出自己配了啥。
       `field-sizing` 兼容性还不够，所以用「够宽的下限 + 允许撑开」这个稳妥写法。 */
    min-width: 120px;
    max-width: 260px;
    width: auto;
    text-overflow: ellipsis;
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.27 / 0.14.31：**分类图标放哪**（老板改过一次口径，别搞混）
   ── 0.14.27 的口径 ──────────────────────────────────────────────────────
     老板原话：「然后如图 把这个全部放到**类型名字**的前面 下拉的也要做」
     → 当时理解成：① 「分类」二字前面；② 下拉每个选项前面。
   ── 0.14.31 的口径（**现在**）──────────────────────────────────────────
     老板原话：「分类前面的fa图标应该放到 **文档（仅供阅读）前面**」
     → 图标跟**当前选中的分类名**走，**不跟「分类」这两个字走**：
       · 「分类」标签卡里**不放图标**（就是纯文字）；
       · 自绘触发条里：`[图标] 文档（仅供阅读） ▾` ✓
       · 下拉每个选项前面仍然有 ✓
   ── ⚠️⚠️ 为什么原生 select / 原生 option 上的图标**整个撤掉了** ──────────
     ① 老板要求「图标都要**兼容日夜间**」，而 CSS `background-image`
        **取不到 `currentColor`**（背景图不是 DOM，继承不到 `color`）
        → 夜里还是黑的 ✗；能用 `currentColor` 的只有内联 `<svg><use>`，
        而 `<select>` / `<option>` 里塞不进 svg；
     ② 老板说「**电脑用户可以不用**写类型名称和这些改动 目前做的改动只是根据
        手机用户」→ 桌面端本来就该保持原样。
     → 所以图标**只留在手机端的自绘下拉**里（触发条 + 选项列表，都走 sprite）。
     ⚠️ 代价：JS 没跑时手机端退回原生 select，那一格**没有图标** —— 可以接受，
        "能用"比"好看"重要（见 `.is-built` 那条失败安全）。
   ══════════════════════════════════════════════════════════════════════════ */
/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.27：**自定义分类下拉**（老板要求「下拉的也要做」）
   ── 为什么不能直接用原生 `<select>` ──────────────────────────────────────
     老板要给**每个选项**前面加图标。而原生 `<option>` **只吃文本**：
       · 塞 `<img>` / 伪元素 → 被浏览器直接丢掉（只剩文字）；
       · 用 `background-image` → Chrome / Edge **忽略 option 的背景图**
         （实测；Firefox 能显示，Safari 不能）→ 不可靠。
     → 所以做一个**自绘下拉**：视觉层自己画，原生 select 留在 DOM 里当数据源。
   ── 与原生 select 的分工（关键设计）────────────────────────────────────
     · **桌面端仍用原生 select**（老板说「电脑用户可以不用…这些改动」）——
       自绘层 `display: none`，一行都不影响桌面；
     · **手机端（≤640px）**：原生 select `display: none`（它开的是系统浮层、
       没法加图标），自绘的触发条 + 选项列表接管。
     · 自绘层只是**改 `select.value` 并派发 `change`** ——
       `catalog.js` 里那些 `skind.value` / `addEventListener('change')`
       **一行都不用改**（这是能这么做的前提）。
   ── ⚠️ 挂在哪 ───────────────────────────────────────────────────────────
     挂在 `.hfpan-cat__searchtype`（那张卡）里、`position: absolute`，
     列表向下展开、宽度对齐整张卡 —— 卡本身没有 `overflow:hidden`，
     不会被裁（同 `.hfpan-cat__bdd` 的路径，真机验过）。
   ══════════════════════════════════════════════════════════════════════════ */
.hfpan-cat__kindsel {
    position: relative;
    display: flex;
    align-items: center;
    /* 手机上吃满「分类」卡片左边的空间（和原生 select 的 flex:1 同一个作用） */
    flex: 1 1 auto;
    min-width: 0;
}

/* 自绘的触发条：观感**照抄原生 select**，只是多了图标 */
.hfpan-cat__kindtrig {
    display: none;            /* 桌面隐藏，只在手机上接管 */
    align-items: center;
    gap: 7px;
    width: 100%;
    min-height: 42px;
    padding: 6px 8px 6px 10px;
    border: 1px solid var(--hfpan-blue-line);
    border-radius: 4px;
    background: var(--hfpan-surface);
    /* ⚠️★ 0.14.31：**不再用 `background-image` 放图标** ──────────────────
       老板要求「图标都要兼容日夜间」，而 CSS 背景图**取不到 `currentColor`**
       （背景图不是 DOM，继承不到 `color`）→ 夜里还是黑的 ✗
       → 图标改成按钮里的内联 `<svg><use>`（见 `.hfpan-cat__kindtrig__ic`），
         背景图这条连同 `padding-left` 一起撤掉。 */
    color: var(--hfpan-blue-ink);
    font: inherit;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
}

/* 当前分类名前面的图标（跟**分类名**走，不跟「分类」标签走）——
   走 sprite，颜色继承按钮的 `--hfpan-blue-ink`，日夜自动跟随 ✓ */
.hfpan-cat__kindtrig__ic {
    flex: none;
    display: block;
    width: 15px;
    height: 15px;
    pointer-events: none;
}

/* 右侧那个小箭头（原生 select 的箭头是 UA 画的，自绘的要自己来） */
.hfpan-cat__kindtrig::after {
    content: "";
    flex: none;
    width: 0;
    height: 0;
    margin-left: auto;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 6px solid currentColor;
    opacity: .75;
}

.hfpan-cat__kindtrig__txt {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 展开的选项列表 */
.hfpan-cat__kindlist {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(100% + 4px);
    z-index: 42;
    max-height: 260px;
    overflow: auto;
    padding: 4px;
    background: var(--hfpan-surface);
    border: 1px solid var(--hfpan-line);
    border-radius: var(--hfpan-radius-card);
    box-shadow: var(--hfpan-shadow-4);
}

/* ⚠️★ `[hidden]` 必须显式写 `display: none` —— 下面 `.hfpan-cat__kindopt` 是
   `display: flex`，**作者样式优先级高于 UA 的 `[hidden]{display:none}`**，
   不写这条 `el.hidden = true` 就藏不住（本项目 0.13.82 踩过同款）。 */
.hfpan-cat__kindlist[hidden] { display: none; }

.hfpan-cat__kindopt {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 8px;
    border-radius: 4px;
    font-size: 14px;
    color: var(--hfpan-ink);
    cursor: pointer;
}

.hfpan-cat__kindopt:hover,
.hfpan-cat__kindopt.is-cur { background: var(--hfpan-blue-soft); }

.hfpan-cat__kindopt.is-cur { color: var(--hfpan-blue-ink); font-weight: 600; }

/* 选项前面的分类图标 */
.hfpan-cat__kindopt__ic {
    flex: none;
    width: 15px;
    height: 15px;
    display: block;
    opacity: .62;
}

.hfpan-cat__kindopt.is-cur .hfpan-cat__kindopt__ic { opacity: .9; }

/* 标签卡里的图标（`.hfpan-cat__searchchip` 内）：和文字同色系、垂直居中 */
.hfpan-cat__searchchip__ic {
    width: 14px;
    height: 14px;
    display: block;
    margin-right: 5px;
    /* ⚠️★ 0.14.27：这个图标现在走 **sprite**（内联 `<svg><use>`），
       不再是 `<img>` —— 那个 svg 里写的是 `fill="currentColor"`，
       所以它**会跟随主题色**（`<img>` 做不到这一点，这也是当初写成 `<img>` 的理由，
       但代价是被子比主题塞 alt + 绑灯箱）。`opacity` 保留：让图标比文字轻一点。 */
    opacity: .62;
}

/* 手机上让它占满那一行（搜索栏在手机端会换行） */
@media (max-width: 640px) {
    .hfpan-cat__skind {
        flex: 1;
        max-width: none;
    }
}

.hfpan-cat__searchkw {
    flex: 1;
    display: flex;
    align-items: center;
    /* ⚠️★ 0.14.32：**gap 必须是 0** ──────────────────────────────────
       0.14.27 之前，「重置」「搜索」是 `.hfpan-cat__search` 的直接子元素、
       彼此**没有间距** → 重置那条分隔线**紧贴着**蓝色搜索按钮，观感是一条完整的栏。
       搬进本容器之后，容器的 `gap: 8px` 在**两者之间塞了 8px 的白**，
       分隔线右边就多出一段空白（老板截图问「这左边多出来的白的又是什么啊」）✗
       → gap 归零，间距改成**挂在图标和输入框自己身上**（见下面两条），
         这样"重置 ↔ 搜索"之间是 0，和改之前一致。 */
    gap: 0;
    /* ⚠️★ 0.14.31：右边距也必须是 0（让最后一个子元素贴到卡片右缘）——
       原来 `padding: 0 12px`，搜索按钮右缘会差 12px，
       看着像"浮在栏里的一个小方块"（老板要求「占满右边然后圆角」）。 */
    padding: 0 0 0 12px;
    min-width: 0;
    /* ⚠️ 0.13.14：必须是定位上下文 —— 「目录搜索」的候选下拉靠它绝对定位 */
    position: relative;
}

/* gap 归零之后，这两处间距要自己补（原来是容器的 gap / 内边距给的）：
   ① 放大镜 → 输入框：8px（和原来的 gap 一致）
   ② 输入框 → 重置：12px（原来是容器的右内边距）
   ⚠️ 别改回用 `gap`：那样"重置 ↔ 搜索"之间又会裂出白缝。 */
.hfpan-cat__searchkw .hfpan-cat__searchicon {
    margin-right: 8px;
}

.hfpan-cat__searchkw .hfpan-cat__skw {
    margin-right: 12px;
}

/* ⚠️★ 0.14.31：**这两个按钮要撑满整条高度** ────────────────────────────
   0.14.27 之前它们是 `.hfpan-cat__search` 的直接子元素，那个容器是
   `align-items: stretch` → 按钮自然填满整条（约 46px）。
   搬进 `.hfpan-cat__searchkw` 之后，这个容器是 `align-items: center`
   （为的是让放大镜与文字垂直居中）→ 两个按钮**不再被拉伸**，
   桌面端缩成内容高度（实测：搜索按钮只剩 **22px**，而卡片高 **44px**）✗
   → 单独给它们 `align-self: stretch` 恢复"占满右边"。
   （手机端本来就有 `min-height: 48px`，加上这条不冲突。） */
.hfpan-cat__searchkw .hfpan-cat__sgo,
.hfpan-cat__searchkw .hfpan-cat__sreset {
    align-self: stretch;
}

/* ══════════════════════════════════════════════════════════════
 * ★ 0.13.14：「目录搜索」的候选下拉（搜索框下面那一层）
 * ── 它由 **JS 动态创建**，并且**挂在 `<body>` 上**（不是挂在搜索框里！）。
 * ── ⚠️⚠️ 为什么必须挂到 body + `position: fixed` ──────────────────
 *   一开始我把它挂在 `.hfpan-cat__searchkw` 里、用 `position: absolute`。
 *   验收站实测：**它被祖先的 `overflow: hidden` 整块裁掉了** ——
 *     ① 我们自己的 `.hfpan-cat__search` 有 `overflow: hidden`；
 *     ② 主题的 `article` 容器也有 `overflow: hidden`。
 *   结果：DOM 里它是开着的（`hidden=false`、4 条候选、`display:block`），
 *   但用户**什么都看不见**。
 *   ⚠️ 更坑的是：**DOM 断言与 Playwright 的点击都发现不了** ——
 *      `isHidden()` 只看 hidden/display，祖先裁剪不影响它；
 *      Playwright 也照样点得到。**只有截图才看得出来。**
 *   所以：挂到 body（脱离所有祖先）+ `position: fixed`（坐标由 JS 按搜索框算）。
 *   ⚠️ 副作用：页面滚动时要重新定位 —— 见 catalog.js 的 sdPlace()。
 * ── 候选每条的样式**复用级联那套**（.hfpan-cat__lddopt / __lddname / __lddpath /
 *    __lddhd / __lddempty）—— 两处的观感必须一致，别再写一套。
 * ── ⚠️ 默认 `hidden` + 自己设了 display → 必须进文件底部那段 hidden 兜底名单。
 * ══════════════════════════════════════════════════════════════ */
.hfpan-cat__sdd {
    position: fixed;            /* ⚠️ 不能改回 absolute —— 会被祖先 overflow:hidden 裁掉 */
    z-index: 9999;              /* 主题的吸顶导航等在 1000 上下，这里要压过去 */
    max-height: 320px;
    overflow: auto;
    background: var(--hfpan-surface);
    border: 1px solid var(--hfpan-line);
    border-radius: 6px;
    box-shadow: var(--hfpan-shadow-4);
    /* ⚠️ 它脱离了 `.hfpan-cat` 子树，**字号必须自己定**（否则继承主题正文，偏大） */
    font-size: 14px;
    line-height: 1.55;
    color: var(--hfpan-ink);
    /* left / top / width 由 JS 按搜索框的位置写死（inline style） */
}

.hfpan-cat__searchicon {
    color: var(--hfpan-ink-3);
    font-size: 13px;
    line-height: 1;
    /* ★ 0.14.31：这里是 **Font Awesome 的 fa-search**（`magnifying-glass`），
       走 sprite 的 `<use>` —— 所以 `color` 能生效（`currentColor` 继承），
       日间 `--hfpan-ink-3` 深灰、夜间自动变浅，**日夜都看得见**。
       ⚠️ 0.13.83~0.14.30 它是老板给的 `<img>`（写死 `#050505`）——
          那种做法夜里图标是黑的（老板报的问题），所以换掉了。
       ⚠️ `width/height` 仍要显式给：内联 svg 默认 300×150，不给会撑爆。 */
    flex: none;
    display: block;
    width: 15px;
    height: 15px;
}

.hfpan-cat__skw {
    border: 0;
    outline: none;
    background: transparent;
    flex: 1;
    padding: 11px 0;
    font-size: 14px;
    min-width: 0;
    color: var(--hfpan-ink);
}

.hfpan-cat__skw::placeholder {
    color: var(--hfpan-ink-3);
}

.hfpan-cat__sgo {
    border: 0;
    background: var(--hfpan-blue);
    color: var(--hfpan-on-blue);
    font-weight: 600;
    letter-spacing: 1px;
    padding: 0 24px;
    cursor: pointer;
    flex: none;
    transition: background .14s;
    /* ★ 0.14.31：**右侧圆角**（老板要求「占满右边然后圆角的按钮」）────────
       它是搜索卡最右端的元素、贴着卡片右缘，所以圆角只给右边两角，
       半径用卡片那个变量 —— 和卡片自己的圆角**逐像素对齐**，
       不会出现"按钮圆角与卡片圆角错开一条缝"。
       左侧两角保持直角：它左边还接着输入框/重置，圆了会裂开。
       ⚠️ 这条原来是写在手机端媒体查询里的；0.14.31 提到基础样式 ——
          桌面端同样需要（老板截图就是桌面端）。
       ⚠️ 卡片有 `overflow:hidden` 也会切一次角，两者结果一致，互为保险。 */
    border-radius: 0 var(--hfpan-radius-card) var(--hfpan-radius-card) 0;
}

.hfpan-cat__sgo:hover {
    background: var(--hfpan-blue-dark);
}

/* ══ ★★ 0.13.48/0.13.50：前台「字号」控件（老板要求：挪到前台、每人只影响自己）══
   按钮在**阅读器上方那条工具条**里（老板原话：「字号不是放在阅读器上方吗
   怎么又跑目录了啊」—— 我第一版放进了目录面板抬头，错了）。
   ⚠️ 所以这里照工具条按钮 `.hfpan-cat__tbtn` 那套观感写，别写抬头那种白描边。
   ⚠️「只下载」类型没有工具条 → 它的按钮落在 `.hfpan-cat__brandbar` 里，同一套样式够用。 */
.hfpan-cat__fontbtn {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 4px 12px;
    border: 1px solid var(--hfpan-line);
    border-radius: 5px;
    background: var(--hfpan-surface);
    color: var(--hfpan-ink);
    font: inherit;
    font-size: 13px;
    line-height: 1.5;
    cursor: pointer;
    white-space: nowrap;
    transition: all .15s ease;
}

.hfpan-cat__fontbtn:hover {
    border-color: var(--hfpan-blue);
    color: var(--hfpan-blue-ink);
}

/* 面板开着时按钮保持"按下"态（跟「品牌」按钮一个口径） */
.hfpan-cat__fontbtn[aria-expanded="true"] {
    border-color: var(--hfpan-blue);
    color: var(--hfpan-blue-ink);
    background: var(--hfpan-blue-soft);
}

.hfpan-cat__fontbtn__big {
    font-size: 15px;
    font-weight: 700;
    line-height: 1;
}

.hfpan-cat__fontbtn__txt { margin-left: 1px; }

/* ── 弹出面板 ────────────────────────────────────────────────────────
   ⚠️⚠️ 必须 **挂 body + position:fixed**：抬头的祖先链上有 `overflow:hidden`
      （`.hfpan-cat__left` / `.hfpan-cat__body` / `.hfpan-cat__panel` 都是），
      挂在原地会被**裁掉** —— 预览稿实测：截图里只剩按钮、弹出层整块不见，
      而 DOM 断言与模拟点击都测不出来（项目 0.13.16 记过这个血案）。 */
.hfpan-cat__fontdd {
    position: fixed;
    z-index: 9990;
    width: 246px;
    padding: 10px 12px;
    background: var(--hfpan-surface);
    border: 1px solid var(--hfpan-line);
    border-radius: 8px;
    box-shadow: var(--hfpan-shadow-4);
    font-size: 12.5px;
    color: var(--hfpan-ink);
}

.hfpan-cat__fontdd[hidden] { display: none; }

.hfpan-cat__fontdd__row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 7px 0;
}

.hfpan-cat__fontdd__row:first-child { margin-top: 0; }
.hfpan-cat__fontdd__row:last-child { margin-bottom: 0; }

.hfpan-cat__fontdd__lbl {
    flex: 0 0 74px;
    color: var(--hfpan-ink-2);
}

.hfpan-cat__fontdd__step {
    width: 26px;
    height: 24px;
    border: 1px solid var(--hfpan-line);
    border-radius: 5px;
    background: var(--hfpan-surface);
    color: var(--hfpan-ink);
    font: inherit;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
}

.hfpan-cat__fontdd__step:hover { border-color: var(--hfpan-blue); color: var(--hfpan-blue-ink); }

.hfpan-cat__fontdd__val {
    flex: 0 0 52px;
    text-align: center;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.hfpan-cat__fontdd__reset {
    margin-left: auto;
    border: 0;
    background: transparent;
    color: var(--hfpan-blue-ink);
    font: inherit;
    font-size: 12px;
    text-decoration: underline;
    cursor: pointer;
}

.hfpan-cat__fontdd__warn {
    margin: 8px 0 0;
    padding: 6px 8px;
    border: 1px solid #ffd400;
    border-radius: 5px;
    background: #fffdf0;
    color: #7a5d00;
    font-size: 11.5px;
}

.hfpan-cat__fontdd__warn[hidden] { display: none; }

/* 深色模式下那条黄提示别太扎眼 */
body.dark-theme .hfpan-cat__fontdd__warn,
html.dark .hfpan-cat__fontdd__warn,
[data-theme="dark"] .hfpan-cat__fontdd__warn {
    border-color: #6b5a2e;
    background: #3a3524;
    color: #e8c56a;
}

/* ══ ★ 0.13.46：搜索栏**尾侧**的「重置」（老板要求挪过来）════════════════
   老板原话：「重置按钮移动到搜索栏尾侧」。
   ── 为什么用 `.hfpan-cat__search .hfpan-cat__sreset` 这种两段选择器 ──
     这个按钮身上同时挂着 `.hfpan-cat__resetbtn`（沿用老板认可的那套中性观感）
     和 `.hfpan-cat__sreset`。两者都是单类选择器、**权重相同**，
     谁在后面谁赢 —— 靠源码顺序太脆，所以这里用**两段选择器**把权重提到 (0,2,0)，
     不管 `.resetbtn` 那条在文件里排哪儿都能盖住。
   ── 覆盖掉哪些 ──────────────────────────────────────────────────────
     `.resetbtn` 是给工具条 / 抬头那种"小胶囊"用的（padding 2px 9px、圆角、描边）；
     搜索栏这一条是**通栏高度**，所以要去掉圆角与描边、只留一条左侧分隔线。 */
.hfpan-cat__search .hfpan-cat__sreset {
    /* ★ 0.13.54：按钮里**只剩一个图标**了（老板要求删掉「重置」两个字），
       所以横向内边距按"图标 + 左右留白"给 —— 18 + 14×2 = 46px，
       正好和搜索栏的高度（约 46px）齐平，看着是个规整的方按钮。 */
    padding: 0 14px;
    border: 0;
    /* ★ 0.13.53：分隔线从**左边**换到**右边** —— 因为「重置」和「搜索」调换了位置，
       现在顺序是「重置 → 搜索」，分隔线该落在重置的右边缘（紧挨搜索按钮）。 */
    border-right: 1px solid var(--hfpan-line);
    border-radius: 0;
    font-size: 13px;
    color: var(--hfpan-ink-2);
    background: var(--hfpan-surface);
    transition: background .14s, color .14s;
}

.hfpan-cat__search .hfpan-cat__sreset:hover {
    border-color: var(--hfpan-line);
    background: var(--hfpan-surface-3);
    color: var(--hfpan-ink);
}

/* ★ 0.13.54：图标从 13px 放大到 **20px**（老板要求「再大一些」）。
   ⚠️ 垃圾桶是**实心**图标，走 `--solid`（fill:currentColor），放大后更清楚；
      别把它跟线框图标（`--line`）的尺寸规则混在一起 —— 那是工具条里的小图标。 */
.hfpan-cat__search .hfpan-cat__sreset .hfpan-cat__toolic {
    width: 20px;
    height: 20px;
}

/* 手机上搜索栏会换行 —— 重置跟着占满那一行，别挤成一小坨 */
@media (max-width: 640px) {
    .hfpan-cat__search .hfpan-cat__sreset {
        flex: 1 1 100%;
        justify-content: center;
        padding: 8px 16px;
        border-right: 0;
        border-top: 1px solid var(--hfpan-line);
    }
}

/* 搜索结果提示条（左栏顶部） */
.hfpan-cat__sbar {
    flex: none;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    background: var(--hfpan-mark-soft);
    border-bottom: 1px solid var(--hfpan-mark-line);
    color: var(--hfpan-mark);
    font-size: 12px;
}

.hfpan-cat__sbartxt b {
    font-weight: 700;
}

.hfpan-cat__sback {
    margin-left: auto;
    border: 1px solid var(--hfpan-mark-line);
    background: var(--hfpan-surface);
    color: var(--hfpan-mark);
    border-radius: 4px;
    padding: 1px 8px;
    font-size: 12px;
    cursor: pointer;
}

.hfpan-cat__sback:hover {
    background: var(--hfpan-mark);
    color: var(--hfpan-surface);
}

/* 搜索结果列表（左栏里） */
.hfpan-cat ul.hfpan-cat__hits {
    margin: 0 !important;
    padding: 0 !important;
    list-style: none !important;
}

.hfpan-cat ul.hfpan-cat__hits li.hfpan-cat__hit {
    list-style: none !important;
    padding: 8px 11px;
    border-bottom: 1px solid var(--hfpan-line-2);
    border-left: 3px solid var(--hfpan-pen);
    cursor: pointer;
    transition: background .14s, border-color .14s;
}

.hfpan-cat ul.hfpan-cat__hits li.hfpan-cat__hit:hover {
    background: var(--hfpan-surface-2);
    border-left-color: var(--hfpan-blue);
}

.hfpan-cat__hitname {
    font-weight: 500;
    word-break: break-all;
    margin-bottom: 3px;
    color: var(--hfpan-ink);
    /* ★ 0.13.48：搜索结果的文件名**也归「文件名」那项字号**（老板要求）——
       原来它连 font-size 都没写，直接继承基准 14px，前台调不到它。 */
    font-size: var(--hfpan-fname-size, 14px);
}

.hfpan-cat__hitpath {
    font-size: 11.5px;
    color: var(--hfpan-ink-2);
    word-break: break-all;
}

.hfpan-cat__hitmeta {
    display: flex;
    gap: 6px;
    align-items: center;
    margin-top: 4px;
    flex-wrap: wrap;
}

.hfpan-cat__chip {
    font-size: 10px;
    letter-spacing: .4px;
    border: 1px solid var(--hfpan-line);
    border-radius: 3px;
    padding: 0 5px;
    color: var(--hfpan-ink-2);
    background: var(--hfpan-surface-3);
}

/* 关键词标红 + 记号笔黄底（签名元素） */
.hfpan-cat__kw {
    color: var(--hfpan-mark);
    font-weight: 600;
    background: linear-gradient(transparent 58%, var(--hfpan-pen-soft) 58%,
                var(--hfpan-pen-soft) 92%, transparent 92%);
    padding: 0 1px;
    border-radius: 1px;
}

/* 命中行高亮（搜索定位过来的那条文件） */
.hfpan-cat__node.is-hit {
    background: var(--hfpan-mark-soft);
    box-shadow: inset 3px 0 0 var(--hfpan-mark);
}

.hfpan-cat__node.is-hit .hfpan-cat__fname {
    font-weight: 600;
}

/* 级联里「搜索帮我选的」那一层：红框；为凑满补的层：蓝框 */
.hfpan-cat__select.is-auto {
    border-color: var(--hfpan-mark) !important;
    background: var(--hfpan-mark-soft) !important;
    color: var(--hfpan-mark) !important;
    font-weight: 600;
}

.hfpan-cat__select.is-filled {
    border-color: var(--hfpan-blue-line);
    background: var(--hfpan-blue-soft);
    color: var(--hfpan-blue-ink);
}

/* ⚠️ 原来这里有一排「大类切换」按钮标签（阅读 / 下载 / 全开）。
   0.5.1 起**已删除** —— 它和顶部搜索栏里的「类型」下拉是同一件事，
   同一件事出现两次只会让站长不知道该点哪个。
   **现在切换大类的唯一入口 = 搜索栏左边的「类型」下拉**（.hfpan-cat__skind）。
   下面这些按钮样式也一并清掉了，别再照着旧版加回来。 */

/* 一个条目 = 一组级联 + 下方主体（0.5.2：级联搬进面板内，与下方合成一栏） */
.hfpan-cat__item {
    margin-bottom: 0;
}

/* ── ★ 级联长度规则（0.5.2 老板定，以 4 个为标准）─────────────────
   桌面：
     · 正好 4 个 → 4 个平分铺满整行
     · 少于 4 个 → 每格仍是 1/4 宽，**末尾空出缺的那几格**（不拉伸、不居中）
     · 多于 4 个 → 全部铺满这一栏、不换行（由 JS 加 .is-fluid，见下）
   手机（≤640px）：每排 4 个，不足一排的**平分铺满**那一排。
   ⚠️ 每个 select 外面包一层 .hfpan-cat__selectcell —— cell 管宽度、select 占满 cell。
   ───────────────────────────────────────────────────────────── */
.hfpan-cat__selects {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    padding: 12px 14px;
    background: var(--hfpan-surface-2);
    border-bottom: 1px solid var(--hfpan-line);
}

.hfpan-cat__selectcell {
    flex: 0 0 auto;
    width: calc((100% - 30px) / 4);      /* 一格 = 1/4 行宽（减 3 个间隙） */
    min-width: 0;
    /* ⚠️ 0.13.13：必须是定位上下文 —— 可输入下拉的箭头与候选层都靠它绝对定位。
       原来没有这一条；对原生 select 没有任何影响。 */
    position: relative;
}

/* 多于 4 个 → 完整自适应、铺满且不换行。
   ⚠️ 必须包在 min-width 媒体查询里：`.hfpan-cat__selects.is-fluid .hfpan-cat__selectcell`
      特异性高于手机规则里的 `.hfpan-cat__selectcell`，不限定会让手机端也走桌面规则
      （实测踩过：手机上 6 个挤成一排、每个只有 38px 宽）。 */
@media (min-width: 641px) {
    .hfpan-cat__selects.is-fluid .hfpan-cat__selectcell {
        flex: 1 1 0;
        width: auto;
    }
}

.hfpan-cat__select {
    width: 100%;
    min-width: 0;
    max-width: 100%;
    padding: 8px 10px;
    border: 1px solid var(--hfpan-line);
    border-radius: 6px;
    background: var(--hfpan-surface);
    color: var(--hfpan-ink);
    font-size: 14px;
    line-height: 1.4;
    text-overflow: ellipsis;
}

.hfpan-cat__select:disabled {
    background: var(--hfpan-surface-3);
    color: var(--hfpan-ink-3);
    cursor: not-allowed;
}

/* ══════════════════════════════════════════════════════════════
 * ★ 0.13.13：可输入的下拉框（后台「目录等级可手动搜索」打开后才出现）
 * ── 它替掉同一格里的 .hfpan-cat__select，所以外观要**尽量对齐**：
 *    同样的高、同样的描边、同样的圆角，只是右端换成自己画的箭头。
 * ── 色值一律走变量（写死的话深色模式就不生效 —— check.php 有断言盯着）。
 * ══════════════════════════════════════════════════════════════ */
.hfpan-cat__lbox {
    width: 100%;
    min-width: 0;
    max-width: 100%;
    padding: 8px 34px 8px 10px;      /* 右边留给箭头（★ 0.14.38：28 → 34，箭头变宽了） */
    border: 1px solid var(--hfpan-line);
    border-radius: 6px;
    background: var(--hfpan-surface);
    color: var(--hfpan-ink);
    font-size: 14px;
    line-height: 1.4;
    font-family: inherit;
}

.hfpan-cat__lbox::placeholder {
    color: var(--hfpan-ink-3);
}

.hfpan-cat__lbox:focus {
    outline: none;
    border-color: var(--hfpan-blue);
    box-shadow: 0 0 0 2px var(--hfpan-blue-soft);
}

/* 已经选好值的那一格 —— 加粗 + 主色描边，和原生下拉"选中一项"的观感接近。
   ⚠️ 类名是 is-chosen，**别用 is-filled** —— 那是 0.5.0「搜索帮我填了这一级」
      的专用标记（蓝框），两件事语义不同，混用会踩 check.php 的反向断言。 */
.hfpan-cat__selectcell.is-chosen .hfpan-cat__lbox {
    font-weight: 600;
    border-color: var(--hfpan-blue-line);
}

/* ══ ★★ 0.14.38：等级目录的箭头**可单独点击 + 比例调大**（老板要求）════════
   ── 老板原话 ──────────────────────────────────────────────────────────
     「等级目录下拉箭头可以单独进行点击，比例调大一些，
       解决第二次手动弹不出来问题」
   ── 改了什么 ──────────────────────────────────────────────────────────
     · `pointer-events: none` → **auto**：以前点箭头等于点输入框（箭头本身
       点不到），现在箭头是**独立热区**；
     · `font-size: 11px` → **16px**：箭头明显变大（原来那个小三角不好点）；
     · 热区做成 **32px 宽的通栏**（`top:0; bottom:0` 本来就有），手指也够得着。
   ⚠️ 输入框右边留白要跟着加大（`.hfpan-cat__lbox` 的 `padding-right`），
      否则文字会滑到箭头底下。 */
.hfpan-cat__lcaret {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--hfpan-ink-3);
    font-size: 16px;
    line-height: 1;
    pointer-events: auto;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

/* 按下去给点反馈（不然手机上没有"点到了"的感觉） */
.hfpan-cat__lcaret:active {
    color: var(--hfpan-blue);
}

.hfpan-cat__ldd {
    position: absolute;
    left: 0;
    top: calc(100% + 3px);
    z-index: 40;
    /* 比格子宽：跨上级搜出来的结果要带"上级路径"，1/4 格宽装不下 */
    min-width: 100%;
    width: max-content;
    max-width: 340px;
    max-height: 280px;
    overflow: auto;
    background: var(--hfpan-surface);
    border: 1px solid var(--hfpan-line);
    border-radius: 6px;
    box-shadow: var(--hfpan-shadow-4);
}

/* 最后一格的下拉往右对齐 —— 否则会顶出容器右边缘 */
.hfpan-cat__selectcell:last-child .hfpan-cat__ldd {
    left: auto;
    right: 0;
}

.hfpan-cat__lddhd {
    position: sticky;
    top: 0;
    padding: 6px 10px;
    font-size: 12px;
    color: var(--hfpan-ink-2);
    background: var(--hfpan-surface-3);
    border-bottom: 1px solid var(--hfpan-line-2);
}

.hfpan-cat__lddhd b {
    color: var(--hfpan-blue-ink);
}

.hfpan-cat__lddopt {
    padding: 7px 10px;
    border-bottom: 1px solid var(--hfpan-line-2);
    cursor: pointer;
}

.hfpan-cat__lddopt:last-child {
    border-bottom: 0;
}

.hfpan-cat__lddopt:hover,
.hfpan-cat__lddopt.is-cur {
    background: var(--hfpan-blue-soft);
}

.hfpan-cat__lddname {
    display: block;
    font-size: 14px;
    color: var(--hfpan-ink);
}

/* 跨上级搜出来时标出"它是哪家的"（同名型号分得清品牌） */
.hfpan-cat__lddpath {
    display: block;
    margin-top: 1px;
    font-size: 12px;
    color: var(--hfpan-ink-3);
}

.hfpan-cat__lddempty {
    padding: 10px;
    font-size: 13px;
    color: var(--hfpan-ink-2);
}

.hfpan-cat__lddempty span {
    display: block;
    margin-top: 3px;
    font-size: 12px;
    color: var(--hfpan-ink-3);
}

/* ⭐ 0.13.17：空目录的小标签（老板要求：候选里就看得出来，别点进去才发现是死路）。
   ⚠️ 跟着目录名后面走（inline-block），字号比名字小一档、颜色弱一档 ——
      它是"提示"，不该抢目录名的视觉重心。 */
.hfpan-cat__lddempty-tag {
    display: inline-block;
    margin-left: 6px;
    padding: 0 5px;
    border-radius: 4px;
    border: 1px solid var(--hfpan-line-2);
    background: var(--hfpan-surface-3);
    color: var(--hfpan-ink-3);
    font-size: 11.5px;
    font-weight: 400;
    line-height: 1.5;
    vertical-align: 1px;
}


/* ══ ★ 0.13.43：**品牌级下拉**（点 A~Z 首字母 → 在「勾了品牌级」的那一格弹出）══
   老板原话：「品牌点击的那个首字母要在对应的勾选的品牌那一级做一个下拉」。
   取代原来「把品牌当成普通目录行列在左栏里」的做法（0.13.0 那版）。
   ── 为什么另起一套、不复用 `.hfpan-cat__ldd` ──────────────────────
      `.hfpan-cat__ldd` 是「目录等级可手动搜索」的候选层，两套逻辑各有
      `lvOpen` / `paintDD` 状态，共用类名会互相清空。所以**定位与观感照抄它**
      （同样 absolute 在 `.hfpan-cat__selectcell` 里 —— 这条路径已在真机验证
      **不会被祖先 overflow 裁掉**），类名分开。
   ⚠️ 深色模式不用单独写：变量挂在上层 `.hfpan-cat` 上，这里全是 var()。 */
.hfpan-cat__bdd {
    position: absolute;
    left: 0;
    top: calc(100% + 3px);
    /* 比 .hfpan-cat__ldd 的 40 高一档 —— 两者已被 JS 做成互斥，这里只求稳 */
    z-index: 41;
    min-width: 100%;
    width: max-content;
    max-width: 340px;
    max-height: 280px;
    overflow: auto;
    background: var(--hfpan-surface);
    border: 1px solid var(--hfpan-line);
    border-radius: 6px;
    box-shadow: var(--hfpan-shadow-4);
}

.hfpan-cat__bdd[hidden] { display: none; }

/* 最后一格的下拉往右对齐 —— 否则会顶出卡片右边缘（照抄 .hfpan-cat__ldd 那条） */
.hfpan-cat__selectcell:last-child .hfpan-cat__bdd {
    left: auto;
    right: 0;
}

.hfpan-cat__bddhd {
    position: sticky;
    top: 0;
    padding: 6px 10px;
    font-size: 12px;
    color: var(--hfpan-ink-2);
    background: var(--hfpan-surface-3);
    border-bottom: 1px solid var(--hfpan-line-2);
}

.hfpan-cat__bddhd b { color: var(--hfpan-blue-ink); }

.hfpan-cat__bddopt {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    border-bottom: 1px solid var(--hfpan-line-2);
    cursor: pointer;
}

.hfpan-cat__bddopt:last-child { border-bottom: 0; }

.hfpan-cat__bddopt:hover { background: var(--hfpan-blue-soft); }

.hfpan-cat__bddic {
    flex: none;
    width: 16px;
    text-align: center;
    color: var(--hfpan-blue);
    font-size: 14px;
}

.hfpan-cat__bddnm {
    font-size: 14px;
    color: var(--hfpan-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.hfpan-cat__bddempty {
    padding: 10px;
    font-size: 13px;
    color: var(--hfpan-ink-2);
}


/* 选完之后才出现的文件列表 */
.hfpan-cat__files {
    margin-top: 0;
}

.hfpan-cat__list {
    list-style: none;
    margin: 0;
    padding: 0;
    border: 1px solid var(--hfpan-line-2);
    border-radius: 6px;
    overflow: hidden;
}

.hfpan-cat__file {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--hfpan-line-2);
    background: var(--hfpan-surface);
    font-size: 14px;
    line-height: 1.5;
}

.hfpan-cat__file:last-child {
    border-bottom: 0;
}

.hfpan-cat__fname {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--hfpan-ink);
    font-size: 14px;
    line-height: 1.5;
}

.hfpan-cat__act {
    flex: none;
    /* ★ 0.13.83：目录文件行里那个「下载」按钮也要放图标（老板要求）——
       ⚠️ 同样必须先是 **flex 容器**，否则 `display:block` 的图标会把文字挤下去
          （工具条那三个按钮就是这么坏的）。 */
    display: inline-flex;
    align-items: center;
    gap: 4px;

    padding: 5px 18px;
    border: 1px solid var(--hfpan-blue);
    background: var(--hfpan-surface);
    color: var(--hfpan-blue-ink);
    border-radius: 5px;
    font-size: 14px;
    cursor: pointer;
    transition: all .15s ease;
}

.hfpan-cat__act:hover {
    background: var(--hfpan-blue);
    color: var(--hfpan-on-blue);
}

.hfpan-cat__tip {
    margin: 0;
    padding: 6px 2px;
    color: var(--hfpan-ink-3);
    font-size: 14px;
}

/* ── 面板：级联 + 目录 + 预览同属一张卡片（0.5.2）────────────── */
.hfpan-cat__panel {
    border: 1px solid var(--hfpan-line);
    border-radius: 6px;
    background: var(--hfpan-surface);
    box-shadow: var(--hfpan-shadow), var(--hfpan-shadow-2);
    overflow: hidden;
}

/* ══ ★ 身份 / 额度卡（0.5.2 起；0.7.8 改成**可收起 + 2 行左对齐**）══════
   位置不变：仍在「目录面板」抬头下面、文件列表上面。
   展开 / 收起由抬头最左边的**头像按钮**控制（`.hfpan-cat__who`），
   展开后 5 秒自动收起（catalog.js 的 quotaTimer，倒计时走下面那条 `.hfpan-cat__qbar`）。
   ⚠️ 数字全部来自后端（见 class-frontend.php 的 render_quota_bar / quota_info）。 */
.hfpan-cat__quota {
    flex: none;

    /* ★ 2 行结构：第 1 行「您是 + 徽章 …… 开通会员」，第 2 行说明。
       用 grid + row-gap 而不是 flex-wrap —— 后者会让文字乱换行（老板说「有点影响美观」）。 */
    display: grid;
    row-gap: 5px;
    padding: 10px 12px 11px;

    font-size: 13px;
    line-height: 1.5;
    background: var(--hfpan-quota-bg);
    border-bottom: 1px solid var(--hfpan-line);

    /* 收起 / 展开动画（高度由 JS 量出来设成固定值，才能过渡） */
    overflow: hidden;
    transition: height .24s ease, padding .24s ease, opacity .18s ease;
}

/* 收起时不占位 —— ⚠️ 真正的兜底在文件下方的「hidden 属性兜底」段
   （那里用 !important 压过主题 bootstrap，这条只是就近说明） */

/* 收起过程中的淡出 */
.hfpan-cat__quota.is-closing {
    opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
    .hfpan-cat__quota { transition: none; }
}

/* 第 1 行：身份在左、按钮在右，两端对齐 */
.hfpan-cat__qrow1 {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
}

.hfpan-cat__qleft {
    display: flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}

.hfpan-cat__qyou {
    color: var(--hfpan-ink-2);
    font-size: 13px;
    flex: none;
}

/* 第 2 行：说明文字，单行左对齐（与上一行同一个左边缘 = 工整） */
.hfpan-cat__qrow2 {
    font-size: 12.5px;
    color: var(--hfpan-ink-2);
    line-height: 1.6;
}

.hfpan-cat__qbadge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex: none;
    padding: 2px 9px;
    border-radius: 20px;
    font-size: 12.5px;
    font-weight: 500;
    border: 1px solid var(--hfpan-blue-line);
    background: var(--hfpan-blue-soft);
    color: var(--hfpan-blue-ink);
}

/* 一级会员：金 */
.hfpan-cat__qbadge.is-vip1 {
    border-color: var(--hfpan-vip1-line);
    background: var(--hfpan-vip1-bg);
    color: var(--hfpan-vip1-fg);
}

/* 二级会员：粉 */
.hfpan-cat__qbadge.is-vip2 {
    border-color: var(--hfpan-vip2-line);
    background: var(--hfpan-vip2-bg);
    color: var(--hfpan-vip2-fg);
}

/* 普通用户：灰 */
.hfpan-cat__qbadge.is-guest {
    border-color: var(--hfpan-line);
    background: var(--hfpan-surface-3);
    color: var(--hfpan-ink-2);
}

/* ★ 0.7.8 新增：「开通会员」按钮 —— 走子比 pay-vip 类名，点了开原生会员弹窗 */
.hfpan-cat__qbuy {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 11px;
    border-radius: 5px;
    border: 1px solid var(--hfpan-blue);
    background: var(--hfpan-surface);
    color: var(--hfpan-blue-ink);
    font-size: 12.5px;
    line-height: 1.5;
    text-decoration: none;
    cursor: pointer;
    transition: background .14s ease, color .14s ease;
}

.hfpan-cat__qbuy:hover,
.hfpan-cat__qbuy:focus-visible {
    background: var(--hfpan-blue);
    color: var(--hfpan-on-blue);
    text-decoration: none;
}

.hfpan-cat__qbuy i {
    font-size: 11px;
}

.hfpan-cat__qnum {
    font-family: Consolas, Menlo, monospace;
    font-weight: 700;
    color: var(--hfpan-blue-ink);
}

/* 快用完了 → 数字变红，提醒一下 */
.hfpan-cat__qnum.is-low {
    color: var(--hfpan-mark);
}

.hfpan-cat__qpts {
    font-family: Consolas, Menlo, monospace;
    font-weight: 700;
    color: var(--hfpan-vip1-fg);
}

.hfpan-cat__qsep {
    color: var(--hfpan-line);
    margin: 0 5px;
}

/* ★ 0.7.8 新增：卡片下沿的 5 秒倒计时细线（纯视觉提示，不影响功能） */
.hfpan-cat__qbar {
    grid-column: 1 / -1;
    height: 2px;
    border-radius: 1px;
    background: var(--hfpan-blue-line);
    transform: scaleX(0);
    transform-origin: left center;
}

.hfpan-cat__qbar.is-run {
    animation: hfpan-qcountdown 5s linear forwards;
}

@keyframes hfpan-qcountdown {
    from { transform: scaleX(1); }
    to   { transform: scaleX(0); }
}

@media (prefers-reduced-motion: reduce) {
    .hfpan-cat__qbar.is-run {
        animation: none;
        transform: scaleX(0);
    }
}

/* ── 左右分栏：左「目录面板」+ 右「预览」 ────────────── */

.hfpan-cat__body {
    display: flex;
    align-items: stretch;
    margin-top: 0;                    /* 0.5.2：级联已在面板内，不需要上间距 */
    border: 0;                        /* 0.5.2：级联 + 主体同属一张卡片，不画内框 */
    border-radius: 0;
    overflow: hidden;

    /* ⚠️ 这里必须是**固定高度**，不能只给 min-height。
       左栏文件一多，整个容器就会被撑高，把右侧预览和整页一起拉长 ——
       （实测反馈过：文件多的时候页面被拉到最长文件那条的长度）。
       固定高度 + 左右各自内部滚动，才是分栏该有的行为。
       ★ 0.14.23：改成**变量 + 兜底**，默认仍是 620px（行为不变）。
         手机端折叠「层级目录及以上」时，JS 会把这个变量调大同样的量 ——
         这样**页面总高不变**（不会跳），而阅读器白得那 273px ✓ */
    height: var(--hfpan-body-h, 620px);
}

.hfpan-cat__left {
    flex: 0 0 260px;
    max-width: 260px;
    border-right: 1px solid var(--hfpan-line-2);
    background: var(--hfpan-surface-2);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    /* ★ 0.13.0：A~Z 竖排要**绝对定位悬浮在左栏里**，所以这里必须是定位锚点。
       ⚠️ 别删 —— 删了 A-Z 会跑到外层容器去（相对最近的非 static 祖先定位）。 */
    position: relative;
}

/* 「下载」大类没有右栏（老板 0.4.3：「去掉右边的预览页面 仅保留目录」）——
   左栏直接占满整行，边框也去掉。 */
.hfpan-cat__body.is-single .hfpan-cat__left {
    flex: 1 1 auto;
    max-width: none;
    border-right: 0;
}

/* ══ ★ 0.13.43：目录面板宽度**跟着级联第一格走** ═══════════════════════
   老板原话：「四个等级目录正常还是四格平分 让目录面板跟着走不就好了」。
   目的：让「二级目录」的**左边缘**正好落在「目录面板」的**右边缘**上。
   ── 算式（级联行 padding-left = 14px、格间隙 = 10px）──────────────
       二级目录左边缘 = 14 + 第一格宽 + 10 = 第一格宽 + 24
       第一格宽       = (100% − 28px − (N−1)×10px) / N     （100% = 卡片内容宽）
       ⇒ 面板宽 = 第一格宽 + 24px  ← 就是下面这条
   ── N 为什么是 max(4, 级数) ──────────────────────────────────────────
       级联的规矩是「≤4 级时每格**固定 1/4 宽**、不足 4 个也不拉伸」（0.5.2 定的）
       → 2/3 级时除数仍是 4；只有 >4 级才加 .is-fluid 改成按级数平分。
       所以 4 级及以下**纯 CSS 就够**（默认值 4）；
       5~6 级由 catalog.js 写 `--hfpan-cell-n`（一行，见 render()）。
   ⚠️ 五个限定一个都不能少（删任一条都会误伤）：
       ① `[data-levels]` —— 文章块 `[hoarfall_pan]` 没有级联，继续吃原来的 260px
       ② `@media (min-width: 861px)` —— ≤860px 左右会改成上下竖排，那时面板
          占满整行、对齐没有意义；**而且本规则权重 (0,5,0) 高于竖排那条 (0,1,0)**，
          不包媒体查询会把它压掉（竖排就不成立了）
       ③ `:not(.is-single)` —— 「只下载」类型左栏本来就占满整行
       ④ `:not(.is-dirhidden)` —— ⚠️⚠️ **「目录」按钮收起左栏时必须让位**：
          收起规则 `.hfpan-cat__item.is-dirhidden .hfpan-cat__left` 只有 **(0,3,0)**，
          低于本条的 (0,5,0) → 不加这个 `:not()`，本条的 `flex` 会把它压回去，
          **面板收不起来、「目录」按钮看着像坏了**（0.13.43 老板实测报回来）。
       ⑤ `max-width: none` —— 原来那条写死的 `max-width: 260px` 必须让位
   ⚠️ 副作用（老板已知情）：面板宽度从此**跟着卡片宽变**
      （900→234px / 1160→299px / 1400→359px / 1600→409px）。
      想调宽度就改那个 `+ 24px` —— 但它一改，对齐就破了，别随手动。
   ══════════════════════════════════════════════════════════════════ */
@media (min-width: 861px) {
    .hfpan-cat__item[data-levels]:not(.is-dirhidden) .hfpan-cat__body:not(.is-single) .hfpan-cat__left {
        flex: 0 0 calc((100% - 28px - (var(--hfpan-cell-n, 4) - 1) * 10px) / var(--hfpan-cell-n, 4) + 24px);
        max-width: none;
    }
}

/* 「下载」大类的说明行（原来那句话在右栏里，右栏去掉后挪到目录上方） */
/* ⚠️ 0.13.46：`.hfpan-cat__panehead .hfpan-cat__resetbtn { margin-left: auto }`
   **已删** —— 重置整体挪到搜索栏尾侧了，抬头里不再有它。
   （0.13.40 曾把「只下载」类型的重置放这儿，现已撤。）
   基础样式 `.hfpan-cat__resetbtn` 保留 —— 搜索栏那个按钮仍在用它。 */

/* ⚠️ 0.13.40：`.hfpan-cat__brandbar`（那条"一排裸按钮"的 bar）**已撤** ——
   只下载类型只保留重置，且挪进了抬头。这条规则留着是为了别的地方万一还在用；
   如果确认全仓没有 `.hfpan-cat__brandbar` 了，可以一起删掉。 */

.hfpan-cat__hint {
    margin: 12px 0 0;
    color: var(--hfpan-ink-2);
    font-size: 13px;
}

.hfpan-cat__panehead {
    flex: none;
    padding: 9px 12px;
    font-weight: 500;
    /* ★ 0.13.48：抬头字号**固定 14px**（原来是 `--hfpan-panehead-size` 可配）——
       老板这次只要两项（文件名 / A~Z 首字母），「面板标题」那项撤了。
       行高固定，免得字大了把标题栏挤变形。 */
    font-size: 14px;
    line-height: 1.4;
    color: var(--hfpan-head-fg);
    background: var(--hfpan-head-bg);
    border-bottom: 1px solid var(--hfpan-head-line);

    /* ★ 0.7.8：抬头从「居中一行字」改成「头像 + 标题」左对齐（老板要求头像放最左边） */
    display: flex;
    align-items: center;
    gap: 9px;
    text-align: left;
}

/* 标题文字（原先是裸文本，包一层好跟头像对齐） */
.hfpan-cat__ptitle {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* ── ★ 0.7.8 新增：抬头最左边的「用户头像」按钮 ──────────────────
   点头像 → 展开 / 收起下面的额度卡。没有额度信息时不输出这个按钮。
   ⚠️ 子比的 `pre_get_avatar` 过滤器会**忽略**我们传的 class
      （它自己拼 `avatar avatar-N`），所以头像的定位样式必须走
      `.hfpan-cat__who img` 这个后代选择器，别指望给它加 class。 */
.hfpan-cat__who {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--hfpan-head-fg);
    font: inherit;
    line-height: 1;
    cursor: pointer;
}

.hfpan-cat__who img {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: block;
    border: 1.5px solid rgba(255, 255, 255, .55);
    background: rgba(255, 255, 255, .22);
    object-fit: cover;
}

/* 未登录时用图标兜底（不请求 gravatar） */
.hfpan-cat__whoicon {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    color: var(--hfpan-head-fg);
    background: rgba(255, 255, 255, .22);
    border: 1.5px solid rgba(255, 255, 255, .55);
}

/* 小三角：展开时转 180° */
.hfpan-cat__whocaret {
    font-size: 11px;
    opacity: .75;
    transition: transform .18s ease;
}

.hfpan-cat__who.is-open .hfpan-cat__whocaret {
    transform: rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
    .hfpan-cat__whocaret { transition: none; }
}

/* 键盘可达：焦点必须看得见（抬头是蓝底，用白描边） */
.hfpan-cat__who:focus-visible {
    outline: 2px solid var(--hfpan-head-fg);
    outline-offset: 2px;
    border-radius: 14px;
}

.hfpan-cat__left .hfpan-cat__files {
    flex: 1;

    /* ⚠️ flex 子项默认 min-height:auto —— 内容一多就把父级撑开，
       这一行不写，上面的 overflow:auto 根本不生效（页面照样被拉长）。 */
    min-height: 0;
    overflow: auto;

    /* ★ 0.14.53：树现在可能**比面板宽**（长文件夹名不截断，见
       `.hfpan-cat__tree { min-width: max-content }` 那段）→
       这一层就是那个**横向滚动容器**（桌面拖滚动条、手机手指左右滑）。
       ⚠️ `overscroll-behavior-x: contain` 不能省：手机上横向滑到头时，
          再往右划会**传给外层**（抽屉 / 整页）→ 看着像"页面被拖动"。
          写 contain 之后滑到头就停住，不带走页面。 */
    overflow-x: auto;
    overscroll-behavior-x: contain;
    padding: 4px 0;
}

.hfpan-cat__right {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--hfpan-surface);

    /* 译文浮层的定位基准（浮层是 absolute 叠在预览上方的） */
    position: relative;
}

/* ══ ★★ 0.14.7：工具条的**外层锚点**（详情面板挂在这一层，不挂工具条）══════
   ── 老板实测报的（手机端）────────────────────────────────────────────
     「点详情没有任何效果」—— 面板**整块看不见**。
   ── 根因（无头浏览器实测，390px 与 700px 对照）────────────────────────
     工具条在 ≤640px 为了「一行横滑」设了
       `.hfpan-cat__toolbar { overflow-x:auto; overflow-y:hidden }`，
     而详情面板是 `position:absolute; top:calc(100% + 6px)` ——
     **正好吊在工具条外面** → 被 `overflow-y:hidden` 整块裁掉。
     实测：面板矩形内 6×6 网格「命中自己」**0/36**（完全点不到），
     而 700px（工具条不横滑、`overflow:visible`）是 **36/36**。
   ── ⚠️ 同一个症状换了病因 ────────────────────────────────────────────
     0.13.82 修过一次「面板被 `.hfpan-cat__right` 的 overflow 裁掉」，
     那时给工具条加 `position: relative` 就够了；
     0.13.89 给工具条加了手机端横滑（`overflow-y:hidden`），
     **又把它关进另一个裁剪框**。所以锚点必须挪到这一层。
   ── 为什么是这一层 ──────────────────────────────────────────────────
     · 工具条自己要保持 `overflow-x:auto`（横滑），**不能**既滚动又不裁剪
       （CSS 里 `overflow-x:auto` + `overflow-y:visible` 是不成立的：
        visible 会被算成 auto，照样裁）；
     · 这一层不裁剪、`position:relative`，面板的 `top:calc(100% + 6px)`
       相对它算 → 高度等于工具条高度（面板 absolute 不占位）→ **位置与桌面一致**；
     · `flex:none` —— 它是 `.hfpan-cat__right`（纵向 flex）的子项，
       不写会被阅读器挤扁。
   ⚠️ 视图菜单 / 字号菜单 / A~Z 走的是**另一条路**（JS 建到 body 上），
      它们躲的是同一个裁剪框；详情面板是 PHP 输出的，躲不了，只能靠这层包裹。 */
.hfpan-cat__toolbarwrap {
    position: relative;
    flex: none;
}

/* 预览区右上角的工具条 */
.hfpan-cat__toolbar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    background: var(--hfpan-surface-2);
    border-bottom: 1px solid var(--hfpan-line-2);
    /* ⚠️⚠️★ 0.13.82：**这条不能省** ────────────────────────────────────
       「文件详情」面板是 `position: absolute; top: calc(100% + 6px); right: 12px`，
       它要挂在**工具条**下面。可工具条原来没定位、`.hfpan-cat__item` 也没定位
       → 最近的定位祖先是 **`.hfpan-cat__right`（整条右栏）** →
       `top: 100%` 变成"整条右栏的底部" → 面板被推到阅读器下方，
       而 `.hfpan-cat__right` 又是 `overflow: hidden` → **整个被裁掉**。
       表现就是老板实测那句：**「点详情没有任何效果」**（其实点了，只是看不见）。
       ⚠️ 加 `position: relative` 只是给面板一个锚点，不改工具条自身布局。
       ⚠️★ 0.14.7：面板的锚点已挪到 `.hfpan-cat__toolbarwrap`（见上），
          这条 `position: relative` 保留无副作用（工具条内部还有浮层依赖它）。 */
    position: relative;
}

/* 工具栏左侧的小提示（0.5.2）：告诉用户「滚轮就能翻」——
   因为放大缩小、页码、翻页箭头、单页切换都按老板要求去掉了。 */
.hfpan-cat__toolhint {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--hfpan-ink-3);
    font-size: 12.5px;
    white-space: nowrap;
}

.hfpan-cat__toolhintic {
    font-size: 12.5px;
}

.hfpan-cat__toolsp {
    margin-left: auto;
}

/* ══════════════════════════════════════════════════════════════
   ★ 0.13.0：品牌首字母检索（A~Z）
   ── 老板批注 ──────────────────────────────────────────────────
     ·「透明背景，悬浮在目录左侧显示，不影响目录，和其他功能无关，
        只和品牌检索有关」
     ·「只在品牌里显示，其他选项无关，文章中也不需要，因为没有品牌」
     ·「比如我选择 A，搜索结果在品牌里下拉菜单：奥迪 奥拓 埃安
        A 开头的品牌都出来」
     ·「之后，我选择奥迪，那上一级车系：唯一对应的上级，就自动显示了，
        再手动选下一级车型、年款了」
   ══════════════════════════════════════════════════════════════ */

/* 「品牌」按钮 —— 在**阅读区工具条**里，最左边第一个
   （老板批注里箭头指的就是那一排：品牌 / 目录- / 目录+ / 单页 / 翻译 / 下载 / 全屏）。
   ⚠️ 0.13.1 前它被我错挪进「目录面板抬头」过 —— 老板看到就问
      「品牌按钮怎么做到这里了」，已挪回。 */
.hfpan-cat__brandbtn {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    flex: none;
    padding: 2px 9px;
    border: 1px solid #ffd400;
    border-radius: 5px;
    background: #fffdf0;
    color: #7a5d00;
    font-size: 12px;
    font-weight: 700;
    line-height: 1.7;
    cursor: pointer;
    white-space: nowrap;
    transition: background .12s, color .12s;
}

.hfpan-cat__brandbtn:hover,
.hfpan-cat__brandbtn[aria-expanded="true"] {
    background: #ffd400;
    color: #5a4400;
}

.hfpan-cat__brandbtn__caret {
    font-size: 9px;
    line-height: 1;
}

/* 「重置」按钮 —— 工具条里，紧跟「品牌」。
   ⚠️ 刻意做成**低调**的样式（灰边、透明底）—— 它是个「清空」操作，
      不该和「品牌」一样抢眼；但也不能太隐蔽（老板要求加它，
      说明用户会去找它）。 */
.hfpan-cat__resetbtn {
    display: inline-flex;
    align-items: center;
    flex: none;
    padding: 2px 9px;
    border: 1px solid var(--hfpan-line-2, #dcdcde);
    border-radius: 5px;
    background: transparent;
    color: var(--hfpan-ink-2, #646970);
    font-size: 12px;
    line-height: 1.7;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color .12s, color .12s;
}

.hfpan-cat__resetbtn:hover {
    border-color: var(--hfpan-primary, #3199f8);
    color: var(--hfpan-primary, #3199f8);
}

/* ★★ A~Z 竖排：悬浮在左栏左侧，透明背景，**只占很窄一条** */
.hfpan-cat__azrail {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    /* ⚠️ 0.13.3：42px → 26px；0.13.5 再收到 22px ——
       老板两次反馈「空出来好大一格」「挤在一起了」，
       这个宽度必须和下面 `.is-brand-on .hfpan-cat__files` 的左内边距配套。 */
    width: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    /* ⚠️ 老板明确要求**透明背景** —— 目录底下能透过去 */
    background: transparent;
    user-select: none;
    z-index: 2;
}

.hfpan-cat__azrail[hidden] { display: none; }

.hfpan-cat__azlist {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0;
    max-height: 100%;
    /* ★ 0.13.48：字号调大后 26 个字母放不下 → **让它滚**（`auto` 只在需要时出滚动条）。
       ⚠️ 不写这条会怎样：`.azlist` 是纵向 flex 容器、字母是它的子项，
          子项默认 `flex-shrink:1` → 放不下时**被压扁**而不是溢出，
          于是「字比盒子高、26 个字母挤成一团」（实测：字号到 15.5px 以后
          盒子就卡死在 23.86px = 620/26 不再长）。配合下面 `.azl { flex: none }` 才成立。 */
    overflow-y: auto;
    overflow-x: hidden;

    /* ══ ★★ 0.13.56：**滚动条不显示，但滚动能力保留** ══════════════════════
       老板原话（附截图，指着字母右边那根灰色杠）：
         「这个字母右边的杠杠可以不让他显示吗 手机可以做上下滑动 **也要去掉杠杠**」。
       ── 为什么要"藏条不藏滚" ─────────────────────────────────────────
         ① 那根条**很占地方**：字母栏总共只有 22px 宽，滚动条一进来就吃掉十几像素
            → 字母被挤到一边（老板截图上就是这么挤着的）；
         ② 但**滚动本身要留着** —— 字号调大后 26 个字母确实放不下，
            手机上还得能上下滑（老板明确说"手机可以做上下滑动"）。
       ── 怎么藏（三件套，缺一个就有浏览器还显示）──────────────────────
         · `scrollbar-width: none`   → Firefox
         · `-ms-overflow-style: none`→ 老 Edge / IE
         · `::-webkit-scrollbar`     → Chrome / Safari / Edge（见下一条规则）
       ⚠️ 别改成 `overflow: hidden` —— 那是**连滚动一起废掉**，
          字号一大底部的字母就永远看不到了。 */
    scrollbar-width: none;
    -ms-overflow-style: none;
    /* 手机上把"竖着滑"这件事说明白（横滑交给外层，不抢手势） */
    touch-action: pan-y;
    -webkit-overflow-scrolling: touch;
}

/* 藏 WebKit 系的滚动条（Chrome / Safari / Edge）——
   ⚠️ 必须写伪元素本身，光靠 `scrollbar-width` 在 Chrome 上不生效。 */
.hfpan-cat__azlist::-webkit-scrollbar {
    width: 0;
    height: 0;
    display: none;
}

/* 单个字母：26 个，**全部可点**（没有 # 兜底分类、没有灰掉的）
   ★ 0.13.48：字号与盒子都跟着 `--hfpan-azl-size` 走（老板要求「A-Z 首字母」可调）——
   盒子用 **em**，字号一调宽高自动跟着缩放：
   1.9em × 1.62em 在默认 10.5px 下正好 = 19.95 × 17.01 ≈ 原来的 20×17（观感不变）。 */
.hfpan-cat__azl {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.9em;
    height: 1.62em;
    /* ⚠️⚠️ 必须 `flex: none` —— 见上面 `.azlist` 那段：
       不加就被 flex 压扁（字号一调大就挤成一团）。 */
    flex: none;
    padding: 0;
    border: 0;
    border-radius: 3px;
    background: transparent;
    color: var(--hfpan-primary, #3199f8);
    font-size: var(--hfpan-azl-size, 10.5px);
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    opacity: .62;
    transition: opacity .1s, background .1s;
}

.hfpan-cat__azl:hover {
    opacity: 1;
    background: rgba(49, 153, 248, .16);
}

.hfpan-cat__azl.is-on {
    opacity: 1;
    background: var(--hfpan-primary, #3199f8);
    color: #fff;
    font-weight: 700;
}

/* 左栏：A-Z 展开时只给**抬头/额度条/小标题**让出窄缝。
   ⚠️ 0.13.3：原来给整个左栏加 `padding-left: 42px` —— 老板反馈
      「点开品牌首字母筛选之后目录那边空出来好大一格」，已收窄。 */
.hfpan-cat__left.is-brand-on .hfpan-cat__panehead,
.hfpan-cat__left.is-brand-on .hfpan-cat__quota,
.hfpan-cat__left.is-brand-on .hfpan-cat__sbar,
.hfpan-cat__left.is-brand-on .hfpan-cat__listcap {
    padding-left: 28px;
}

/* ★★ 0.13.5：**目录内容也要让位** ────────────────────────────────
   ── 老板反馈「挤在一起了」──────────────────────────────────────
      A~Z 字母紧贴着文件夹图标和文件名，看着糊成一团。
   ── 为什么必须加在 `.hfpan-cat__files` 上 ────────────────────────
      目录树自己（`.hfpan-cat__tree`）是 `padding: 0 !important` ——
      那是防主题给 ul 加缩进的（见下面那段注释），权重很高、动不了。
      所以只能给**滚动容器**加左内边距，整体把内容推过去。
   ⚠️ 这个值要比 A-Z 的宽度（22px）**大一点**，留出视觉呼吸的间隙 ——
      两者相等时字母右边缘正好贴着图标，就是老板说的「挤在一起」。 */
.hfpan-cat__left.is-brand-on .hfpan-cat__files {
    /* 32px = A-Z 的 22px + 10px 呼吸间隙。
       ⚠️ 不能等于 22px —— 那样字母右边缘正好贴着图标，就是老板说的
          「挤在一起了」（0.13.5 修）。 */
    padding-left: 32px;
    /* 滚动条常驻槽位 —— 否则内容多起来时滚动条会挤占宽度，
       A-Z 和目录的相对位置就跟着变（看着像"忽宽忽窄"）。 */
    scrollbar-gutter: stable;
}

/* ⚠️ 0.13.43：`.hfpan-cat__left.is-brand-on .hfpan-cat__branditem`（品牌行不再重复留内边距）
   已随「品牌列表」一起删掉 —— 品牌不再写进左栏，改成品牌级那一格的下拉
   （见上面的 `.hfpan-cat__bdd`）。`branditem` 现在全项目已无产出点。 */

/* 左栏顶部那条小标题：说明「现在列的是什么」 */
.hfpan-cat__listcap {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 0 0 8px;
    padding: 6px 9px;
    background: #fffdf0;
    border: 1px solid #ffd400;
    border-radius: 5px;
    font-size: 12.5px;
    font-weight: 600;
    color: #7a5d00;
}

.hfpan-cat__listcap[hidden] { display: none; }

.hfpan-cat__listcap__sp {
    margin-left: auto;
    font-weight: 400;
    font-size: 11.5px;
    color: #a7aaad;
}

/* ⚠️ 0.13.43：`.hfpan-cat__brandlist` / `__branditem` / `__brandic` / `__brandnm`
   这一整组**已删** —— 品牌不再画成左栏的目录行。
   老板 0.13.0 的原话是「不做下拉框，直接把品牌文件夹放在目录里」，
   0.13.43 改口：「品牌点击的那个首字母要在对应的勾选的品牌那一级做一个下拉」。
   → 品牌现在走 `.hfpan-cat__bdd`（品牌级那一格的下拉）。
   ⚠️ 左栏顶部那条黄色小标题 `.hfpan-cat__listcap` **保留** ——
      选定品牌后它仍要说明「现在列的是哪个品牌的什么」（renderListCap）。 */

/* 搜索栏下面那行「文件搜索 / 品牌搜索」（老板给的参考图） */
.hfpan-cat__searchopts {
    display: flex;
    align-items: center;
    gap: 56px;                 /* ★ 0.13.38：间隔从 18px 拉大（老板要求） */
    justify-content: center;   /* ★ 0.13.38：两个选项**居中** */
    position: relative;        /* 给右边那句提示做绝对定位用 */
    padding: 9px 14px;
    background: var(--hfpan-surface, #fff);
    border: 1px solid var(--hfpan-line-2);
    border-top: 0;
    border-radius: 0 0 8px 8px;
}

.hfpan-cat__sopt {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--hfpan-ink-2);
    font-size: 13.5px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
}

.hfpan-cat__sopt input { margin: 0; }

.hfpan-cat__sopt:has(input:checked) { color: var(--hfpan-primary, #3199f8); }

.hfpan-cat__soptsp { margin-left: auto; }

/* ★ 0.13.38：两个选项居中后，那个「把提示顶到右边」的占位就不需要了 ——
   提示改成**绝对定位贴右**，这样选项才是真正在整行里居中。
   ⚠️ 别用 `margin-left:auto` 顶提示：那会让选项偏左，不是居中。 */
.hfpan-cat__searchopts .hfpan-cat__soptsp { display: none; }

.hfpan-cat__searchopts .hfpan-cat__sopthint {
    position: absolute;
    right: 14px;
    top: 50%;
    transform: translateY(-50%);
}

/* ══ ★ 0.13.38：「目录」按钮 —— 收起 / 展开左边目录栏 ══════════════════
   ── 布局是 flexbox（`.hfpan-cat__left { flex: 0 0 260px }`）────────
      ⚠️⚠️ 收起**不能只写 `display:none`** —— 万一以后这层换成 grid，
         被摘掉的元素会让后面的兄弟"顶位"掉进 0 宽的轨道里（预览稿就踩过，
         表现为"收起来之后什么都不显示"）。
      → 一律用「**收宽度 + 裁溢出**」：`.left` 本来就有 `overflow:hidden`。 */
.hfpan-cat__item.is-dirhidden .hfpan-cat__left {
    flex: 0 0 0;
    max-width: 0;
    border-right: 0;
}
.hfpan-cat__item.is-dirhidden .hfpan-cat__right { flex: 1 1 auto; }

/* 工具条里那个「目录」按钮的图标 */
.hfpan-cat__toolic {
    width: 14px;
    height: 14px;
    display: block;
    flex: none;
}

/* ⚠️⚠️ 0.13.39：SVG 的 `fill` / `stroke` **必须在这里（或内联 style）再写一遍** ——
   主题的 CSS 里只要有一条 `svg { fill: … }` 就会**盖掉 SVG 的呈现属性**
   （CSS 优先于 `fill="none"` 这种属性）→ 线框图标被填成**实心方块**
   （老板实测：「目录按钮的图标都没显示出来」，截图里就是个蓝方块）。
   → 两个图标分两种：
     · `--line`  = 线框（目录）：不填、只描边
     · `--solid` = 实心（垃圾桶）：填充、不描边 */
.hfpan-cat__toolic--line {
    fill: none !important;
    stroke: currentColor !important;
}
.hfpan-cat__toolic--solid {
    fill: currentColor !important;
    stroke: none !important;
}

/* ⭐ 0.13.39：「目录」按钮跟**重置 / 全屏**长一样（老板：「格格不入」）——
   原来我给它单独写了一套（`--hfpan-primary` 蓝边），跟旁边的黄色「品牌」和
   灰色「重置」都不搭。现在直接沿用 `.hfpan-cat__resetbtn` 那套中性样式，
   只在「已收起」时给一个淡淡的底色提示。 */
.hfpan-cat__dirbtn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex: none;
    padding: 2px 9px;
    border: 1px solid var(--hfpan-line-2, #dcdcde);
    border-radius: 5px;
    background: transparent;
    color: var(--hfpan-ink-2, #646970);
    font-size: 12px;
    line-height: 1.7;
    cursor: pointer;
    transition: all .15s ease;
}
.hfpan-cat__dirbtn:hover {
    border-color: var(--hfpan-ink-3, #8c8f94);
    color: var(--hfpan-ink, #1d2327);
}
/* 收起状态：淡淡的底 + 深一点的边 —— 一眼知道"现在是收着的" */
.hfpan-cat__dirbtn.is-on {
    background: var(--hfpan-surface-2, #f6f7f9);
    border-color: var(--hfpan-ink-3, #8c8f94);
    color: var(--hfpan-ink, #1d2327);
}

/* ══ ★★ 0.13.53：阅读器页码 —— **两个可点的方框**（老板给的参考图）══════
   形态 `[5] / [30]`：**左框 = 当前页**（点一下 = 上一页）、**右框 = 总页数**（点一下 = 下一页）。
   老板原话：「参考图片 将页数那个改为可交互 前面的例如5/30的5 不可自定义填写
             改为可以交互的点击的形式」+ 图注「这两个就是按钮 往前翻，往后翻」。
   ⚠️ 0.13.38 那版是「第 [X] / N 页」，X 是个**可输入框** —— 这次按要求撤掉输入、
      换成按钮，别再退回 input。
   ⚠️ 原来这里还有**第二套** `.hfpan-cat__pager` 规则（旧版「‹ 页码 › 成组」留下的），
      两套互相打架 —— 这次一并清掉，只留这一套。 */
.hfpan-cat__pager {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-left: 4px;
    font-size: 12.5px;
    white-space: nowrap;               /* 别被换行拆散 */
}
.hfpan-cat__pager[hidden] { display: none; }   /* 没有页码概念的文件不显示 */

.hfpan-cat__pagesep {
    color: var(--hfpan-ink-3);
    font-size: 12.5px;
}

/* 两个方框按钮 —— 照参考图那种"小方框数字"的观感 */
.hfpan-cat__pagebtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 34px;
    padding: 2px 7px;
    border: 1px solid var(--hfpan-line);
    border-radius: 5px;
    background: var(--hfpan-surface);
    color: var(--hfpan-ink);
    font: inherit;
    font-size: 12.5px;
    font-weight: 600;
    line-height: 1.5;
    cursor: pointer;
    transition: border-color .14s, color .14s, background .14s;
}

.hfpan-cat__pagebtn:hover:not(:disabled) {
    border-color: var(--hfpan-blue);
    color: var(--hfpan-blue-ink);
    background: var(--hfpan-blue-soft);
}

/* ⚠️ 到头了就把那个按钮**变灰**（点了也没反应，不如明说）——
   第一页时「上一页」灰、最后一页时「下一页」灰（由 syncPager 设 disabled）。 */
.hfpan-cat__pagebtn:disabled {
    opacity: .45;
    cursor: default;
}

/* 「当前页」那个框（左框）用主色轻强调一下，跟右边"总数"区分开 */
.hfpan-cat__pagebtn[data-hfpan-pageprev] {
    color: var(--hfpan-blue-ink);
    border-color: var(--hfpan-blue-line);
}
.hfpan-cat__pagebtn[data-hfpan-pageprev]:disabled {
    color: var(--hfpan-ink);
    border-color: var(--hfpan-line);
}

.hfpan-cat__tbtn--nav {
    padding: 4px 8px;
    font-size: 15px;
    line-height: 1;
}

/* 手动缩放时显示倍率；自适应时是空的 */
.hfpan-cat__zoomval {
    min-width: 38px;
    color: var(--hfpan-ink-3);
    font-size: 12px;
}

.hfpan-cat__tbtn {
    /* ⚠️⚠️★ 0..13.83：**这三条不能省** ──────────────────────────────────
       ── 老板实测报的（原话）「这三个按钮PC显示这样」（截图：图标跑到文字**上面**）
       ── 根因 ──────────────────────────────────────────────────────────
          `.hfpan-cat__tbtn` 原来**没写 display** → 按钮是默认的 `inline-block`；
          而图标 `.hfpan-cat__btnico` 为了脱离"文字基线"写的是 `display:block`
          → **块级子元素强制换行**，图标被挤到文字上一行。
          （对照：`.hfpan-cat__fontbtn` / `.hfpan-cat__detailbtn` 本来就写了
            `inline-flex`，所以「字号」「详情」看着是正常的 —— 只有这三个按钮坏。）
       ── 顺带修掉的第二个 bug ────────────────────────────────────────────
          手机端那两条规则里有 `justify-content: center` ——
          **`justify-content` 只对 flex 容器生效**，原来等于没写、图标没居中。
          改成 inline-flex 之后它才真的起作用。
       ⚠️ 以后往按钮里塞图标，**先确认按钮是 flex 容器**。 */
    display: inline-flex;
    align-items: center;
    gap: 5px;

    padding: 4px 12px;
    border: 1px solid var(--hfpan-line);
    background: var(--hfpan-surface);
    color: var(--hfpan-ink);
    border-radius: 5px;
    font-size: 13px;
    line-height: 1.5;
    cursor: pointer;
    transition: all .15s ease;
}

.hfpan-cat__tbtn:hover {
    border-color: var(--hfpan-blue);
    color: var(--hfpan-blue-ink);
}

.hfpan-cat__viewer {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: auto;
    background: var(--hfpan-viewer-bg);

    /* ★ 0.14.6：手机端**双指捏合由我们自己接管**（缩放的是文件，不是整个网页）——
       `pan-x pan-y` = 单指上下左右照常原生滚动，但**不允许浏览器自己做 pinch-zoom**
       （这个列表里没有 `pinch-zoom`）→ 两指手势原样派发给我们，
       由 catalog.js 的 touchstart / touchmove 处理。
       ⚠️ 只写在阅读器上 —— 页面其余部分保留浏览器自带的捏合缩放
          （那是无障碍能力，不该全局禁掉）。
       ⚠️ 别写 `touch-action:none` —— 那会**连单指滚动一起废掉**（本 bug 的前车之鉴）。 */
    touch-action: pan-x pan-y;

    /* ══ ★★ 0.14.58：**预览内容保护**（老板报的 P0：右键就能复制/保存）══════
       ── 老板原话 ──────────────────────────────────────────────────────────
         「页面上所有展示的 pdf 或者图片 均可以使用**右键复制粘贴和保存图片**」。
       ── 这三条各管什么 ────────────────────────────────────────────────────
         · `user-select: none`     —— 选中不了（Ctrl+C 那条路堵掉）；
         · `-webkit-touch-callout` —— **iOS 长按**弹出的那个菜单
                                     （"存储图像 / 拷贝"就是它，不是 contextmenu）；
         · `-webkit-user-select`   —— Safari 要这个前缀才认。
       ── ⚠️ 文本选择工具必须放行 ──────────────────────────────────────────
         下面那条 `.hfpan-cat__viewer[data-tool="text"] { user-select: text }`
         是 (0,2,0)，**压得过**这里的 (0,1,0) ✓ —— 所以"文本选择工具"照旧能选字，
         别把那条删了。
       ── ⚠️ 这**不是"安全边界"** ──────────────────────────────────────────
         截图 / 录屏 / 开发者工具里直接找流地址都绕得过去。
         真正管用的是"流地址一次性 token + 水印溯源"（见 catalog.js 那段长注释）。 */
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
}

/* 内容超出可视范围时可按住拖动平移（JS 加 is-pannable / is-panning）——
   给 grab 光标，不然用户根本不知道这里能拖。 */
.hfpan-cat__viewer.is-pannable {
    cursor: grab;
}

.hfpan-cat__viewer.is-panning {
    cursor: grabbing;
    user-select: none;
}

.hfpan-cat__frame {
    display: block;
    width: 100%;
    flex: 1;
    min-height: 0;
    border: 0;
    background: var(--hfpan-surface);
}

.hfpan-cat__img {
    display: block;
    max-width: 100%;
    margin: 0 auto;
    /* ★★ 0.14.59：`height: auto` 必须有 —— 图片现在渲染成 **`<canvas>`**
       （为了把水印画进像素，见 catalog.js 的 renderImage）。
       ⚠️ `<img>` 的 `height` 默认就是 auto（`max-width:100%` 会等比缩），
          但 **`<canvas>` 的默认高度是它的 `height` 属性值** ——
          不写 auto 的话 `max-width:100%` 会把它**横向压扁**（比例全错）✗
          （这条对 `<img>` 无副作用，所以两条路径共用一条规则。） */
    height: auto;
    /* ★★ 0.14.58：拖拽也堵掉（JS 那边已有 `dragstart` 拦截，这是 CSS 侧的第二道）——
       不然按住图片拖到桌面就是一次"另存为"。
       （`draggable="false"` 是 HTML 侧的第一道，见 catalog.js 的 renderImage。） */
    -webkit-user-drag: none;
    user-drag: none;
}

.hfpan-cat__viewer .hfpan-cat__tip {
    padding: 34px 16px;
    text-align: center;
}

/* pdf.js 画布容器：居中 + 可滚动 */
.hfpan-cat__canvaswrap {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    padding: 12px;
    box-sizing: border-box;

    /* ⚠️ 这两行是「放大后左边看不见」的根治办法（0.4.5，老板实测报回）：
       内容比容器宽时，如果容器width固定 100% 再靠 justify-content 居中，
       溢出的部分会被**平分到左右两侧** —— 而滚动区只能从 0 开始，
       分到左边的那一半（实测 293px）**永远滚不到**，看上去就是「左边被挡死」。
       改成「容器按内容撑开（max-content），自己用 auto 外边距居中」：
       内容窄时 min-width:100% 照样铺满并居中；内容宽时容器跟着变宽、贴左，
       整份内容都能滚到。 */
    width: max-content;
    min-width: 100%;
    margin: 0 auto;
}

.hfpan-cat__canvaswrap canvas {
    display: block;
    box-shadow: var(--hfpan-shadow-3);
}

/* ── 连页模式：整份 PDF 纵向排开，往下拉看完全部 ─────────────
   默认就是这个模式（客户要的「以前那种」效果）；
   点「翻译」时才自动切成单页。 */
.hfpan-cat__pdfscroll {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 14px;
    box-sizing: border-box;

    /* ⚠️ 必须 flex:none —— 它是纵向 flex 容器里的子项，
       默认允许收缩会把整摞页面压进一屏高度，滚动就没了。 */
    flex: none;

    /* 同 canvaswrap：按内容撑开 + auto 外边距居中，
       否则放大后居中的溢出会分一半到滚动起点左边 → 左边永远滚不到。 */
    width: max-content;
    min-width: 100%;
    margin: 0 auto;
}

.hfpan-cat__pdfpage {
    /* 还没画出来的页：白底占位 + 中间一个页码，尺寸由 JS 按页面比例算好 */
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    background: var(--hfpan-surface);
    box-shadow: var(--hfpan-shadow-3);
    color: var(--hfpan-ink-3);
    font-size: 13px;
}

.hfpan-cat__pdfpage canvas {
    display: block;
}

/* ── hidden 属性兜底 ────────────────────────────────────────
   ⚠️⚠️ 这条不能删，而且**凡是「靠 hidden 显隐 + 自己设了 display」的元素都必须列进来**：
      主题自带的 bootstrap 里 `[hidden]{display:none}` 与我们的 `.xxx{display:flex}`
      **同权重（0,1,0）**，同权重看加载顺序 —— 插件样式在主题之后加载，
      会把 hidden 盖掉 → 元素明明设了 hidden 却还显示着。

   ⭐ 0.7.8 补漏（老板在验收站看到「目录面板下面那条粉色条」就是这个）：
      `.hfpan-cat__sbar`（搜索结果提示条）的 `display:flex` 把 hidden 盖掉了 →
      平时没搜索时也露一条空的粉底条（`--hfpan-mark-soft` 就是淡粉）。
      同一批漏掉的还有 `.hfpan-cat__quota`（display:grid）与
      `.hfpan-cat__canvaswrap`（display:flex）。

   ⚠️ 以后新增「默认 hidden、靠 JS 显隐」的元素时，**先看它有没有设 display**：
      设了就必须加到这里，否则又是同一个坑。

   ⭐ 0.13.13 补：`.hfpan-cat__ldd`（可输入下拉的候选层）也是「默认 hidden、
      靠 JS 显隐」，而且它设了 `position:absolute` 与 `box-shadow` ——
      不加进来，换主题后又会在没打字时露出一个空白的浮层。
   ⭐ 0.13.14 补：`.hfpan-cat__sdd`（搜索栏「目录搜索」的候选下拉）同理，
      它还是**JS 动态创建**的，更要靠这条兜底。 */
.hfpan-cat__tr[hidden],
.hfpan-cat__tbtn[hidden],
.hfpan-cat__sbar[hidden],
.hfpan-cat__quota[hidden],
.hfpan-cat__canvaswrap[hidden],
.hfpan-cat__ldd[hidden],
.hfpan-cat__sdd[hidden],
.hfpan-cat__selects[hidden] {
    display: none !important;
}

/* ── 译文浮层：**叠在原文上方**（不替换原文、不另开页）────────
   客户明确要求的形态。半透明白底 + 卡片阴影，
   固定在预览区右侧，可滚动、可关闭。 */
.hfpan-cat__tr {
    position: absolute;
    top: 52px;                       /* 工具条下面一点 */
    right: 12px;
    z-index: 20;
    width: 44%;
    max-width: 420px;
    max-height: calc(100% - 76px);
    display: flex;
    flex-direction: column;
    background: var(--hfpan-veil);
    border: 1px solid var(--hfpan-line);
    border-radius: 8px;
    box-shadow: var(--hfpan-shadow-4);
    font-size: 13px;
    line-height: 1.6;
    overflow: hidden;
}

.hfpan-cat__tr-head {
    flex: none;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 10px;
    background: var(--hfpan-surface-2);
    border-bottom: 1px solid var(--hfpan-line-2);
}

.hfpan-cat__tr-title {
    flex: 1;
    min-width: 0;
    font-weight: 500;
    color: var(--hfpan-ink);
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* 「图片识别」标记 —— 让用户知道这份译文是从图片认出来的 */
.hfpan-cat__tr-badge {
    flex: none;
    padding: 1px 6px;
    border-radius: 3px;
    background: var(--hfpan-surface-3);
    color: var(--hfpan-quota-pts);
    font-size: 12px;
}

.hfpan-cat__tr-close {
    flex: none;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--hfpan-ink-2);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
}

.hfpan-cat__tr-close:hover {
    color: var(--hfpan-ico-pdf);
}

.hfpan-cat__tr-body {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: 8px 10px;
}

.hfpan-cat__tr-row {
    padding: 6px 0;
    border-bottom: 1px dashed var(--hfpan-line-2);
}

.hfpan-cat__tr-row:last-child {
    border-bottom: 0;
}

.hfpan-cat__tr-src {
    color: var(--hfpan-ink-3);
    font-size: 12px;
}

.hfpan-cat__tr-dst {
    color: var(--hfpan-ink);
    word-break: break-word;
}

.hfpan-cat__tr-foot {
    flex: none;
    padding: 6px 10px;
    border-top: 1px solid var(--hfpan-line-2);
    background: var(--hfpan-surface-3);
    color: var(--hfpan-ink-3);
    font-size: 12px;
}

.hfpan-cat__tr-wait,
.hfpan-cat__tr-error {
    margin: 0;
    padding: 14px 4px;
    text-align: center;
    color: var(--hfpan-ink-2);
}

.hfpan-cat__tr-error {
    color: var(--hfpan-ico-pdf);
}

/* 语言选择 */
.hfpan-cat__tr-langs {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.hfpan-cat__tr-lang {
    padding: 5px 12px;
    border: 1px solid var(--hfpan-line);
    border-radius: 5px;
    background: var(--hfpan-surface);
    color: var(--hfpan-ink);
    font-size: 13px;
    line-height: 1.5;
    cursor: pointer;
    transition: all .15s ease;
}

.hfpan-cat__tr-lang:hover {
    border-color: var(--hfpan-blue);
    color: var(--hfpan-blue-ink);
}

.hfpan-cat__tr-lang.is-on {
    background: var(--hfpan-blue);
    border-color: var(--hfpan-blue);
    color: var(--hfpan-on-blue);
}

.hfpan-cat__tr-note {
    margin: 10px 0 0;
    color: var(--hfpan-ink-3);
    font-size: 12px;
}

/* 左栏：能点的文件行 */
.hfpan-cat__file.is-clickable {
    cursor: pointer;
}

.hfpan-cat__file.is-clickable:hover {
    background: var(--hfpan-blue-soft);
}

.hfpan-cat__file.is-on {
    background: var(--hfpan-blue-soft);
}

/* ⚠️ 桌面上没有"收起抽屉"这回事 —— 那个 ✕ 一律不显示。
   ⚠️⚠️ 这条**必须排在下面那段 `@media (max-width: 860px)` 之前** ——
      两者特异性都是 (0,1,0)，谁在后面谁赢；写反了手机上也会是 `display:none`
      （我第一版就写反了，真机实测 ✕ 不显示才发现）。 */
.hfpan-cat__dirclose { display: none; }

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.13.58：≤860px 左栏改成**抽屉**（参考老板给的 52chegai.com/dlt）
   ══════════════════════════════════════════════════════════════════════════
   ── 原来错在哪 ──────────────────────────────────────────────────────────
     原来这里是「上下堆叠」：左栏（文件列表）在上、预览在下。
     手机上要读 PDF 得**先滑过整个文件列表**才看得到预览 —— 很别扭。
   ── 参考站怎么做的（抓它的 mobile.css 看过后照做）────────────────────────
     `.directory-panel` 是 `position:absolute; width:75%; max-width:320px;`
     收起时 `transform: translateX(-100%)` —— 即**抽屉**：盖在预览上、滑进滑出；
     另配悬浮圆按钮 + 面板抬头里的 ✕。
     它的文件行也更"点得着"：`min-height:40px`、图标 18px、圆角 8px、选中蓝底白字。
   ── 我们怎么落地（**不新增开关逻辑**）──────────────────────────────────
     复用已有的 `is-dirhidden` class（工具条「目录」按钮 + localStorage 记忆），
     抽屉的滑出/滑进就是它；抬头那个 ✕ 也挂同一个 `data-hfpan-dirtoggle`。
   ⚠️ 只对**有右栏**的 body 生效 —— `.is-single` 是「只下载」类型（只有左栏），
      把它设成 absolute 会让 body 高度塌成 0、整块消失。
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 860px) {

    /* ── 抽屉的定位上下文 ─────────────────────────────────────────────── */
    .hfpan-cat__body:not(.is-single) {
        position: relative;

        /* ⚠️⚠️★ 0.14.6：**这里绝对不能写 `display:block`** ──────────────────
           ── 老板实测报的（手机端，原话）──────────────────────────────────
             「垂直滚动在手机页无法正常使用 表现是阅读器的 pdf 无法正常上下滑动
               但是切换为水平滚动即可正常左右滑动」
           ── 根因（无头浏览器实测，不是读 CSS 猜的）────────────────────────
             写成 `display:block` 之后，**右栏的高度就变成"内容多高就多高"**：
               · `.hfpan-cat__body`   高 620px、`overflow:hidden`（有界 + 裁溢出）
               · `.hfpan-cat__right`  高 **5807px**（被 PDF 内容整个撑开）
               · `.hfpan-cat__viewer` clientHeight **=** scrollHeight = 5754px
             → 阅读器**根本不是滚动容器**（没有高度差可滚）：
               手指竖滑时 `scrollTop` 恒为 0，滑的是**整页**（实测 pageScrollY=283），
               而 620px 以外的页面全被 body 裁掉 —— **永远够不到**。
           ── 为什么偏偏「水平能滑、垂直不能滑」────────────────────────────
             横向模式下**宽度**天然有界（右栏宽 = 容器宽）→ 横向滚动成立 ✓
             而纵向的**高度**当时是无界的 → 纵向滚动不成立 ✗
             （所以 0.13.99~0.14.5 那几版改 `touch-action` / 反边距 / 视图模式
               全都无效 —— **病灶在高度链，不在手势、也不在状态**。）
           ── 修法：**保留 flex，别动它** ────────────────────────────────────
             基类 `.hfpan-cat__body{display:flex;align-items:stretch;height:620px}`
             本身就对：左栏是 `position:absolute`（脱离文档流），右栏是唯一的
             流内子项 → `align-items:stretch` 把它拉到 620px → 阅读器高度有界 → 能滚 ✓
             ⚠️ 这**正是「只下载」类型（`.is-single`）一直好用的原因**：
                下面这条选择器带 `:not(.is-single)`，它的 body 从来都是 flex
                （实测其文件列表 clientHeight 553 / scrollHeight 1227 = 能滚）。
                也就是说**坏的只有"有右栏"这一支**，改法就是让两支一致。
             ⚠️ 别再往这里加 `display:block` / `flex-direction:column` ——
                前者复现本 bug，后者会让左栏那条 absolute 抽屉的
                `top:0;bottom:0` 与 `align-items:stretch` 的既有行为一起变。 */
        overflow: hidden;
    }

    /* ── 左栏 = 抽屉：默认滑出屏幕外，没被收起时滑进来 ────────────────── */
    .hfpan-cat__body:not(.is-single) .hfpan-cat__left {
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        width: 86%;
        max-width: 340px;
        flex: none;
        z-index: 30;
        border-right: 1px solid var(--hfpan-line);
        border-bottom: 0;
        box-shadow: 2px 0 18px rgba(0, 0, 0, .22);
        transform: translateX(-104%);
        transition: transform .26s cubic-bezier(.4, 0, .2, 1);
    }

    .hfpan-cat__item:not(.is-dirhidden) .hfpan-cat__body:not(.is-single) .hfpan-cat__left {
        transform: none;
    }

    /* ── 遮罩：点一下就收起（伪元素挂在 body 上，点击会算到 body 头上）── */
    .hfpan-cat__body:not(.is-single)::after {
        content: '';
        position: absolute;
        inset: 0;
        background: rgba(0, 0, 0, .34);
        z-index: 25;
        opacity: 0;
        pointer-events: none;
        transition: opacity .26s;
    }

    .hfpan-cat__item:not(.is-dirhidden) .hfpan-cat__body:not(.is-single)::after {
        opacity: 1;
        pointer-events: auto;
    }

    /* ── 右栏（工具条 + 预览）铺满，给足高度 ──────────────────────────── */
    .hfpan-cat__body:not(.is-single) .hfpan-cat__right {
        min-height: 480px;
    }

    .hfpan-cat__viewer,
    .hfpan-cat__frame {
        min-height: 420px;
    }

    /* ── 窄屏放不下「右半边浮层」—— 改成横跨整块，压在原文下方 ────────── */
    .hfpan-cat__tr {
        left: 8px;
        right: 8px;
        width: auto;
        max-width: none;
        max-height: 62%;
    }

    /* ── 文件 / 文件夹行：按参考站的口径做"点得着"（≥44px）───────────── */
    .hfpan-cat__node {
        min-height: 44px;
        padding: 10px 10px 10px 4px;
        border-radius: 8px;
        font-size: 14px;
    }

    /* 触摸反馈（参考站的 `:active` 那套）—— 手机上悬停不可用，靠这个给反馈 */
    .hfpan-cat__node.is-dir:active,
    .hfpan-cat__node.is-file.is-clickable:active {
        background: var(--hfpan-blue-soft);
    }

    /* ── 抽屉抬头那个 ✕（桌面隐藏，见下面那条全局规则）────────────────── */
    .hfpan-cat__dirclose {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        margin-left: auto;
        width: 40px;
        height: 40px;
        padding: 0;
        border: 0;
        border-radius: 50%;
        background: rgba(255, 255, 255, .18);
        color: var(--hfpan-head-fg);
        cursor: pointer;
        flex: none;
    }

    .hfpan-cat__dirclose svg {
        width: 18px;
        height: 18px;
        display: block;
    }

    .hfpan-cat__dirclose:active {
        background: rgba(255, 255, 255, .34);
    }
}


/* ⚠️ 手机上插件底部要给主题的**固定底栏**（子比 footer-tabbar）留位置，
   否则最后一行文件会被压在底栏下面、点不到。
   参考站的 mobile-layout-fix.css 就是专门处理这件事的（它留了 140px）。 */
@media (max-width: 860px) {
    .hfpan-cat__files {
        padding-bottom: 76px;
    }
}

/* ── 左栏：可展开的目录树（文件夹 + 文件混排） ────────── */

.hfpan-cat__left .hfpan-cat__files {
    flex: 1;
    overflow: auto;
    padding: 4px 0;
}

/* ⚠️ 这段必须写成高权重 + !important —— 实测踩过坑：
   主题（子比等）普遍会给正文里的 ul / li 加缩进，比如
       .entry-content ul { padding-left: 2em }
   它的权重是 (0,1,1)，比单写一个 .hfpan-cat__tree (0,1,0) **高一档**，
   会把我们的 padding:0 重置压过去 —— 表现就是**左边空出一大片白**，
   图标被推到 40~70px 之外（实测：文件图标 39px、子文件 73px）。
   这里的 !important 是「嵌进未知主题的组件」的标准自保做法，不要删。 */
.hfpan-cat ul.hfpan-cat__tree,
.hfpan-cat ul.hfpan-cat__children {
    list-style: none !important;
    margin: 0 !important;
    padding: 0 !important;
}

.hfpan-cat ul.hfpan-cat__children {
    padding-left: 14px !important;
}

.hfpan-cat li.hfpan-cat__node {
    list-style: none !important;
    margin: 0 !important;
    padding-left: 2px !important;
    text-indent: 0 !important;
}

/* 子列表：占满整行 + 缩进一层 —— 这才是"树"该有的样子 */
.hfpan-cat__children {
    grid-column: 1 / -1;
    position: relative;
}

/* 子层级左侧一条淡竖线：一眼看出「这些是属于上一层文件夹的」 */
.hfpan-cat__children::before {
    content: '';
    position: absolute;
    left: 5px;
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--hfpan-line);
}

.hfpan-cat__children > .hfpan-cat__node:last-child {
    border-bottom: 0;
}

/* ⚠️ 树的每个节点必须用 grid，不能用 flex：
   每行里还嵌着一个 <ul>（子列表），用 flex 的话它会被当成一个 flex 项，
   跟箭头、图标挤在同一行上，展开时看着就是"乱掉 / 没显示"。
   grid 五列 = 箭头 / 图标 / 名字 / 大小 / 按钮，子列表让它跨满整行。 */
.hfpan-cat__node {
    display: grid;
    grid-template-columns: 10px 15px minmax(0, 1fr) auto auto;
    align-items: center;
    column-gap: 6px;
    /* ★ 0.5.4 表格化：行高略增、行间加淡分隔线、悬停给淡蓝底 ——
       跟预览稿的文件列表观感一致（原来是 6px 内边距、几乎看不出行）。 */
    padding: 8px 8px 8px 2px;
    border-bottom: 1px solid var(--hfpan-line-2);
    font-size: 14px;
    line-height: 1.5;
    transition: background .12s ease;
}

.hfpan-cat__node:last-child {
    border-bottom: 0;
}

.hfpan-cat__node:hover {
    background: var(--hfpan-surface-2);
}

.hfpan-cat__node.is-dir {
    cursor: pointer;
    font-weight: 500;
    color: var(--hfpan-ink);
}

.hfpan-cat__node.is-file.is-clickable {
    cursor: pointer;
}

/* 当前正在预览的那一行（比悬停更明显一点）。
   ⚠️ 左侧那道竖条用 `box-shadow: inset` 画 —— 不能用 `border-left`，
      否则会挤动整行内容（图标和文件名一起右移 3px，看着像跳了一下）。 */
.hfpan-cat__node.is-on {
    background: var(--hfpan-blue-soft);
    box-shadow: inset 3px 0 0 var(--hfpan-blue);
}

/* 最左边那一格是**展开箭头**的位置：文件夹有 ▶（点它展开/收起）。
   文件行不再留这一格（JS 里不输出 twist），图标直接靠最左 ——
   实测反馈：文件行那格留空会被当成"莫名其妙的空白 / 看不到"。 */
.hfpan-cat__twist {
    flex: none;
    width: 10px;
    height: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--hfpan-ink-2);
    transition: transform .15s ease;
}

.hfpan-cat__node.is-dir.is-open > .hfpan-cat__twist {
    transform: rotate(90deg);
}

.hfpan-cat__twist svg {
    display: block;
}

/* ── 文件 / 目录图标（0.5.4：Font Awesome 4 + 彩色底）──────────
   客户选的是「用子比自带的 FA4」。FA4 只有描边图标，观感比 FA6 的实心弱，
   所以做成**彩色圆角底 + 白色描边图标** —— 远看更接近预览稿那种"实心块"。
   ⚠️ 尺寸/行高必须显式定：FA4 的 <i> 是行内元素，不定会撑高行、
      和旁边的文件名基线对不齐（子比正文行高偏大）。
   ⚠️ `.fa` 的 font-family 由主题的 font-awesome.min.css 提供 —— 不重复加载。 */
.hfpan-cat__ico {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;

    width: 16px;
    height: 16px;
    border-radius: 4px;
    font-size: 9px;
    line-height: 1;
    color: #fff;                       /* 图标本身画成白色 */
    background: var(--hfpan-ink-3);    /* 未知类型：中性灰底 */
    speak: none;
    font-style: normal;
    font-variant: normal;
    text-transform: none;
    -webkit-font-smoothing: antialiased;
}

/* 底色按类型分（跟预览稿一致） */
.hfpan-cat__ico.is-dir   { background: var(--hfpan-ico-dir); }   /* 文件夹：黄（FA4 的实心文件夹） */
.hfpan-cat__ico.is-pdf   { background: var(--hfpan-ico-pdf); }   /* PDF：红 */
.hfpan-cat__ico.is-img   { background: var(--hfpan-ico-img); }   /* 图片：蓝 */
.hfpan-cat__ico.is-vid   { background: var(--hfpan-ico-vid); }   /* 视频：紫 */
.hfpan-cat__ico.is-aud   { background: var(--hfpan-ico-aud); }   /* 音频：橙 */
.hfpan-cat__ico.is-zip   { background: var(--hfpan-ico-zip); }   /* 压缩包：暗黄 */
.hfpan-cat__ico.is-doc   { background: var(--hfpan-ico-doc); }   /* 文档：蓝 */
.hfpan-cat__ico.is-xls   { background: var(--hfpan-ico-xls); }   /* 表格：绿 */
.hfpan-cat__ico.is-ppt   { background: var(--hfpan-ico-ppt); }   /* 演示：橙红 */
.hfpan-cat__ico.is-code  { background: var(--hfpan-ico-code); }   /* 代码：灰蓝 */
.hfpan-cat__ico.is-other { background: var(--hfpan-ink-3); }

/* 文件夹是实心图标，白字 + 黄底可能发飘 —— 稍微压一点亮度 */
.hfpan-cat__ico.is-dir {
    font-size: 10px;
}

/* 文件行没有箭头，照旧让图标靠最左（与文件夹行的箭头左对齐）——
   但**不能**用「图标跨箭头+图标两列」的写法：跨列只会让图标起点左移，
   文件名仍从第 3 列开始，中间就空出「箭头列 + 间距」的空白，
   实测反馈「图标和文件名距离太远」。
   正确做法：文件行单独用 3 列（没有箭头那一列），图标落在第 1 列、
   文件名紧跟其后 —— 左边缘依然与箭头对齐，中间只剩正常的 6px 间距。
   ⚠️ 0.7.7 去掉「文件大小」那一列（原为 `15px minmax(0,1fr) auto auto`），
      文件行只剩「图标 / 名字 / 行内下载按钮」。 */
.hfpan-cat__node.is-file {
    grid-template-columns: 15px minmax(0, 1fr) auto;
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.53：树里的文件名**不再截断**，改成"整棵树横向滑动"（老板要求）
   ── 老板原话 ──────────────────────────────────────────────────────────────
     「目录下的文件夹名过长 超出最大显示值则**不做截断** 而是**可以向右滑动**
       手机交互则是可以**手指向右滑动** 查看完整文件名
       **取加载最长的文件名为标准来进行展示**」。
   ── 改前是什么 ────────────────────────────────────────────────────────────
     名字那一格是 `minmax(0,1fr)` + `text-overflow: ellipsis` ——
     面板只有 260px（手机抽屉 75%），名字一长就变成「非常长的资料文件夹名…」✗
   ── 改法（**只有两条，缺一不可**）─────────────────────────────────────────
     ① 这一格**不再省略**：`overflow: visible` + `text-overflow: clip`
        （`white-space: nowrap` 保留 —— 名字必须**一行**，才能"往右滑看全"）；
     ② 下面那条 `.hfpan-cat__tree { min-width: max-content }` ——
        **这就是"取加载最长的文件名为标准"**：
        `max-content` = "按内容最宽的那一行来算"，于是整棵树的宽度
        自动等于**当前已加载的、最长的那个名字**所在行的宽度 ✓
        （不用 JS 去量、也不怕懒加载 —— 新展开的目录比原来长，树自己就变宽）。
   ── 为什么两条要配套 ──────────────────────────────────────────────────────
     只加 ①：名字会被 `1fr` 那一列压扁 / 溢出到行外；
     只加 ②：那一列仍是 `1fr`（吃掉剩余宽度）→ 名字照样被省略号截掉。
   ── 滑动的方向 / 手感 ────────────────────────────────────────────────────
     横向滚动条由 `.hfpan-cat__left .hfpan-cat__files` 自己的 `overflow: auto`
     提供（面板 260px 装不下变宽的树）；手机就是手指左右滑。
   ── ⚠️ 为什么文件名那格还要留 `min-width: 0` ──────────────────────────────
     它属于 grid 项，`min-width: 0` 让**列宽由轨道决定**（而不是被内容顶开）——
     树已经够宽了，不需要它再去顶。
   ══════════════════════════════════════════════════════════════════════════ */
.hfpan-cat__node .hfpan-cat__fname {
    min-width: 0;
    overflow: visible;
    white-space: nowrap;
    text-overflow: clip;
    font-weight: 400;
    /* 字号可由后台配（默认 14px） */
    font-size: var(--hfpan-fname-size, 14px);
}

/* ★★ 0.14.53：整棵树的宽度 = **已加载的最长名字**那一行的宽度（见上面那段说明）
   ⚠️ 只给**顶层**的 `.hfpan-cat__tree` 加，**不要**加到 `.hfpan-cat__children`：
      子层是嵌在父行里的，父行的 max-content 已经把它算进去了；
      给子层也加一遍等于重复算，5~6 级的深树会**越算越宽**。
   ⚠️ 也不能加到 `.hfpan-cat__hits`（搜索结果那套）—— 那边的名字是
      `word-break: break-all` **换行显示**的，宽度必须是 100%，不然长名字会被推出屏幕。 */
.hfpan-cat__left .hfpan-cat__files > ul.hfpan-cat__tree {
    min-width: max-content;
}

.hfpan-cat__left .hfpan-cat__tip {
    padding: 14px 12px;
    text-align: left;
}

/* ── 手机（≤640px）：级联**每排 4 个** ────────────────────────
   规则（老板定）：
     · 不足一排（例如整行只有 3 个）→ 这几个**平分铺满**那一排；
     · 多于 4 个 → 排到第二排，第二排不足 4 个也**平分铺满**。
   做法：每格用 `flex: 1 1 calc((100% - 30px)/4)` ——
   flex-basis 定「一排 4 个」的宽度，`flex-grow:1` 让不足一排时自动均分剩余空间。
   ⚠️ 桌面那条 `.hfpan-cat__selects.is-fluid .hfpan-cat__selectcell` 特异性更高，
      所以它必须包在 @media (min-width:641px) 里，否则会压过这里（实测踩过）。 */
@media (max-width: 640px) {
    .hfpan-cat__select {
        width: 100%;
    }

    .hfpan-cat__selectcell {
        flex: 1 1 calc((100% - 30px) / 4);
        width: auto;
        min-width: 0;
    }

    /* 手机上搜索栏换行：类型一行、关键词 + 搜索一行 */
    .hfpan-cat__search {
        flex-wrap: wrap;
    }

    .hfpan-cat__searchtype {
        width: 100%;
        border-right: 0;
        border-bottom: 1px solid var(--hfpan-line);
        padding: 8px 12px;
    }

    .hfpan-cat__sgo {
        padding: 0 18px;
    }
}

/* ══════════════════════════════════════════════════════════════
 * ★ 0.7.2 文章插入块（短代码 `[hoarfall_pan]`）
 *
 * 与 `[hoarfall_pan_catalog]` 的视觉差别只有两点，别做多：
 *   ① 没有搜索栏 —— 所以整块直接就是那张面板卡片（不需要上方留白衔接搜索栏）；
 *   ② **没有级联栏**（0.7.6 起）—— 进文章直接列根目录，往下钻靠左栏目录树。
 *
 * ⚠️ 只覆盖这两处。其余样式（面板、文件行、预览区、额度条）**全部复用上面已有的** ——
 *    另起一套必然两处漂移，改一处忘一处。
 * ══════════════════════════════════════════════════════════════ */
.hfpan-cat--single {
    /* 没有搜索栏，靠一个上边距与上一段正文拉开 */
    margin-top: 18px;
}

.hfpan-cat--single .hfpan-cat__item {
    /* catalog 里每个条目上方有一道分隔线（多个条目之间要分家），
       单块时只有它一个，那道线在正文里显得像"半截表格"。 */
    border-top: 0;
}

/* ⛔ 0.7.6 删掉了这两条（原来给「单块里那一级级联」用）：
     .hfpan-cat--single .hfpan-cat__selectcell { flex: 1 1 100%; }
     .hfpan-cat--single .hfpan-cat__selects    { margin-bottom: 12px; }
   因为文章里的块**已经不再输出级联栏**（老板原话：「上面就不需要等级目录栏了」）。
   级联只存在于 `[hoarfall_pan_catalog]` 独立页面，那里走通用样式。
   ⛔ 别再为单块加 selects / selectcell 的样式 —— 那块 DOM 不会再出现。 */


/* fp:7d69ff42a93b47ce */

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.13.57：手机端（≤640px）整体适配 —— 一次把这条理顺
   ══════════════════════════════════════════════════════════════════════════
   ── 老板要求 ────────────────────────────────────────────────────────────
     「对插件所有前台后台的页面对手机版 ui 做一个针对性优化，删除无意义的提示
      例如 滚轮上下翻页 等，以确保能适配市面上多数手机的 ui 而不会出现排版错乱
      ui 错乱 文字超出显示框等相关问题」
   ── 先量再改（真机 iPhone 视口 320/360/375/390/414 实测出来的毛病）──────
     ① **阅读器工具条出界**：320px 时「全屏」右边超出 119px、「翻译」74px ——
        页面不横滚是因为工具条被 `overflow:hidden` 裁掉，也就是**按钮直接看不见**；
     ② **搜索选项提示叠字**：「按文件名提示」绝对定位贴右，窄屏直接压在「文件搜索」上；
        ⚠️ 这条本来是 0.13.x 修过的（「手机端选项退回左对齐」那段 @media），
           0.13.53 我替换页码 CSS 时**连带把它删掉了** → 回归。现在补回来并加强；
     ③ **级联 4 格挤一行**：每格只有 ~70px，「1.欧系」被截成「1.欧…」；
     ④ **搜索栏挤成 4 行**：重置被 `flex:1 1 100%` 顶成独占一行，「搜索」掉到下一行且只有 22px 高；
     ⑤ **点击目标太小**：类型下拉 34px、搜索 22px、级联 38px、抬头按钮 24~30px（手机推荐 ≥40px）。
   ── 这份为什么放在**文件最后** ──────────────────────────────────────────
     靠**源码顺序**压过前面那些零散的手机规则（特异性相同）。
     ⚠️ 以后加手机样式也放这儿，别散在各处 —— 散着写必然互相打架（①②就是教训）。
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

    /* ── ① 搜索栏：**两行**（类型一行；关键词 + 重置 + 搜索 一行）────────── */
    .hfpan-cat__search {
        flex-wrap: wrap;
        align-items: stretch;
    }

    /* 第一行：类型（整行） */
    .hfpan-cat__searchtype {
        flex: 1 1 100%;
        width: auto;
        border-right: 0;
        border-bottom: 1px solid var(--hfpan-line);
        padding: 8px 12px;
        min-height: 50px;
    }

    /* ★★ 0.14.27：手机上**换成自绘下拉**（原生 select 的选项加不了图标）
       ── 分工 ────────────────────────────────────────────────────────────
         · 桌面端：原生 select 照旧（老板说电脑端不用改）；
         · 手机端：原生 select 藏起来，`.hfpan-cat__kindtrig` + `__kindlist` 接管。
       ── ⚠️⚠️ 必须挂在 `.is-built` 上（**失败不能变空框**）──────────────────
         第一版是**无条件** `display: none` 藏原生 select ✗ ——
         结果一旦 JS 没跑起来（浏览器缓存了旧 `catalog.js`、或脚本报错），
         自绘触发条就不存在，而下拉已经被 CSS 藏掉 →
         **整个分类框变成一片空白**（老板的深色截图就是这个状态）。
         → 改成：**只有 JS 成功建出自绘下拉**（给 `.hfpan-cat__kindsel` 加上
           `.is-built`）才藏原生 select。JS 没跑就退回原生下拉，
           顶多"没图标"，但**一定能用**。
       ⚠️ 用 `display: none` 而不是 `visibility/opacity` —— 藏不干净的话，
          原生 select 会在自绘触发条上面**再叠一层**，点下去开的是系统浮层。 */
    .hfpan-cat__kindsel.is-built .hfpan-cat__skind { display: none; }

    .hfpan-cat__kindsel.is-built .hfpan-cat__kindtrig { display: flex; }

    /* ⚠️★ JS 没跑时的**退路**：原生 select 仍要占满、点得着 ──────────────
       0.13.57 给它定的 `min-height: 42px`（手指点得准）+ `max-width: none`
       不能因为改自绘下拉就丢掉 —— 否则 JS 没跑时那个"退路"只有 31px 高。 */
    .hfpan-cat__skind {
        flex: 1 1 auto;
        min-width: 0;
        max-width: none;
        min-height: 42px;
    }

    /* 第二行：关键词 + 重置 + 搜索（都在一行里，别各自占一行） */
    .hfpan-cat__searchkw {
        flex: 1 1 0;
        min-width: 0;
        min-height: 48px;
    }

    .hfpan-cat__search .hfpan-cat__sreset {
        flex: none;
        width: 48px;
        min-height: 48px;
        padding: 0;
        justify-content: center;
        border-right: 1px solid var(--hfpan-line);
        border-top: 0;             /* 盖掉旧规则里那条"独占一行"的写法 */
    }

    .hfpan-cat__sgo {
        flex: none;
        min-height: 48px;
        padding: 0 18px;
    }

    /* ── ② 搜索选项行：**选项一行、提示另起一行**（不再绝对定位叠字）───── */
    .hfpan-cat__searchopts {
        flex-wrap: wrap;
        justify-content: flex-start;
        gap: 4px 26px;
        padding: 10px 12px;
    }

    /* 标签整体当点击目标（radio 本体只有 14×14，手指点不着） */
    .hfpan-cat__sopt {
        min-height: 40px;
        font-size: 14px;
    }

    /* 那个"把提示顶到右边"的占位在换行布局里只会添乱 */
    .hfpan-cat__searchopts .hfpan-cat__soptsp { display: none; }

    /* 提示改成**正常流**里的一行（旧规则是 absolute 贴右 → 窄屏必叠字） */
    .hfpan-cat__searchopts .hfpan-cat__sopthint {
        position: static;
        transform: none;
        flex: 1 1 100%;
        font-size: 12px;
    }

    /* ── ③ 级联：4 格挤一行会截断文字 → **2×2** ─────────────────────────── */
    .hfpan-cat__selects {
        flex-wrap: wrap;
    }

    .hfpan-cat__selectcell {
        flex: 1 1 calc(50% - 5px);   /* 一行两个（间隙 10px） */
        width: auto;
        min-width: 0;
    }

    .hfpan-cat__select,
    .hfpan-cat__lbox {
        width: 100%;
        min-width: 0;
        min-height: 42px;            /* 点击目标 */
    }

    /* ── ④ 阅读器工具条：**会换行**，别把「翻译 / 全屏」裁到屏幕外 ──────── */
    .hfpan-cat__toolbar {
        flex-wrap: wrap;
        gap: 8px;
        padding: 8px 10px;
    }

    /* ★ 老板点名要删的「滚轮上下翻页」—— 手机上根本没有滚轮。
       见下面那条 `@media (hover: none)`：触屏平板（>640px）也一并隐藏。 */
    .hfpan-cat__toolhint { display: none; }

    /* 换行之后这个"把后面顶到最右"的占位会把第二行顶开，去掉 */
    .hfpan-cat__toolsp { display: none; }

    /* 工具条按钮的点击目标（原来 24~30px 高） */
    .hfpan-cat__dirbtn,
    .hfpan-cat__brandbtn,
    .hfpan-cat__fontbtn,
    .hfpan-cat__tbtn {
        min-height: 40px;
        padding: 8px 12px;
    }

    /* 页码两个方框（0.13.53 加的）也跟着放大 */
    .hfpan-cat__pagebtn {
        min-width: 40px;
        min-height: 36px;
    }

    /* ── ⑤ 抬头 / 头像 / 额度卡 ──────────────────────────────────────────── */
    .hfpan-cat__panehead { min-height: 48px; }

    .hfpan-cat__who {
        min-width: 40px;
        min-height: 40px;
    }

    /* ── ⑥ A~Z 字母栏：手指点得着一点（原来 20×17）────────────────────── */
    .hfpan-cat__azrail { width: 28px; }

    .hfpan-cat__azl {
        width: 2.1em;
        height: 1.9em;
    }

    /* ── ⑦ 预览区别在手机上占掉半屏空白 ────────────────────────────────── */
    .hfpan-cat__viewer,
    .hfpan-cat__frame {
        min-height: 320px;
    }
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.27：手机端搜索区改成「两张独立卡片」（老板要求）══════════════════
   ── 老板原话 ────────────────────────────────────────────────────────────
     「手机区域的搜索框和上方的类型保持同样的卡片样式和圆角角度
       在类型框右边添加类型两个字 例如 文档（仅供阅读）  类型
       （搜索框）    图标   搜索
       左右保持对齐 下方搜索添加卡片类样式」
   ── 改前是什么样 ────────────────────────────────────────────────────────
     类型 + 搜索框 + 重置 + 搜索**全在一张卡片里**：类型那行底下一条
     `border-bottom` 分隔线，重置那条竖线横穿整张卡 —— 看着是"一张卡被切成
     四格"，不是两张卡。
   ── 改后 ────────────────────────────────────────────────────────────────
     ① **类型一张卡**：只有下拉 + 右边「类型」两个字，自己带边框与圆角；
     ② **搜索一张卡**：图标 + 输入框 + 重置 + 搜索，同样带边框与圆角；
     ③ 两张卡**同宽同圆角**（都吃 `--hfpan-radius-card`）、左边缘对齐
        （同属 `.hfpan-cat__search` 这个 flex 容器，宽度天然一致）。
   ── ⚠️ 为什么把外框拆到两张卡上 ────────────────────────────────────────
     `.hfpan-cat__search` 原来自己带 `border` + `overflow: hidden` ——
     留着它就只能得到"一张大卡里两条"，做不出两张独立卡 ✗
     （`overflow:hidden` 还会把圆角内的子元素裁出直角）。
     所以外框改成 `border:0 / background:transparent / overflow:visible`，
     框与圆角**下放到两张卡自己身上** ✓
   ── ⚠️ 桌面端不动 ──────────────────────────────────────────────────────
     这条只在 ≤640px 生效；桌面端仍是原来"一条搜索栏"的形态。
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
    /* ① 外框让位给两张卡（透明、不裁、不画框） */
    .hfpan-cat__search {
        background: transparent;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        overflow: visible;
        /* 两张卡之间留 10px（原来是靠 border-bottom 分隔，现在靠间距）
           ⚠️★ 这条 gap 只夹在**类型卡 / 搜索卡**之间 —— 重置与搜索已经
              挪进 `.hfpan-cat__searchkw`（见 class-frontend.php），
              不会再横穿搜索卡内部。 */
        gap: 10px;
    }

    /* ② 类型卡：自带边框与圆角 */
    .hfpan-cat__searchtype {
        background: var(--hfpan-surface);
        border: 1px solid var(--hfpan-line);
        border-radius: var(--hfpan-radius-card);
        box-shadow: var(--hfpan-shadow);
        /* 盖掉旧规则里那条 `border-bottom` 分隔线 —— 现在是两张卡，不需要它 */
        border-bottom: 1px solid var(--hfpan-line);
        /* ⚠️★ 右边距**必须是 0**（左边留 12px）——
           「类型」那张卡片要贴到卡右缘（389）才能和「搜索」按钮同宽同位。
           右边留 12px 的话它最多只能到 377，和按钮差 12px（实测踩到）。
           卡片的圆角由 `overflow` 之外的边框自己收，不需要靠内边距留白。 */
        padding: 8px 0 8px 12px;
    }

    /* ③ 类型卡内部：下拉占满、右边一格**正好等于「搜索」按钮宽**
          ── 老板要求（原话）────────────────────────────────────────────
            「类型选择最右边与搜索框的最右边 搜索按钮最左边平齐」
            「你没发现类型文字和搜索按钮大小不一样吗」
          ── 所以是这两条同时成立 ──────────────────────────────────────
            ① 「类型」那张小卡片 **和「搜索」按钮一样宽**（都 65px）；
            ② 下拉右缘 = 搜索按钮左缘。
          ── 怎么同时做到（关键是**下拉与「类型」之间不留空隙**）────────
            类型卡（整宽 390）: [13 ──── 下拉 ──── 324][324 ─ 类型 ─ 389]
            搜索卡（整宽 390）: [13 ── 输入框 ── 280][280 重置 324][324 搜索 389]
                                              ↑            ↑          ↑
                                    下拉右缘=按钮左缘   两卡右缘=按钮右缘
            · 「类型」65px 且 `margin-left:auto` → 贴右缘，右缘 389 = 按钮右缘 ✓
            · 下拉吃满剩下的（`flex:1`），右缘自然落在 324 = 按钮左缘 ✓
            · **gap 必须是 0** —— 有 gap 的话下拉右缘会往左缩，两条线就分家了。
              ⚠️ 我前两版就是在这儿栽的：先写 gap 12 + chip 54，又写 gap 13 + chip 40，
                 结果 chip 只有 40px，和 65px 的按钮**大小不一样**（老板一眼就看出来了）。
                 其实根本不需要 gap —— 下拉和「类型」本来就该是紧挨着的两格。 */
    .hfpan-cat__searchtype {
        gap: 0;
    }

    .hfpan-cat__skind {
        /* 吃满「类型」卡片左边的全部空间 → 右缘自然落在 324
           （= 搜索卡右缘 390 − 边框 1 − 按钮 65 = 搜索按钮左缘） */
        flex: 1 1 auto;
        min-width: 0;
        margin-right: 0;
    }

    /* ④ 「类型」两字**也做成一张卡片**（老板要求：「类型这两个字也用卡片进行展示」）
          ── 宽度 = **和「搜索」按钮逐像素同宽**（老板要求）─────────────
             「你没发现类型文字和搜索按钮大小不一样吗」——
             上一版我为了对齐把它做成 40px（按钮 65px），两块大小不一，看着就是歪的。
             → 现在直接吃同一个变量 `--hfpan-sgo-w`，**永远同宽**。
             宽度对了，下拉右缘自然也落在按钮左缘上（见上面第 ③ 条的推导）。 */
    .hfpan-cat__searchlbl {
        flex: none;
        width: var(--hfpan-sgo-w, 65px);
        /* ⚠️ border-box：`.hfpan-cat__searchchip` 是 border-box，
           这里若用默认的 content-box，标签盒会比 chip 窄 2px（边框加在 100% 外）*/
        box-sizing: border-box;
        /* 贴右缘：靠 auto 边距推到最右（前提是**旁边的下拉不增长**，见上） */
        margin-left: auto;
        color: var(--hfpan-ink-2);
        font-size: 13px;
    }

    .hfpan-cat__searchchip {
        display: flex;
        align-items: center;
        justify-content: center;
        width: 100%;
        min-height: 42px;
        /* ⚠️ 必须是 border-box —— 否则 1px 边框会加在 100% 之外，
           chip 比 `.hfpan-cat__searchlbl` 宽 2px，把右缘顶出去（第一版实测 67 vs 65） */
        box-sizing: border-box;
        /* 和类型下拉**同一档观感**（同圆角、同底色）——
           老板要"用卡片展示"，那就得是卡片，不是裸字 */
        background: var(--hfpan-surface-2);
        border: 1px solid var(--hfpan-line);
        border-radius: 4px;
    }

    /* ④ 搜索卡：图标 + 输入框 + 重置 + 搜索，**一张卡**装齐 */
    .hfpan-cat__searchkw {
        background: var(--hfpan-surface);
        border: 1px solid var(--hfpan-line);
        border-radius: var(--hfpan-radius-card);
        box-shadow: var(--hfpan-shadow);
        /* ⚠️ 卡内子元素紧挨着（不留 flex gap）—— 否则输入框与重置之间裂一道缝 */
        gap: 0;
        padding: 0 0 0 12px;
    }

    /* ★ 上下节奏（老板要求「看上下是否协调」）────────────────────────────
       搜索区总高 128（类型卡 68 + 间距 10 + 搜索卡 50），
       而它下面那行「目录搜索 / 文件搜索」原来只隔 **12px** ——
       比两张卡之间的 10px 才多 2px，看着像"第三张卡粘在一起"。
       → 拉到 **14px**，和卡内 13px 的间距同一档，三段的呼吸感就一致了。 */
    .hfpan-cat__search {
        margin-bottom: 14px;
    }

    /* ⚠️★ 卡内 gap 归零之后，间距由图标和输入框自己带（0.14.32 起**已在基础样式里**，
       见 `.hfpan-cat__searchkw .hfpan-cat__searchicon` / `.hfpan-cat__skw`）——
       这里不再重复写，免得两处漂移。
       ⚠️ 也别改回用 `gap`：那会连"重置 ↔ 搜索"之间也裂开一道缝
       （老板截图就是问那段多出来的白）。 */

    /* 重置：从"整条竖线"改成卡内的**图标按钮**（不再横穿卡片） */
    .hfpan-cat__search .hfpan-cat__sreset {
        width: 44px;
        min-height: 48px;
        border-right: 0;
        border-radius: 0;
    }

    /* 搜索：卡的右端收口 —— ⚠️ 0.14.31 这条**已提到基础样式**（桌面端同样要），
       这里留一行说明，别再重复写一遍（重复写容易两处漂移）。 */

    /* ══════════════════════════════════════════════════════════════════════
       ★★ 0.14.56：**把电脑端搜索框的样式同步到手机**（老板要求）
       ── 老板原话 ────────────────────────────────────────────────────────────
         「电脑的搜索框样式同步到手机的样式上」。
       ── 同步的是哪几样（= 0.14.52 在 ≥641px 上做的那一套）──────────────────
         ① 输入框**自己画一个框**：`1px solid var(--hfpan-blue-line)` + 4px 圆角 +
            同样 **34px 高**。
            改前手机上它是"裸"的（`border:0` + 透明底）—— 跟电脑端 0.14.52
            改之前**一模一样**，也就是老板当时说的「**搜索的框没有表现出来**」；
         ② 放大镜 15 → **13px**；
         ③ 卡片**留白**：`padding: 6px 8px` + `gap: 6px`（原来只有左内边距 12px，
            上下是 0 → 按钮顶满卡片高度，没有呼吸感）；
         ④ 重置 / 搜索按钮**圆角 4px** —— 它们原来贴卡片右缘，才需要
            "只圆右边两角"（0.14.31）；现在卡片有了内边距、按钮不再贴边，
            四个角都圆才自然（和电脑端同一条理由）。
       ── ⚠️ 故意**没同步**的一样：按钮高度 ──────────────────────────────────
         电脑端是 32px，手机端**保持 48px**（`min-height`）——
         那是 0.13.x 定的"**手指点得准**"的尺寸，缩到 32px 会难点 ✗
         （留白 / 圆角 / 框都同步了，所以观感是**同一套**，只是触控目标更大。）
       ── ⚠️ 两条别踩 ────────────────────────────────────────────────────────
         · **别把这段挪进 `@media (min-width: 641px)`** —— 那就成了电脑端那条；
         · 输入框与重置之间的间距**不用重写** —— 基础样式里已经有
           `.hfpan-cat__searchkw .hfpan-cat__skw { margin-right: 12px }`，
           电脑端吃的也是它（改这里会让两端漂移）。
       ══════════════════════════════════════════════════════════════════════ */
    /* ⚠️⚠️★ 0.14.57：选择器**必须写成两段** `.hfpan-cat__searchkw .hfpan-cat__skw` ──
       单段 `.hfpan-cat__skw` 是 (0,1,0)，**输给**基础样式里那条
       `.hfpan-cat__searchkw .hfpan-cat__skw { margin-right: 12px }`（(0,2,0)）
       → 我第一版就是单段，实测"留白"还是 18px（`_verify_01456.cjs` 量出来的）。
       ⚠️ **这是同一个坑的第三次**（前两次：放大镜被 `.btnico` 盖、重置按钮被基础样式盖）——
          以后在这个文件里改**任何已有元素**的样式，先看一眼有没有更靠后/更高权重的规则。 */
    .hfpan-cat__searchkw .hfpan-cat__skw {
        border: 1px solid var(--hfpan-blue-line);
        border-radius: 4px;
        background: var(--hfpan-surface);
        padding: 6px 10px;
        /* ★★ 0.14.57：**手机上把框撑到和这一排一样高（48px）**（老板要求）──
           ── 老板原话：「这框太小了 而且和右边的垃圾箱图标还有留白 调整一下」。
           ── 为什么手机上不是 34px ────────────────────────────────────────────
             电脑端 34px 是配它那排 32px 按钮的；而**手机这排按钮是 48px**
             （手指点得准），框却只有 34px → 比旁边矮一截，看着**明显偏小** ✗
             → 手机上给它 48px，和「重置 / 搜索」齐平，整排高度一致。
           ⚠️ 顺带的好处：48px 也是"手指点得进去"的高度（Apple 建议 ≥44px），
              原来 34px 的输入框点起来偏小。
           ⚠️ 电脑端**保持 34px 不动** —— 那是 0.14.52 老板认可的那套
              （"背景要做一些留白"），别一起改了。 */
        min-height: 48px;
        /* ★★ 0.14.57：**把框右边的留白缩掉**（老板要求同上）───────────────
           ── 改前为什么空那么多 ──────────────────────────────────────────────
             基础样式里有 `.hfpan-cat__searchkw .hfpan-cat__skw { margin-right: 12px }`
             （0.14.32 定的：那会儿框还是"裸"的，靠外边距跟重置拉开距离），
             再加上卡片的 `gap: 6px` → 框到垃圾桶之间**一共 18px** ✗
           ── 现在 ────────────────────────────────────────────────────────────
             框自己有边框了，"靠外边距拉开"就不需要了 → 归零，
             只留卡片那 6px 的 flex 缝（够分清是两个东西，又不空）✓
           ⚠️ 只改手机：电脑端那条 12px 是它那套观感的一部分，别一起动。 */
        margin-right: 0;
    }

    .hfpan-cat__searchkw .hfpan-cat__searchicon {
        width: 13px;
        height: 13px;
    }

    .hfpan-cat__searchkw {
        padding: 6px 8px;
        gap: 6px;
    }

    .hfpan-cat__search .hfpan-cat__sreset,
    .hfpan-cat__sgo {
        border-radius: 4px;
    }

    .hfpan-cat__search .hfpan-cat__sreset {
        padding: 0 10px;
        width: auto;
        min-width: 44px;
    }

    .hfpan-cat__sgo {
        padding: 0 16px;
    }
}

/* ══ ★ 0.13.57：**触屏设备**（不限宽度）也要删掉「滚轮上下翻页」══════════════
   手机在 ≤640px 那条里已经隐藏了；这条管的是**触屏平板**（641~860px）——
   它们同样是手指操作，没有滚轮。
   ⚠️ 用 `hover: none` / `pointer: coarse` 判"触屏"，比写死宽度更准
      （窄窗口的桌面浏览器仍然看得到提示，那是对的）。 */
@media (hover: none), (pointer: coarse) {
    .hfpan-cat__toolhint { display: none; }
}
/* ══ ★ 0.13.57：预览区那句占位提示 —— **桌面 / 手机各一句** ═══════════════
   桌面上左右分栏，列表在**左边**；手机上（≤860px 起就是上下堆叠）列表在**上面**，
   再写「在左边点一个文件」就是**错的**（老板要删的"无意义提示"里就有这类）。
   ⚠️ 默认显示桌面那句，手机那句用媒体查询切 —— 别用 JS 改文案（没必要）。 */
.hfpan-cat__tipmob { display: none; }

@media (max-width: 860px) {
    .hfpan-cat__tipdesk { display: none; }
    .hfpan-cat__tipmob { display: inline; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.13.66：手机端 A~Z 字母栏 —— **钉在屏幕最左侧 + 模糊背景 + 滑动放大**
   ══════════════════════════════════════════════════════════════════════════
   ── 老板原话 ────────────────────────────────────────────────────────────
     「客户说不是要上下滚动 手机版是**固定在那个地方** 然后手指按上去
       上下滑动之中或者某处会**放大这个字母**
       我想了一下逻辑 滑动到最后的那一个字母**然后再去加载文件**」
     「手机版的话把字母**镶嵌在屏幕左侧** 点击品牌之后展开
       然后做一个**模糊或者半透明背景** 来实现刚才我们说的那个效果」
     「**必须松手才加载**（滑动中绝不发请求）」
   ── 三条落地 ────────────────────────────────────────────────────────────
     ① **钉在视口最左侧**（不是面板里）→ `.is-docked` + `position: fixed`；
        ⚠️ 必须由 JS 把字母栏**移到 `<body>`** —— 左栏抽屉带 `transform`，
           而 `transform` 会把 `position: fixed` 的包含块变成它自己，
           钉不到屏幕上（同 `.hfpan-cat__bdd` / `__fontdd` 的理由）。
     ② **26 个字母自适应铺满**（`flex:1 1 0` + 容器 `overflow:hidden`）→
        **永远不滚**（这条取代 0.13.48/0.13.56 那套"藏滚动条"的做法）。
     ③ 手指压住的字母 **`scale(1.9)` 放大** + 旁边一个**大字母气泡**跟着手指；
        松手才 `onPickLetter()`（滑动过程中一个请求都不发）。
   ⚠️ 只影响 ≤860px；桌面字母栏仍在面板里、仍按字号走。
   ══════════════════════════════════════════════════════════════════════════ */
/* ⚠️★ 0.13.71：**桌面与手机拆成两套**（老板要求）────────────────────────
   老板原话：「电脑端的品牌字母你放在**目录面板左边**不就好了 固定在面板目录左边
             点击品牌会展开 再点就收起 **不用和手机端的逻辑一样**」。
   ── 背景（0.13.67 的 bug）──────────────────────────────────────
     字母栏在左栏内部，左栏一收（`flex:0 0 0; max-width:0; overflow:hidden`）
     就被裁成 0 宽 → 看不见也点不到。当时我把它钉到了**屏幕**最左侧 ——
     桌面观感不对（跑到浏览器窗口边上、压住主题头部）。
   ── 现在的口径 ────────────────────────────────────────────────
     · **桌面**：钉在**插件容器**最左侧（`position:absolute` 相对 `.body`），
       观感就是原来那条窄栏；点击「品牌」展开、再点收起。
     · **手机**：仍是"钉屏幕最左侧 + 半透明模糊底 + 26 字母自适应 +
       按住滑动放大 + 松手才加载"那一套（见下面 @media 里）。
   ⚠️ 定位上下文：`.hfpan-cat__body` 必须有 `position: relative`，
      否则桌面的 absolute 会挂到更外层去。 */
.hfpan-cat__body { position: relative; }

@media (min-width: 861px) {
    /* 桌面：钉在**面板左边**（插件容器最左侧），就是原来那条窄栏 */
    .hfpan-cat__azrail.is-docked {
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        width: 22px;
        z-index: 5;
    }
}

@media (max-width: 860px) {
    /* 手机：钉在**屏幕**最左侧（fixed）+ 半透明模糊底 */
    .hfpan-cat__azrail.is-docked {
        position: fixed;
        left: 0;
        top: 0;
        bottom: 0;
        width: 34px;
        z-index: 9996;
        /* 半透明 + 自身也糊一点，底下内容若隐若现 */
        background: rgba(255, 255, 255, .72);
        -webkit-backdrop-filter: blur(10px);
        backdrop-filter: blur(10px);
        border-right: 1px solid rgba(0, 0, 0, .06);
        box-shadow: 2px 0 18px rgba(0, 0, 0, .10);
        /* 手指在字母栏上滑动时**不要让页面跟着滚** */
        touch-action: none;
    }

    /* ② 26 个字母自适应铺满 —— 永远不滚 */
    .hfpan-cat__azrail.is-docked .hfpan-cat__azlist {
        height: 100%;
        max-height: none;
        overflow: hidden;
        justify-content: space-between;
    }

    .hfpan-cat__azrail.is-docked .hfpan-cat__azl {
        flex: 1 1 0;
        min-height: 0;
        width: 100%;
        height: auto;
        font-size: 12px;
    }

    /* ③ 手指压住的那个：放大 */
    .hfpan-cat__azrail.is-docked .hfpan-cat__azl.is-big {
        transform: scale(1.9);
        opacity: 1;
        background: var(--hfpan-blue-soft);
        box-shadow: 0 2px 12px rgba(49, 153, 248, .40);
        z-index: 3;
    }

    /* ⚠️★ 0.13.67：**整页那层模糊遮罩已删** ——
       老板原话：「首字母**只对左边那一栏**做背景处理 移除其他整个页面的模糊背景」。
       → 现在背景处理**只在字母栏自己那一条**上（见上面 `.is-docked` 的
         半透明底 + `backdrop-filter: blur(10px)`），页面其余部分**不再被糊**。
       （`.hfpan-cat__azmask` 这个类名保留一行空规则占位，方便对照历史。） */

    /* 跟着手指的大字母气泡 */
    .hfpan-cat__azbub {
        position: fixed;
        z-index: 9997;
        width: 64px;
        height: 64px;
        border-radius: 50%;
        background: var(--hfpan-blue);
        color: #fff;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 30px;
        font-weight: 800;
        box-shadow: 0 8px 26px rgba(49, 153, 248, .45);
        transform: translateY(-50%) scale(.6);
        opacity: 0;
        transition: opacity .12s, transform .12s;
        pointer-events: none;
    }

    .hfpan-cat__azbub.is-show {
        opacity: 1;
        transform: translateY(-50%) scale(1);
    }
}
/* ↑ 手机媒体查询到此收口（0.13.71 拆分时补的） */

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.13.68：视图模式（老板给的 PDF 阅读器参考图，「仿一个」）
   ══════════════════════════════════════════════════════════════════════════
   ── 参考图里那 14 项，逐条对应到我们的查看器 ──────────────────────────────
     · 演示模式        → 整块全屏 + 一次一页 + 点一下/方向键翻页
     · 转到第一页/最后 → 已有 `scrollToPage()`
     · 顺时针/逆时针旋转 → pdf.js `getViewport({rotation})` 重画（不是 CSS 转，
                           否则页面尺寸与滚动条全对不上）
     · 文本选择/手形工具 → `user-select` + 光标 + 开关"按住拖动平移"
     · 页面/垂直/水平/平铺滚动 → `.pdfscroll` 的 `flex-direction` / `wrap`
     · 单页/双页/书籍视图 → 每行几页（`fitScale` 除以每行页数）+ 只显示当前页
   ── 菜单为什么挂 body ────────────────────────────────────────────────────
     工具条祖先有 `overflow:hidden`，菜单挂原地会被裁掉（同 `.hfpan-cat__bdd` /
     `__fontdd` / `__azrail` 的理由）。所以菜单由 JS 建到 body 上、`position:fixed`。
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 工具条里那个 `»` 按钮（只放图标，跟参考图一致）────────────────────── */
.hfpan-cat__viewbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 34px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--hfpan-line);
    border-radius: 5px;
    background: var(--hfpan-surface);
    color: var(--hfpan-ink);
    cursor: pointer;
    transition: all .15s ease;
}

.hfpan-cat__viewbtn svg { width: 15px; height: 15px; display: block; }

.hfpan-cat__viewbtn:hover,
.hfpan-cat__viewbtn[aria-expanded="true"] {
    border-color: var(--hfpan-blue);
    color: var(--hfpan-blue-ink);
    background: var(--hfpan-blue-soft);
}

/* ── 弹出菜单（挂 body，fixed）──────────────────────────────────────────── */
.hfpan-cat__viewmenu {
    position: fixed;
    z-index: 9990;
    min-width: 210px;
    max-height: 70vh;
    overflow-y: auto;
    padding: 6px;
    background: var(--hfpan-surface);
    border: 1px solid var(--hfpan-line);
    border-radius: 8px;
    box-shadow: var(--hfpan-shadow-4);
    font-size: 13px;
    color: var(--hfpan-ink);
}

.hfpan-cat__viewmenu[hidden] { display: none; }

.hfpan-cat__viewmenu__it {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    padding: 8px 10px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
    white-space: nowrap;
}

.hfpan-cat__viewmenu__it:hover { background: var(--hfpan-surface-3); }

/* 当前生效的那一项：加粗 + 主色（跟参考图里"选中项"一个意思） */
.hfpan-cat__viewmenu__it.is-on {
    background: var(--hfpan-blue-soft);
    color: var(--hfpan-blue-ink);
    font-weight: 600;
}

.hfpan-cat__viewmenu__it i {
    flex: none;
    width: 16px;
    font-size: 14px;
    text-align: center;
    opacity: .8;
}

.hfpan-cat__viewmenu__sep {
    height: 1px;
    margin: 6px 4px;
    background: var(--hfpan-line-2);
}

/* ══ 版式：全挂在 `.hfpan-cat__pdfscroll` 的 `data-view` 上 ══════════════ */

/* 水平滚动：一行排开，左右滚 */
.hfpan-cat__pdfscroll[data-view="horizontal"] {
    flex-direction: row;
    align-items: center;
}

/* 平铺滚动：一行多页、自动换行 */
.hfpan-cat__pdfscroll[data-view="tile"] {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
}

/* 双页 / 书籍：一行两页 */
.hfpan-cat__pdfscroll[data-view="double"],
.hfpan-cat__pdfscroll[data-view="book"] {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
}

/* ⚠️ 双页模式一行放两页 —— 中间那道 14px 的 gap 会让第二页掉到下一行，
   所以把 gap 收窄（宽度是 JS 按"每行页数"算的，这里只管间距）。 */
.hfpan-cat__pdfscroll[data-view="double"],
.hfpan-cat__pdfscroll[data-view="book"],
.hfpan-cat__pdfscroll[data-view="tile"] {
    gap: 10px;
}

/* ══ ★★ 0.14.9：这三种「一行多页」的版式必须给**确定宽度** ═══════════════
   ── 老板的问题：「其他的视图格式能兼容吗」→ 一量就发现它们**根本没在换行** ──
   ── 根因 ────────────────────────────────────────────────────────────────
     基类 `.hfpan-cat__pdfscroll` 有 `width: max-content`（0.4.5 为「放大后
     左边滚不到」加的，本身是对的），可它对 **`flex-wrap: wrap`** 是致命的：
     容器按内容撑开 → 永远没有"行宽"可言 → **永不折行**。
   ── 实测（本机夹具，30 页真 PDF）──────────────────────────────────────────
     · 双页：每页 175px（占阅读器宽 45%），30 页排成**一条超长横条**、
             `canScrollX=true`、`canScrollY=false` —— 「一行两页」从来没生效过；
     · 平铺：每页 113px（占宽 29%），同上；
     · 书籍：**封面页宽 5540px**（占宽 **1428%**）—— 因为封面那条
             `flex: 0 0 100%` 在 max-content 容器里算出了个天文数字；
             电脑端更夸张（13040px）。
   ── 修法 ────────────────────────────────────────────────────────────────
     给这三种版式**确定宽度** `width: 100%` → 容器有了行宽 → 真的按行折行，
     封面那条 `flex-basis: 100%` 也变成"一行宽"（388px）而不是 5540px。
   ⚠️ `justify-content: safe center` 的 **`safe` 不能省**：
      内容比容器宽时（用户放大之后）它会退化成 `start`，
      否则 `center` 会把溢出**平分到左右两侧**，而滚动区只能从 0 开始 →
      **左边那一半永远滚不到**（0.4.5 血案，老板原话「放大之后文件的左边区域
      完全被挡死无法查看」）。不支持 `safe` 的老浏览器只是退回居中（优雅降级）。 */
.hfpan-cat__pdfscroll[data-view="tile"],
.hfpan-cat__pdfscroll[data-view="double"],
.hfpan-cat__pdfscroll[data-view="book"] {
    width: 100%;
    justify-content: safe center;
}

/* 书籍视图：**第 1 页（封面）单独一行** —— 占满整行、去掉白底与阴影，
   看起来就是"封面单独居中"（不是一块大白条）。 */
.hfpan-cat__pdfscroll[data-view="book"] .hfpan-cat__pdfpage[data-page="1"] {
    flex: 0 0 100%;
    background: transparent;
    box-shadow: none;
}

/* 单页视图：**只显示当前页** */
.hfpan-cat__pdfscroll[data-view="single"] .hfpan-cat__pdfpage:not(.is-cur) {
    display: none;
}

/* 页面滚动：一次一页、带吸附（滚动容器在 viewer 上，所以吸附也写在它身上） */
.hfpan-cat__viewer.is-snap {
    scroll-snap-type: y mandatory;
}

.hfpan-cat__viewer.is-snap .hfpan-cat__pdfpage {
    scroll-snap-align: center;
}

/* ══ 文本选择工具 / 手形工具 ══════════════════════════════════════════════
   手形（默认）：按住拖动平移（JS 的 pan 逻辑），光标 grab / grabbing。
   文本选择：允许框选文字，光标 text，**关掉拖动平移**（JS 里判 viewTool）。 */
.hfpan-cat__viewer[data-tool="text"] {
    cursor: text;
    user-select: text;
    -webkit-user-select: text;
}

.hfpan-cat__viewer[data-tool="text"] .hfpan-cat__pdfpage canvas {
    user-select: text;
}

.hfpan-cat__viewer[data-tool="pan"] {
    user-select: none;
    -webkit-user-select: none;
}

/* ══ 演示模式 ════════════════════════════════════════════════════════════
   整块铺满视口、一次一页、四周留黑底（跟阅读器的"演示/放映"一个观感）。 */
.hfpan-cat__viewer.is-demo {
    position: fixed;
    inset: 0;
    z-index: 9994;
    background: #14161a;
    padding: 0;
}

.hfpan-cat__viewer.is-demo .hfpan-cat__pdfscroll {
    min-height: 100%;
    justify-content: center;
    padding: 0;
}

.hfpan-cat__viewer.is-demo .hfpan-cat__pdfpage:not(.is-cur) {
    display: none;
}

/* 演示模式下的页码提示（右下角） */
.hfpan-cat__demohint {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 9995;
    padding: 6px 12px;
    border-radius: 999px;
    background: rgba(0, 0, 0, .55);
    color: #fff;
    font-size: 12.5px;
    pointer-events: none;
}

.hfpan-cat__demohint[hidden] { display: none; }

/* 手机上工具条按钮的点击目标（与其它工具条按钮一致） */
@media (max-width: 640px) {
    .hfpan-cat__viewbtn { width: 40px; height: 40px; }
}


/* ══════════════════════════════════════════════════════════════════════
   ★★ 0.13.81：统一用户信息 —— 说明图标 + 「权限额度说明」弹窗
   ── 老板原话 ─────────────────────────────────────────────────────────
     「在 您是 游客 右边这里加上这个 svg 小图标（仅图标）」「点击后弹窗」
     「头像和点击交互的功能保持不变」
   ── 两块 ─────────────────────────────────────────────────────────────
     ① `.hfpan-cat__qinfo`  徽章右边那个 17×17 图标按钮（**只图标、无文字**）
     ② `.hfpan-cat__qmodal` 点它弹出来的说明弹窗
        （10 秒自动关；✕ / 「知道了」/ 点背景 / Esc 也能关 —— 逻辑在 catalog.js）
   ⚠️⚠️ 弹窗是**挂 body** 的（JS 搬过去），所以它的类名**必须**同时出现在
      文件上方那三处 token 选择器串里（浅色 + 深色 + 系统深色），
      否则取不到 `--hfpan-*` → 整块透明。这是第四次踩这个坑了。
   ══════════════════════════════════════════════════════════════════════ */

/* ── ① 说明图标（贴在「您是 XX」徽章右边）────────────────────────────── */
.hfpan-cat__qinfo {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    cursor: pointer;
    line-height: 1;
    opacity: .9;
    transition: opacity .14s ease;
}

/* ⚠️ svg 自身带 202×200 的宽高属性 —— 这里必须**写死尺寸兜住**，
   否则某些主题的 `img { max-width: 100% }` 会把它按原尺寸铺开。
   ★ 0.13.83：这个图标从 `<img>` 换成了 sprite 里的 `<svg><use>`
   （不再产生 `<img>`，主题的灯箱/alt 注入就碰不到它）——
   所以选择器要**同时**认 img（历史）和 svg（现在）。 */
.hfpan-cat__qinfo img,
.hfpan-cat__qinfo svg {
    display: block;
    flex: none;
    width: 17px;
    height: 17px;
}

.hfpan-cat__qinfo:hover,
.hfpan-cat__qinfo:focus-visible {
    opacity: 1;
}

.hfpan-cat__qinfo:focus-visible {
    outline: 2px solid var(--hfpan-blue);
    outline-offset: 1px;
}

/* 游客那行只是引导登录、不是数字 → 弱化一档 */
.hfpan-cat__qrow2.is-guestline {
    color: var(--hfpan-ink-3);
}

/* ── ② 弹窗 ─────────────────────────────────────────────────────────── */
.hfpan-cat__qmodal {
    position: fixed;
    inset: 0;
    /* 压过插件自己的浮层（字号面板 9990 / 视图菜单 9997），别用 999999 那种野值 */
    z-index: 9998;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 18px;
}

.hfpan-cat__qmodal[hidden] { display: none; }

/* 半透明背景 —— 点它 = 关掉 */
.hfpan-cat__qmodal__veil {
    position: absolute;
    inset: 0;
    background: rgba(20, 22, 26, .45);
}

.hfpan-cat__qmodal__box {
    position: relative;
    width: 100%;
    max-width: 430px;
    max-height: calc(100vh - 36px);
    overflow-y: auto;
    padding: 16px 18px 14px;
    border-radius: 12px;
    background: var(--hfpan-surface);
    border: 1px solid var(--hfpan-line);
    box-shadow: var(--hfpan-shadow-4);
    color: var(--hfpan-ink);
    font-size: 13.5px;
    line-height: 1.75;
    animation: hfpan-qmodal-in .16s ease-out;
}

@keyframes hfpan-qmodal-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .hfpan-cat__qmodal__box { animation: none; }
}

.hfpan-cat__qmodal__hd {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 10px;
    padding-right: 28px;
}

.hfpan-cat__qmodal__hd b {
    font-size: 14.5px;
    font-weight: 600;
}

.hfpan-cat__qmodal__ic {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--hfpan-blue);
    color: var(--hfpan-on-blue);
    font-size: 12px;
    font-weight: 700;
    font-style: italic;
    line-height: 1;
}

/* 右上角 ✕ */
.hfpan-cat__qmodal__x {
    position: absolute;
    top: 9px;
    right: 9px;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--hfpan-ink-3);
    font-size: 17px;
    line-height: 1;
    cursor: pointer;
}

.hfpan-cat__qmodal__x:hover,
.hfpan-cat__qmodal__x:focus-visible {
    background: var(--hfpan-surface-3);
    color: var(--hfpan-ink);
}

.hfpan-cat__qmodal__lead {
    margin: 0;
}

.hfpan-cat__qmodal__list {
    margin: 10px 0 0;
    padding: 9px 11px;
    border-radius: 8px;
    background: var(--hfpan-surface-2);
    border: 1px solid var(--hfpan-line-2);
}

.hfpan-cat__qmodal__row {
    display: flex;
    align-items: baseline;
    gap: 6px;
}

.hfpan-cat__qmodal__dot {
    flex: none;
    color: var(--hfpan-ink-3);
}

/* 身份那列定宽 —— 让「游客查阅 / 普通用户 / SVIP会员」竖着对齐 */
.hfpan-cat__qmodal__who {
    flex: none;
    width: 76px;
    color: var(--hfpan-ink-2);
}

.hfpan-cat__qmodal__txt {
    min-width: 0;
}

.hfpan-cat__qmodal__ft {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--hfpan-line-2);
    font-size: 12px;
    color: var(--hfpan-ink-3);
}

.hfpan-cat__qmodal__cd {
    font-variant-numeric: tabular-nums;
}

.hfpan-cat__qmodal__ok {
    flex: none;
    padding: 4px 14px;
    border-radius: 8px;
    border: 1px solid var(--hfpan-blue-line);
    background: var(--hfpan-blue-soft);
    color: var(--hfpan-blue-ink);
    font: inherit;
    font-size: 12.5px;
    font-weight: 500;
    cursor: pointer;
}

.hfpan-cat__qmodal__ok:hover,
.hfpan-cat__qmodal__ok:focus-visible {
    background: var(--hfpan-blue);
    color: var(--hfpan-on-blue);
    border-color: var(--hfpan-blue);
}

/* ── 手机（0.13.57 起手机样式集中在文件末尾，这条也放这儿）──────────────
   ⚠️ 身份列 76px 在 320px 上会把说明文字挤成两行 → 收窄；
      图标点击目标放大到 24（WCAG 2.2 的 24×24 下限）。 */
@media (max-width: 640px) {
    .hfpan-cat__qmodal {
        padding: 12px;
        align-items: flex-end;
    }

    .hfpan-cat__qmodal__box {
        max-width: none;
        padding: 14px 15px 12px;
        font-size: 13px;
    }

    .hfpan-cat__qmodal__who { width: 64px; }

    .hfpan-cat__qinfo { width: 24px; height: 24px; }
    .hfpan-cat__qinfo img,
    .hfpan-cat__qinfo svg { width: 19px; height: 19px; }
}

/* ══════════════════════════════════════════════════════════════════════
   ★★ 0.13.82：视频在线播放
   ── 老板原话 ─────────────────────────────────────────────────────────
     「在线预览把视频格式也做支持」。
   ── 只放行浏览器原生放得出来的那几个 ──────────────────────────────────
     mp4 / m4v / webm / ogv（后端 class-stream.php 的 MIME_MAP 同一个名单）。
     mkv / avi / flv / wmv 仍然显示「该格式暂不支持在线预览」——
     浏览器原生放不出来，要服务端转码，不做。
   ══════════════════════════════════════════════════════════════════════ */

/* 视频：预览区底色换黑 —— 跟播放器连成一片，比浅灰好看（深色模式本来就是深色） */
.hfpan-cat__item.is-video .hfpan-cat__viewer {
    background: #000;
}

.hfpan-cat__video {
    /* ⚠️⚠️ `flex: none` 不能省 ────────────────────────────────────────
       `.hfpan-cat__viewer` 是**纵向 flex 容器**，子项默认 `flex-shrink: 1`
       → 会被压到容器高度（0.4.4 图片"左右拉伸"那个血案就是这么来的）。
       视频有固有宽高比，被压就变形，所以必须脱离压缩。 */
    flex: none;
    display: block;
    margin: auto;               /* 在 flex 容器里居中（同图片那套做法） */
    max-width: 100%;
    max-height: 100%;
    background: #000;
}

/* 视频用不上的两个工具条按钮 —— 隐掉，别摆着让人点了没反应：
   · 翻译：只有 PDF 有文字层（点它会弹「目前只有 PDF 支持翻译」）
   · 视图模式（»）：那 14 项全是 PDF 的排版/旋转/双页，对视频没意义 */
.hfpan-cat__item.is-video [data-hfpan-translate],
.hfpan-cat__item.is-video [data-hfpan-viewbtn] {
    display: none;
}

/* 手机：视频铺满宽度、限高，免得竖屏视频把工具条顶出屏幕 */
@media (max-width: 640px) {
    .hfpan-cat__video {
        max-height: 60vh;
    }
}

/* ══════════════════════════════════════════════════════════════════════
   ★★ 0.13.82：「文件详情」按钮 + 面板
   ── 老板原话 ─────────────────────────────────────────────────────────
     「在阅读器的字体右侧添加一个文件详情 点开之后可以查看到详细信息」
     「你的下载次数和阅读次数是这个文件被查看被下载的总次数」。
   ── 位置 ─────────────────────────────────────────────────────────────
     按钮在工具条里「A± 字号」右边；面板挂在按钮下方、贴右边缘
     （工具条是 position:relative，面板 position:absolute）。
     这个位置是老板看过预渲染稿后说「就这个位置很不错」的那个。
   ⚠️⚠️ `.hfpan-cat__detail__row` 是 `display:flex` —— **作者样式优先级高于
      UA 的 `[hidden]{display:none}`**，所以每一层用 hidden 的元素都必须
      自带一条显式隐藏规则，否则 JS 里 `el.hidden = true` **藏不住**。
      （0.13.82 的预渲染稿就栽在这上面，老板实测"弹窗关不掉"。）
   ══════════════════════════════════════════════════════════════════════ */

.hfpan-cat__detailbtn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 12px;
    border: 1px solid var(--hfpan-line);
    border-radius: 5px;
    background: var(--hfpan-surface);
    color: var(--hfpan-ink);
    font: inherit;
    font-size: 13px;
    line-height: 1.5;
    cursor: pointer;
    white-space: nowrap;
    transition: all .15s ease;
}

/* 面板开着时按钮高亮（一眼看出"这个面板是它开的"） */
.hfpan-cat__detailbtn.is-on {
    border-color: var(--hfpan-blue);
    color: var(--hfpan-blue-ink);
    background: var(--hfpan-blue-soft);
}

/* 按钮里那个小圆 i */
.hfpan-cat__detailbtn__ic {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--hfpan-blue);
    color: var(--hfpan-on-blue);
    font-size: 10px;
    font-weight: 700;
    font-style: italic;
    line-height: 1;
}

/* ── 面板 ─────────────────────────────────────────────────────────── */
.hfpan-cat__detail {
    position: absolute;
    top: calc(100% + 6px);
    right: 12px;
    z-index: 30;              /* 压过预览区内容，但低于浮层（9990+） */
    width: 252px;
    padding: 12px 14px;
    border-radius: 10px;
    background: var(--hfpan-surface);
    border: 1px solid var(--hfpan-line);
    box-shadow: var(--hfpan-shadow-4);
    color: var(--hfpan-ink);
    font-size: 13px;
    line-height: 1.5;
    text-align: left;
}

.hfpan-cat__detail[hidden] { display: none; }

.hfpan-cat__detail__hd {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin: 0 0 9px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--hfpan-line-2);
}

.hfpan-cat__detail__hd b {
    font-size: 13.5px;
    font-weight: 600;
}

.hfpan-cat__detail__x {
    flex: none;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--hfpan-ink-3);
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
}

.hfpan-cat__detail__x:hover,
.hfpan-cat__detail__x:focus-visible {
    background: var(--hfpan-surface-3);
    color: var(--hfpan-ink);
}

/* 文件名（长名字要能断行，别撑破面板） */
.hfpan-cat__detail__name {
    margin: 0 0 8px;
    font-size: 12.5px;
    color: var(--hfpan-ink-3);
    word-break: break-all;
    line-height: 1.5;
}

.hfpan-cat__detail__name[hidden] { display: none; }

.hfpan-cat__detail__tip {
    margin: 0;
    color: var(--hfpan-ink-3);
    font-size: 12.5px;
}

.hfpan-cat__detail__row {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 3px 0;
}

/* ⚠️⚠️ 这条不能省：上面是 display:flex（作者样式）→ 会盖过 UA 的 [hidden] */
.hfpan-cat__detail__row[hidden] { display: none; }

.hfpan-cat__detail__k {
    flex: none;
    width: 52px;
    color: var(--hfpan-ink-2);
}

.hfpan-cat__detail__v {
    min-width: 0;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    word-break: break-all;
}

/* 「禁止下载」—— 红字，一眼看出是"不给"而不是"0 次" */
.hfpan-cat__detail__v.is-off {
    color: var(--hfpan-mark);
    font-weight: 500;
}

/* 手机：面板铺满工具条宽度（252px 在 320px 上会顶出去） */
@media (max-width: 640px) {
    .hfpan-cat__detail {
        right: 8px;
        left: 8px;
        width: auto;
    }
}

/* ══════════════════════════════════════════════════════════════════════
   ★★ 0.13.83：按钮上的小图标（老板给的 4 个 svg）
   ── 老板原话 ─────────────────────────────────────────────────────────
     「将对应按钮的文字前面加上对应的 svg 图标」
     「如果是手机访问的话则只显示图标 不显示文字」
     「搜索按钮放在这里吧」（箭头指的是**输入框左侧那个放大镜**）
     「后面的搜索文字保持不变」
   ── 落到哪 ───────────────────────────────────────────────────────────
     · 搜索 → 输入框左侧（替掉原来的 🔍 emoji），**「搜索」按钮文字不变**
     · 翻译 / 全屏 / 下载 → 工具条按钮的**文字前面**
     · 详情 → 它本来就有个 i 圆标，手机端也跟着只留图标（口径一致）
   ── ⚠️ 颜色**保留老板给的原始值**（他说「默认的发给你的那个颜色就行」）——
      所以这里是 <img>，图标自带 fill、**不跟随主题色**。别改成 currentColor。
   ══════════════════════════════════════════════════════════════════════ */

.hfpan-cat__btnico {
    flex: none;
    display: block;
    width: 16px;
    height: 16px;
    /* ⚠️ `display:block` 是为了**脱离 inline 基线对齐** ——
       内联 svg/img 默认坐在文字基线上，看着会往下掉
       （0.13.83 预渲染稿踩过，老板实测「图标和文字没有对齐」）。
       `flex:none` 是防被按钮这个 flex 容器挤扁。 */
}

/* ── 手机端：有图标的按钮**只留图标、隐掉文字** ──────────────────────
   ⚠️⚠️ 隐掉文字 = 按钮的**可访问名也没了**（`display:none` 会从无障碍树里
      消失）→ 所以那些按钮在 PHP 里都补了 `aria-label`，别删。
   ⚠️ 按钮做成 40×40：≥40px 是项目里手机端点击目标的下限（0.13.57 定的）。 */
@media (max-width: 640px) {
    .hfpan-cat__tbtn__txt,
    .hfpan-cat__detailbtn__txt {
        display: none;
    }

    .hfpan-cat__tbtn,
    .hfpan-cat__detailbtn {
        width: 40px;
        height: 40px;
        justify-content: center;
        padding: 0;
    }
}

/* ── ★ 0.13.83：图标 sprite 容器 ───────────────────────────────────────
   `<use>` 引用的 `<symbol>` 定义在这里，每个容器只内联一份。
   ⚠️ 藏它用 `position:absolute;width:0;height:0`，**不用 `display:none`** ——
      老浏览器对 display:none 的 sprite 解析有坑；而且本项目刚栽过
      "行内 display 盖过 [hidden]"（0.13.83 预渲染稿）。
   ⚠️ `overflow:hidden` 兜住 symbol 里可能超出的绘制。 */
.hfpan-cat__icosprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
    pointer-events: none;
}

/* ══════════════════════════════════════════════════════════════════════
   ★★ 0.13.89：手机端（≤640px）改动 —— **纯 CSS 那一半**
   ── 客户 7 条里的：① 搜索方式居中 ② 字母条底色 ③ 左右顶格
                     ⑥ 工具条一行横滑 ⑦ 目录拉升 + 圆角 + 边界感
   ── 还有两条是 JS（④ 双击等级目录才输入、⑤ 选完自动弹目录列表），下一轮做
   ── 老板确认的：字母条是**浮层**；底色用**方案 ① 层级灰**
   ⚠️ 整段**只在 ≤640px 里** —— **PC 一行不改**。
   ⚠️ 追加在文件末尾：同特异性靠**顺序**覆盖，全程不用 `!important`。
   ══════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

    /* ── ① 目录搜索 / 文件搜索：**居中** + 上下间距调小 ────────────────
       ⚠️ 它原来是靠一个 `margin-left:auto` 的占位（`.hfpan-cat__soptsp`）
          撑开的，所以居中的关键是 `justify-content:center`。 */
    .hfpan-cat__searchopts {
        justify-content: center;
        padding-top: 5px;
        padding-bottom: 5px;
    }

    /* ── ⑥ 工具条：**一行 + 左右滑动**，不要两行 ──────────────────────
       ⚠️ 必须同时给子项 `flex:none` —— 否则 flex 容器会把按钮压扁。 */
    .hfpan-cat__toolbar {
        flex-wrap: nowrap;
        overflow-x: auto;
        overflow-y: hidden;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        padding: 6px 8px;
    }
    .hfpan-cat__toolbar::-webkit-scrollbar { display: none; }
    .hfpan-cat__toolbar > * { flex: none; }

    /* ── ③ 左右顶格 + ⑦ 目录往右拉升 / 圆角 / 边界感 ──────────────────
       ⚠️ 手机端左栏**本来就是抽屉**（`.hfpan-cat__body:not(.is-single)` 那条：
          absolute + width:86% + max-width:340px）—— 客户说的「浮在阅读器上面」
          就是它。这里把它**拉到几乎满宽**（右侧留 8px 缝）、
          **右上右下倒圆角**、加阴影做出"浮在上面"的边界感。 */
    .hfpan-cat__body:not(.is-single) .hfpan-cat__left {
        width: calc(100% - 8px);
        max-width: none;
        border-radius: 0 14px 14px 0;
        box-shadow: 2px 0 16px rgba(0, 0, 0, .14);
    }

    /* ── ② 字母条：**浮层 + 不透明底色**（方案 ① 层级灰）───────────────
       ⚠️ 客户确认它是**浮在文件列表上面** → 底色**必须不透明**，
          半透明会让字母和文件名叠在一起、两边都看不清。
       ⚠️ 让位边距**已经有了**（`.is-brand-on .hfpan-cat__files{padding-left:32px}`），
          这里不要重复加，加了会把文件名的可用宽度再压窄一次。
       ⚠️ 用主题变量而不是写死色值 —— 日间自动是 #f4f6f8/#1a1d21，
          夜间自动是 #37383a/#e5eef7，**两套一次搞定**，也不会和主题打架。 */
    .hfpan-cat__azrail.is-docked {
        background: var(--hfpan-surface-3);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        box-shadow: 1px 0 8px rgba(0, 0, 0, .10);
    }
    .hfpan-cat__azrail.is-docked .hfpan-cat__azl { color: var(--hfpan-ink); }
    .hfpan-cat__azrail.is-docked .hfpan-cat__azl.is-on { color: var(--hfpan-blue); }
}

/* ══════════════════════════════════════════════════════════════════════
   ★★ 0.13.90：**手机端顶格 —— 绕开子比的 `.container` 限制**
   ── 老板的问题（原话）──────────────────────────────────────────────
     「你可能做了顶格 但是子比的那个页面做了限制 只有打开了全屏无背景
       才会是顶格处理；但是如果我设置了全屏无背景 电脑的也会显示全屏很难看」
   ── 根因 ────────────────────────────────────────────────────────────
     子比把正文包在 bootstrap 风格的 **`.container`** 里
     （`zibll/css/bootstrap.css:925` 起，`max-width` 按断点 1200px 等 + 左右内边距）。
     我们的短代码**跑在这个容器里面** → 在容器内部无论怎么写，都顶不出它的边。
   ── 解法：**整块「反边距」拉出去**（经典 full-bleed），不动主题设置 ────────
     `margin-left/right: calc(50% - 50vw)`
     原理：50% 是「容器内容宽度的一半」，50vw 是「视口宽度的一半」，
     两者相减正好把这一块**从容器里拽到视口两端**。
     ── 为什么不用「全屏无背景」────────────────────────────────────────
       · 那是**页面级**开关 → 电脑端也跟着全屏，老板说难看 ✗
       · 它还会影响**这个页面的所有元素**（标题、面包屑…），不只是我们这块 ✗
     ── 为什么不用 `:has()` 改 `.container` ─────────────────────────────
       `:has()` 要 2023+ 的浏览器；而且**依赖"容器类名就叫 .container"**这个假设。
       反边距**不依赖主题结构**，主题换皮也照样生效 ✓
   ⚠️ 只在 ≤640px 里 —— **电脑端一行不改**（老板要的正是这个）。
   ⚠️ `max-width:100vw` 兜一下：个别安卓浏览器 `100vw` 会比可视区略宽，
      不加会出现一点点横向滚动。
   ══════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

    /* ⚠️⚠️★ 0.13.99：**只留反边距，不要 `max-width:100vw` / `width:auto`** ──
       ── 老板报的：「手机页面访问滑动不了 pdf 文件」────────────────────
         我 0.13.90 为了"防横向滚动"多加了这两行，结果**正好造成横向滚动**：
         手机浏览器的 `100vw` **不等于可视宽度**（地址栏收起/展开时会变），
         `max-width: 100vw` 会让这一块**比屏幕宽几个像素** →
         页面出现横向滚动 → **在 PDF 上竖着滑，手势被横向滚动吃掉** →
         表现就是"滑动不了 PDF" ✗
       ── 标准写法就是只有反边距 ────────────────────────────────────────
         `50%` 是容器内容宽度的一半、`50vw` 是视口宽度的一半，
         相减正好贴到视口两端；**宽度自然就等于视口，不会越界** ✓
         多加 max-width/width 反而引入 `vw` 的误差 ✗
       ⚠️ 教训：`vw` 单位在移动端**不可信**（地址栏、滚动条都会让它和可视宽度不等）。
          能用 `%` + 负边距解决的地方，别掺 `vw` 的宽度约束。 */
    /* ⚠️⚠️★ 0.14.0：**不再用「负边距硬拉」，改成去掉容器的限制** ──────────
       ── 老板报的：「手机页面访问滑动不了 pdf 文件」（0.13.99 没修好）──────
         0.13.90 我用的是经典反边距 `margin-left: calc(50% - 50vw)`。
         它**只有在父容器正好居中时**才刚好贴到视口两端 ✓；
         只要中间多一层带内边距的包裹、或父容器不是居中的，
         这一块就会**往一边越界** ✗ → **横向溢出** ✗ →
         **在 PDF 上竖着滑，手势被横向滚动吃掉** ✗
         （0.13.99 我只去掉了 `max-width:100vw`，那只是帮凶，**主犯是负边距**。）
       ── 换成「把子比容器的限制去掉」──────────────────────────────────
         `.container:has(.hfpan-cat)` —— 只作用于**含本插件的那张页面**：
         去掉 `max-width` 和左右内边距 → 内容自然贴到视口两端 ✓
         **完全不产生溢出**（我们没动自己的宽度）✓
       ── 为什么可以接受 `:has()` ────────────────────────────────────
         它要 2023+ 的浏览器（Chrome 105 / Safari 15.4 / Firefox 121）。
         不支持的浏览器**只是不顶格**（优雅降级，不会坏）✓
         而反边距那种做法的失败模式是**页面横向溢出**（比不顶格严重得多）✗
         → 宁可"老浏览器不顶格"，也不要"所有浏览器都可能横向溢出"。
       ⚠️ 断点用 860px，和抽屉布局一致（0.13.96 那次教训：断点别写歪）。 */
    .container:has(.hfpan-cat),
    .container:has([data-hfpan-cat]) {
        max-width: none;
        padding-left: 0;
        padding-right: 0;
    }
}

/* ══════════════════════════════════════════════════════════════════════
   ★★ 0.13.91：手机端「目录搜索 / 文件搜索」那一行**再压矮**
   ── 客户反馈：「目录搜索和文件搜索那卡片的上下间距太长了 需要做一下缩短」
   ── 根因（上一轮没找到）────────────────────────────────────────────
     我 0.13.89 只把 padding 从 10px 收到 5px —— 但**真凶不是 padding**，是
       `.hfpan-cat__sopt { min-height: 40px }`（0.13.57 那条"点击目标 ≥40px"）
     → 那一行至少还是 40 + 5 + 5 = **50px 高**，padding 收得再小也没用。
   ── 修法 ────────────────────────────────────────────────────────────
     把这两个**单选框标签**的最小高度收到 28px（WCAG 2.5.8 的下限是 24×24，
     28 仍在安全线内；而且**整个 label 都可点**，实际可点面积比数字大），
     padding 再收到 2px。整行 50px → **32px**（矮了约 36%）。
   ⚠️ 只压这一行 —— **工具条那些按钮的 40px 不动**（那是 0.13.57 定的真·点击目标，
      按钮是独立小方块，误触代价高；这两个单选标签不一样）。
   ⚠️ 只在 ≤640px 里，**电脑端不改**。
   ══════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

    .hfpan-cat__searchopts {
        padding-top: 2px;
        padding-bottom: 2px;
        gap: 2px 22px;
    }

    .hfpan-cat__sopt {
        min-height: 28px;      /* ← 40px 是这一行"太长"的真凶 */
        font-size: 13.5px;
    }
}

/* ══════════════════════════════════════════════════════════════════════
   ★★ 0.13.92：手机端「目录搜索 / 文件搜索」**垂直居中**
   ── 老板反馈：「这个俩文字和选择有点感觉偏上了 做下居中处理」
   ── 为什么会偏上（光有 align-items:center 治不了）────────────────────
     这一行本来就是 `align-items:center`，但**光有它不够**：
       · 主题继承下来的 `line-height` 会把**行盒**撑得比文字本身高，
         文字就贴在行盒**顶部** → 看着偏上；
       · 而且这一行**会换行**（右边那句提示是 `flex:1 1 100%`，自己占一行），
         换行后由 `align-content` 决定各行怎么排 —— 它默认 `stretch`，
         不是居中。
   ── 修法 ────────────────────────────────────────────────────────────
     ① 把行高收回来（`1.2`）—— 行盒不再虚高，文字自然落回中线；
     ② `align-items:center` + `align-content:center` —— 换行前后都居中；
     ③ 单选框自己 `vertical-align:middle`，别让它跟着文字基线跑。
   ⚠️ 只在 ≤640px 里，**电脑端不改**。
   ══════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

    .hfpan-cat__searchopts {
        align-items: center;
        align-content: center;
        line-height: 1.2;
    }

    .hfpan-cat__sopt {
        align-items: center;
        line-height: 1.2;
    }

    .hfpan-cat__sopt input {
        margin: 0;
        vertical-align: middle;
    }
}

/* ══════════════════════════════════════════════════════════════════════
   ★★ 0.13.93：手机端这一行**给定高度 + 强制居中**（第 4 次修，这次给死值）
   ── 老板反馈（选项 A）：「还是偏上」
   ── 为什么前 3 次没修好 ─────────────────────────────────────────────
     0.13.89 收 padding、0.13.91 收 min-height、0.13.92 加 align-content ——
     三条都**只改了一半**：这一行的**高度一直是"内容撑多高就多高"**，
     没有死值。于是只要外层（搜索卡片）给它多一点的可用空间，
     居中基准就会飘，"偏上"就一直在。
   ── 这次的做法 ──────────────────────────────────────────────────────
     ① 给行**一个明确的最小高度**（36px），上下 padding 归零
        → 高度确定，居中才有基准；
     ② `align-items:center` + `align-content:center`（换行前后都居中）；
     ③ label 自己 `align-self:center`、去掉它自己的 min-height
        → 别让 label 撑高整行、也别让它自己贴顶。
   ⚠️ 只在 ≤640px 里，**电脑端不改**。
   ⚠️ 如果这样还是偏上，那**偏的就不是这一行**，是外层搜索卡片的上下留白不等 ——
      那种情况我需要你在浏览器里对着这一行**右键 → 检查**，
      把它的盒模型截图给我（或者我加一条红色虚线调试边框，你截图给我看）。
   ══════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {

    .hfpan-cat__searchopts {
        min-height: 36px;
        padding-top: 0;
        padding-bottom: 0;
        align-items: center;
        align-content: center;
    }

    .hfpan-cat__sopt {
        min-height: 0;
        align-self: center;
    }
}


/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.23：手机端「层级目录及以上」整块折叠 / 下拉
   ══════════════════════════════════════════════════════════════════════════
   ── 老板要的（原话）──────────────────────────────────────────────────────
     「将手机的访问页面 将层级目录及以上的区域做一个折叠和下拉
       置顶svg用于折叠 下拉如文件名」
   ── 折的是哪三块 ─────────────────────────────────────────────────────────
     搜索栏 + 搜索模式 + 层级目录（级联）—— 正好是 `.hfpan-cat__body` 之前
     的全部内容。收起来之后，阅读器 / 目录面板拿到整屏。
   ── ⚠️ 只在手机上（≤860px）──────────────────────────────────────────────
     桌面端屏幕够大、三块本来就摆得下，不需要折叠；
     把手的规则也一并只在手机端生效（桌面端 `display:none`）。
   ── ⚠️ 为什么用 `display:none` 而不是高度过渡 ───────────────────────────
     这三块高度**不固定**（级联格数会变、搜索模式那行可有可无），
     做高度动画要现量高度，还容易和抽屉的 `transform` 打架。
     折叠是"腾地方"的动作，瞬间完成反而更跟手。
   ══════════════════════════════════════════════════════════════════════════ */

/* 桌面端：把手不出现（规则只写在手机媒体查询里，这里显式关掉防漏） */
.hfpan-cat__topfold { display: none; }

@media (max-width: 860px) {
    /* 收起状态：把三块一起收掉 */
    .hfpan-cat.is-topfold .hfpan-cat__search,
    .hfpan-cat.is-topfold .hfpan-cat__searchopts,
    .hfpan-cat.is-topfold .hfpan-cat__selects {
        display: none;
    }

    /* ══════════════════════════════════════════════════════════════════
       ★★ 0.14.31：把手**放回目录面板上方**（老板要求）════════════════════
       ── 老板原话 ──────────────────────────────────────────────────────
         「等级目录以上的收起和展开按钮放回到目录面板上方 与用户头像平齐
           然后也替换为合适的fa图标」
         「等级目录以上的收起和展开按钮做一个调整 不要太难看即可」
       ── 这一版和上一版的区别（0.14.27 → 0.14.31）────────────────────
         · 0.14.27：塞进抬头里、**绝对居中**、图标是老板给的"蓝圆+白箭头"，
           还得靠白描边把它从蓝底上"托"出来；
         · 0.14.31（现在）：**回到面板上方独立一条**、**左缘与头像对齐**、
           图标换成 Font Awesome 的 `angles-up` / `angles-down`（走 sprite，
           `fill="currentColor"` → **日间深灰、夜间浅色，自动兼容**）。
       ── 「与用户头像平齐」怎么落地的 ──────────────────────────────────
         头像的左缘在抬头里 = 面板边框 1px + 抬头内边距 12px = **13px**
         （真机量出来的，见 `_diag_topfold_align.cjs`）。
         所以这条 bar 给 `padding-left: 13px` —— 把手的左缘就正好压在头像左缘上 ✓
       ── ⚠️ 为什么不放回抬头里 ────────────────────────────────────────
         抬头是**蓝底**，把手放进去要么被背景吃掉、要么得描边"托"出来，
         两种都难看；而且老板这次明确说「放回到目录面板上方」。
       ── ⚠️ 多占的那点高度（比 0.14.27 多）────────────────────────────
         独立一条会净占约 34px。0.14.23 那版就是因此把阅读器往下顶，
         所以这条 bar 做成**紧凑胶囊**（28px 高 + 6px 下边距），
         并且**只在面板展开时出现**（收起时整条不占位，见文件末尾那条）。
       ══════════════════════════════════════════════════════════════════ */
    /* ══════════════════════════════════════════════════════════════════
       ★★ 0.14.34：把手**放回目录面板抬头里、和头像同一行**（老板澄清）════
       ── 老板原话 ──────────────────────────────────────────────────────
         「收起和展开那个按钮我不是说要**集成到目录面板上面**吗
           **和头像平齐不是竖齐**」
       ── 我上一版（0.14.31）错在哪 ─────────────────────────────────────
         我理解成"放到面板**上方**"（面板外面那一条），还把它的左缘和
         头像左缘对齐了 —— 那是**竖齐**（同一竖线、不同行）✗
         老板要的是**横齐**：同一行、就在头像旁边。
       ── 现在 ──────────────────────────────────────────────────────────
         由 JS 插在抬头里、**头像右边**（DOM：`[头像][把手] 目录面板 … [✕]`），
         抬头的 `align-items:center` 让它与头像**垂直居中、同一排** ✓
         ⚠️ 不再需要 `position:absolute`（那是 0.14.27 居中用的），
            也不再有"净占一条 34px"的问题 —— 抬头本来就在那儿。
       ── 观感 ──────────────────────────────────────────────────────────
         抬头是**蓝底白字**，所以把手做成**半透明胶囊**（和那个 ✕ 同一套）：
         `rgba(255,255,255,.18)` 底 + 白图标白字。
         ⚠️ 别用"白底 + 蓝图标"—— 那在蓝底上像贴了块白纸。
       ══════════════════════════════════════════════════════════════════ */
    .hfpan-cat__topfold {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 5px;
        flex: none;
        /* ★★ 0.14.35：**由把手吃掉空白**（老板要求「放到文字和 ✕ 之间、靠 ✕」）——
           原来空白是被 ✕ 的 `margin-left:auto` 吃掉的，把手插在 ✕ 前面也只会
           贴在标题后面。现在改由把手吃，它就落到 ✕ 左边（抬头 gap:9px 留出间距）。 */
        margin: 0 0 0 auto;
        min-height: 30px;
        padding: 4px 10px;
        border: 0;
        border-radius: 999px;
        background: rgba(255, 255, 255, .18);
        color: var(--hfpan-head-fg);
        font: inherit;
        font-size: 12px;
        line-height: 1.2;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
    }

    /* ★★ 0.14.35：把手存在时，把 ✕ 的 `margin-left:auto` 收掉 ——
       两个 auto 会**平分**空白，把手就被推到"正中间"而不是"靠 ✕"。
       ⚠️ 用相邻兄弟选择器（`+`）：只在把手真存在时生效，
          桌面端（把手 `display:none`）与"没有 ✕"的场景都不受影响。 */
    .hfpan-cat__topfold + .hfpan-cat__dirclose {
        margin-left: 0;
    }

    /* 图标：Font Awesome 的 angles-up / angles-down（走 sprite，颜色跟主题走） */
    .hfpan-cat__topfold__ic {
        flex: none;
        display: block;
        width: 14px;
        height: 14px;
        /* ⚠️ sprite 里的 path 写的是 `fill="currentColor"` ——
           内联 svg 能正常继承 `color`（这正是从 `<img>` 换成 `<use>` 的原因：
           `<img>` 取不到外层 color，夜里图标还是黑的）。
           这里 `inherit` = 抬头的白字色（蓝底上看得清）。 */
        color: inherit;
        pointer-events: none;
    }

    .hfpan-cat__topfold__txt {
        white-space: nowrap;
    }

    .hfpan-cat__topfold:active {
        background: rgba(255, 255, 255, .34);
    }

    /* ⚠️★ **面板收起时不显示**（老板要求：「只有目录面板展开之后才会显示」）——
       收起时左栏宽度为 0、整块都被裁掉，本来也看不见；
       这里显式关掉，免得将来布局一变它又"从缝里露出来"。 */
    .hfpan-cat__item.is-dirhidden .hfpan-cat__topfold { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.37：类型卡**拉伸到与「二级目录」左边对齐**（老板要求）
   ── 老板原话（附截图：红框=类型卡，红线=二级目录那一栏的左缘）──────────
     「将图中的类型选择拉伸至于二级目录左边对齐（如图）」
   ── ⚠️⚠️ 为什么写在**文件最末尾**而不是基础规则旁边 ─────────────────────
     基础规则 `.hfpan-cat__searchtype`（约第 353 行）**本身就在
     `@media (prefers-color-scheme: dark)` 块里面**（那个块从第 276 行开始）。
     第一版把 `@media (min-width: 641px)` 写在它下面 →
     **`@media` 嵌 `@media` 是无效 CSS，浏览器整块丢掉**，
     结果只在夜间模式误打误撞生效、白天完全没效果（实测踩到）。
     → 必须放在**顶层**。放末尾还能顺带压过前面所有同特异性的宽度规则。
   ── 为什么必须用 calc、不能写死宽度 ─────────────────────────────────────
     类型卡原来**按内容自适应**（实测约 230px），而级联每格是
     `calc((100% - 30px) / 4)` —— 随屏幕宽度变。
     写死宽度在任何宽度上都对不齐，实测差值：
       700px +38 / 860px +12 / 1024px −27 / 1200px −70。
   ── 公式怎么推的 ───────────────────────────────────────────────────────
     级联容器 `.hfpan-cat__selects`：内边距 14、格间距 10，每格 = (内容宽 − 30) / 4。
     第二格左缘（相对容器外框）= 14 + 格宽 + 10
       = 14 + (100% − 28 − 30) / 4 + 10
       = calc(24px + (100% − 58px) / 4)
     类型卡的包含块与级联容器**同宽**，所以把类型卡设成这个宽度即可。
     实测 700 / 860 / 1024 / 1200 四组**误差都是 0**。
   ── 边界 ───────────────────────────────────────────────────────────────
     ⚠️ 只在 ≥641px 生效 —— 手机上类型卡是整行（`width:100%`，见 ≤640px 那段）。
     ⚠️ 只对「≤4 级」的级联成立。级数 >4 时 JS 会给容器加 `.is-fluid`
        （每格改成等分），那条公式就不准了 → 下面用 `:has()` 退回按内容自适应。
     ⚠️ 桌面端**另外那几处** `.hfpan-cat__searchtype`（约 3054 / 3250 行）都在
        手机媒体查询里，不会和这段打架。
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 641px) {
    .hfpan-cat__searchtype {
        /* ⚠️⚠️ 0.14.37：**必须 border-box** ────────────────────────────────
           `width` 默认算的是**内容盒**（不含内边距与边框），而公式算出来的
           是**外框宽**。这个元素有 `padding: 0 12px` + `border-right: 1px`
           = **25px** —— 实测差值就恒定是这 25px（700/860/1024/1200 全是 +25）。
           改成 border-box 后 `width` 就是外框宽，右缘才落得准。 */
        box-sizing: border-box;
        width: calc(24px + (100% - 58px) / 4);
    }

    /* 级数 >4（`.is-fluid`，每格等分）→ 别硬套 1/4 公式，退回按内容自适应 */
    .hfpan-cat:has(.hfpan-cat__selects.is-fluid) .hfpan-cat__searchtype {
        width: auto;
    }

    /* ══ ★★ 0.14.41：类型下拉**拉伸填满卡片**（老板要求）════════════════════
       ── 老板原话（附截图：红框圈着「阅读（只阅读）」那个下拉，它右边空着一截）──
         「这里也**拉伸一下** 右边**不要留空**」
         （「也」= 跟 0.14.37 那次拉伸类型卡是同一件事，这次轮到卡里的下拉）
       ── 为什么会留空 ──────────────────────────────────────────────────────
         `.hfpan-cat__skind` 是**按内容自适应**的（0.5.4 为了长类名不被截成
         「自定义占位符（仅下…」），还带 `max-width: 260px`；
         而「分类」标签被顶到卡片右缘 → **宽屏上中间就空出一截**
         （线上实测 1200px 空 ~54px、1024px 空 22px、700px 只空 6px）。
       ── 怎么改 ────────────────────────────────────────────────────────────
         `flex: 1 1 auto` + `max-width: none` + `min-width: 0`：
         让下拉**吃满**卡片里剩下的宽度，「分类」标签照旧贴右缘 ✓
       ⚠️ `min-width: 0` **不能省** —— 留着 0.5.4 那条 `min-width: 120px` 的话，
          窄一点（700px）时卡片内容区只有 155px，下拉会被撑出去、把标签挤掉。
       ⚠️ 只写在 ≥641px：手机上这套原生下拉是 `display:none` 的
          （自绘触发条 `.hfpan-cat__kindtrig` 接管，它本来就是 `flex:1 1 auto`，
           所以手机端**本来就没这个空档**，不用管）。
       ⚠️ 长类名的好处没丢：下拉变**更宽**了，能显示的字**更多**（不是更少）。 */
    .hfpan-cat__skind {
        flex: 1 1 auto;
        max-width: none;
        min-width: 0;
    }
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.42：抬头里的「全部展开 / 全部折叠」按钮（老板要求）
   ── 老板原话 ──────────────────────────────────────────────────────────────
     「添加一个**全部展开和全部折叠**的功能按钮 **放到你觉得合适的地方**」
   ── 观感 ──────────────────────────────────────────────────────────────────
     和「收起」把手**同一套**（抬头是蓝底 → 半透明白胶囊 + 白字），
     免得抬头里冒出两种风格的按钮打架。
     ⚠️ 别改成"白底 + 蓝字" —— 在蓝底上像贴了块白纸（把手那条踩过）。
   ── ⚠️ 为什么写在这里（文件末尾的顶层）──────────────────────────────────
     抬头相关的规则有些在 `@media (prefers-color-scheme: dark)` 块里，
     新规则**必须放顶层**，否则可能被嵌进那个块、只在夜间生效
     （0.14.37 那条 `@media` 嵌 `@media` 被整块丢掉的坑）。
   ⚠️ 桌面端也显示（不是只有手机）—— 桌面端左栏同样是一棵树，同样需要。
   ══════════════════════════════════════════════════════════════════════════ */
.hfpan-cat__expandall {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin: 0;
    padding: 3px 9px;
    border: 0;
    border-radius: 999px;
    background: rgba(255, 255, 255, .18);
    color: var(--hfpan-head-fg);
    font: inherit;
    font-size: 12px;
    line-height: 1.3;
    white-space: nowrap;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.hfpan-cat__expandall i {
    font-size: 13px;
    line-height: 1;
}

.hfpan-cat__expandall:active {
    background: rgba(255, 255, 255, .34);
}

/* 「还有更多，再点一次」那一档 —— 给一点不同的底色，让人看出它变了 */
.hfpan-cat__expandall.is-more {
    background: rgba(255, 255, 255, .3);
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.43：「当前：xxx」指示条（老板要求）
   ── 老板原话 ──────────────────────────────────────────────────────────────
     「在目录面板上方（如果是品牌选择的话则在「已选：奥迪（一汽）接着选下一级」
       **下方**）添加一个**最后展开的等级目录名**」
   ── 预渲染确认过的口径（2026-09-26，他亲自选的）──────────────────────────
     · 放哪：**紧贴列表上方**（DOM 上排在 `.hfpan-cat__listcap` **后面** →
       品牌模式下自然落在「已选」下面 ✓ 正是他要的位置）；
     · 显示什么：**只最深那一层**的名字，前缀「当前：」（他说"其他不换"）。
   ── 观感 ──────────────────────────────────────────────────────────────────
     一条淡蓝的信息条，和「已选」小标题同一族但**能区分开**
     （小标题是 `--hfpan-surface-2` 灰蓝，这条用更淡的蓝 + 小方块图标）。
   ⚠️⚠️ **`[hidden]` 那条不能省** —— 本规则写了 `display:flex`，
      它会**盖过浏览器默认的 `[hidden]{display:none}`**（类选择器特异性更高），
      结果"隐藏"的指示条照样显示。渲染稿里就踩到过：
      **两条指示条同时出现**，而只查 `el.hidden` 属性的断言**假通过**了，
      是截图才发现的。所以判可见一律用 `getComputedStyle().display`。
   ⚠️ 名字长 → 省略号截断（面板窄），`title` 里有完整名字可悬停看。
   ══════════════════════════════════════════════════════════════════════════ */
.hfpan-cat__where {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 7px 12px;
    background: var(--hfpan-blue-soft);
    border-bottom: 1px solid var(--hfpan-line);
    color: var(--hfpan-ink-2);
    font-size: 12.5px;
    line-height: 1.45;
}

/* ⚠️ 必须紧跟上面那条（原因见注释） */
.hfpan-cat__where[hidden] {
    display: none;
}

/* ★★ 0.14.53：前面那个图标从「蓝方块」换成 **FA4 的 `fa-map-marker`**（老板要求）
   ── 老板原话 ──────────────────────────────────────────────────────────────
     「面板目录下方对应的最后一个等级目录文件夹显示的图标改为 fa 图标
       代码为 **fa-map-marker**」，并给了样子：`[图标] 当前：1.欧系`。
   ── 改前是什么 ────────────────────────────────────────────────────────────
     一个 `<span>` 靠 `background` + `border-radius` 画出来的 **13×13 蓝方块** ——
     跟"这里显示的是**位置**"没有半点关系。
   ── 改法 ──────────────────────────────────────────────────────────────────
     那个元素改成 `<i class="hfpan-cat__where__ico fa fa-map-marker">`（见 catalog.js
     的 `paintWhere()`），这里只负责**尺寸与颜色**：
       · 宽度留 13px 让"图标 + 文字"两行的左缘对齐（跟原来一样，不改观感节奏）；
       · `text-align: center` —— FA4 的 `<i>` 是行内元素，不居中会跟文字差半像素；
       · 颜色走 `--hfpan-blue`（**不能写死**：写死深色模式不生效，check.php 有断言盯着）。
   ⚠️ 不要写 `font-size` 之外的尺寸（width/height 对字体图标没有意义，
      真正的字身大小由 font-size 决定）。 */
.hfpan-cat__where__ico {
    flex: none;
    width: 13px;
    text-align: center;
    /* ★★ 0.14.55：老板要求**固定粉红**（不跟主色走）——
       原来这里是 `var(--hfpan-blue)`，后台一改全局颜色它就跟着变，
       而老板要的是"这个图标永远是粉的"。见 token 块里 `--hfpan-pin` 的注释。
       ⚠️ 仍然走**变量**（不是直接写 `#f04494`）：这样改色只需动 token 一处，
          也满足 check.php 那条"颜色不许写死在业务规则里"的断言。 */
    color: var(--hfpan-pin);
    font-size: 13px;
    line-height: 1;
}

.hfpan-cat__where__txt {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.hfpan-cat__where__txt b {
    color: var(--hfpan-blue-ink);
    font-weight: 600;
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.48：**只保留等级目录那套输入框的蓝底**（老板要求）
   ── 老板原话 ──────────────────────────────────────────────────────────────
     「搜索相关的蓝色背景回调 恢复上一版的样子 添加的搜索路径不变
      **仅撤销搜索栏的蓝色背景 等级目录的蓝色背景保留**」
   ── 演变 ──────────────────────────────────────────────────────────────────
     · 0.14.46：主搜索框 `.hfpan-cat__skw` **和** 等级目录 `.hfpan-cat__lbox`
       **都**加了蓝底（老板当时说"所有的搜索地方"）；
     · 0.14.48（现在）：**只撤销主搜索框那条**，等级目录那条**保留** ✓
       → 主搜索框回到上一版的样子（聚焦只有蓝描边 + 蓝色外圈，**底色不变**）。
   ── 覆盖范围（现在只有这一处）──────────────────────────────────────────
     · `.hfpan-cat__lbox` —— 等级目录那套"可输入下拉"的输入框（能打字搜）。
   ── ⚠️ 色值必须走变量 ─────────────────────────────────────────────────────
     `--hfpan-blue-soft`（日间 `#eaf4fe` / 夜间 `#16304a`）——
     写死颜色**深色模式就不生效**，`check.php` 有断言盯着。
   ══════════════════════════════════════════════════════════════════════════ */
.hfpan-cat__lbox:focus {
    background: var(--hfpan-blue-soft);
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.46：搜索结果里那行"在哪个目录"（老板要求）
   ── 老板原话 ──────────────────────────────────────────────────────────────
     「搜索文件功能时 展示出来的文件需要**显示对应路径**」
   ── 内容规则（在 `catalog.js` 的 `shortDir()` 里）────────────────────────
     ≤3 段 → 全显示；>3 段 → 只显示**前 3 段** + `…`；完整路径在 `title` 里。
   ── 观感 ──────────────────────────────────────────────────────────────────
     比文件名**小一号、淡一档**（`--hfpan-ink-3`），不抢文件名的主角位置；
     太长就省略号截断（面板窄）。
   ══════════════════════════════════════════════════════════════════════════ */
.hfpan-cat__hitpath {
    margin-top: 2px;
    color: var(--hfpan-ink-3);
    font-size: 12px;
    line-height: 1.4;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.52：搜索框自己要有框 + 图标/按钮缩小 + 卡片留白（老板要求）
   ── 老板原话 ──────────────────────────────────────────────────────────────
     「**搜索的框没有表现出来** 然后对应的**图标和搜索按钮也进行缩小一下**
      （**背景要做一些留白**）」
   ── 改前实测（线上 1280px，量出来的不是猜的）────────────────────────────
     · 搜索卡片 `.hfpan-cat__searchkw`：918×46，**上下内边距 0** ✗
       → 「搜索」按钮 78×**44** 顶满卡片高度、贴着卡片上下边，**没有留白** ✗
     · 搜索框 `.hfpan-cat__skw`：742×44，**border:0 + 透明底** ✗
       → 它就是"裸"在卡片里的一块，**看不出是个输入框** ✗（老板说的就是这条）
     · 放大镜 `.hfpan-cat__searchicon`：15×15
   ── 改法（只动 ≥641px；手机端有它自己的一套触控尺寸，别动）─────────────
     ① **卡片留白**：`padding: 6px 8px` + `gap: 6px`（原来上下是 0 ✗）
     ② **搜索框画框**：跟左边那个「阅读（只阅读）」下拉**同一套** ——
        `1px solid var(--hfpan-blue-line)` + `4px` 圆角 + 同样的 34px 高 ✓
        （老板原话是「样式和上方的分类类似」，这样两块才像一套）
     ③ **放大镜 15 → 13px**
     ④ **重置 / 搜索按钮 44 → 32px 高**，`align-self: center` 让它**垂直居中**，
        四周留出空白 ✓；「搜索」按钮的**右侧圆角也去掉了** ——
        它原来贴卡片右缘才需要"只圆右边两角"（0.14.31），现在有留白、不贴边了，
        四个角都圆才自然 ✓
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 641px) {
    /* ① 卡片留白 */
    .hfpan-cat__searchkw {
        padding: 6px 8px;
        gap: 6px;
    }

    /* ② 搜索框自己画一个框（跟「阅读（只阅读）」下拉同一套） */
    .hfpan-cat__skw {
        border: 1px solid var(--hfpan-blue-line);
        border-radius: 4px;
        background: var(--hfpan-surface);
        padding: 6px 10px;
        min-height: 34px;
    }

    /* ③ 放大镜小一点
       ⚠️★ 0.14.56：选择器**必须带 `.hfpan-cat__searchkw` 前缀**（两段 = (0,2,0)）——
          这个 `<img>` 身上还挂着 `.hfpan-cat__btnico`，那条规则写在文件**更后面**
          （约 4366 行）、权重相同 (0,1,0) → **后写的赢**，实测电脑端量出来是 13px
          只是因为这条在 4366 之后；手机那条原本写在 3400 附近就被盖成 16px ✗
          → 两处都改成两段选择器，以后 `.btnico` 挪到哪儿都不会再盖住。 */
    .hfpan-cat__searchkw .hfpan-cat__searchicon {
        width: 13px;
        height: 13px;
    }

    /* ④ 重置 / 搜索按钮小一点 + 垂直居中（四周就自然留白了） */
    .hfpan-cat__sreset,
    .hfpan-cat__sgo {
        min-height: 32px;
        height: 32px;
        align-self: center;
        border-radius: 4px;
    }

    /* ⚠️★ 0.14.56：这里的选择器**必须写成两段** `.hfpan-cat__search .hfpan-cat__sreset`
       —— 0.14.52 当初写的是单段 `.hfpan-cat__sreset`（(0,1,0)），
       **输给**上面基础样式里那条 `.hfpan-cat__search .hfpan-cat__sreset`（(0,2,0)，
       见约 852 行，那里写着 `padding: 0 14px` + `border-right` + `border-radius: 0`）
       → 结果 0.14.52 想做的"去掉分隔线 / 内边距缩到 10px"**一条都没生效**，
       电脑端一直还是旧的直角 + 14px + 那条竖分隔线 ✗
       （0.14.56 同步手机样式时被 `_verify_01456.cjs` 的**两端对比**量出来的。） */
    .hfpan-cat__search .hfpan-cat__sreset {
        padding: 0 10px;
        border-right: 0;           /* 搜索框自己有框了，中间那条分隔线就多余了 */
        /* ⚠️ 圆角也要写在**这条两段选择器**里 —— 上面那条 `border-radius: 4px`
           是单段 (0,1,0)，同样输给基础样式里那条 (0,2,0) 的 `border-radius: 0`
           （实测：不写这句，电脑端重置按钮就还是直角，手机端是圆的 → 两端不一致）。 */
        border-radius: 4px;
    }

    .hfpan-cat__sgo {
        padding: 0 16px;           /* 原来 24px，缩一点 */
    }
}

/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.51：电脑端也拆成两张卡 —— 分类一块背景、搜索一块背景（老板要求）
   ── 老板原话（两次，第二次才说准）──────────────────────────────────────────
     「搜索区域用卡片包裹住 样式和上方的分类类似 先做预渲染吧」
     「一个小卡片 和上面的分类风格类似 明白我的意思吗 只对搜索那一栏做改动」
     →「你看那个**分类的选择框和后面的分类 后面有一个大的背景卡片**
        我也想把**搜索也做成这种效果**明白吗」
   ── 他要的到底是什么 ──────────────────────────────────────────────────────
     现在电脑端：**一整块背景**罩着「分类 + 搜索框 + 重置 + 搜索」四格 ✗
     他要：**分类后面一块背景、搜索后面另一块背景**（跟手机端一致）✓
     → 也就是把外框那块背景**下放成两块**，只动搜索那一栏，
       模式切换（`.hfpan-cat__searchopts`）和级联（`.hfpan-cat__selects`）**一个字不改** ✓
   ── ⚠️⚠️ 为什么 gap 必须是 0（不能像手机那样留 10px 缝）──────────────────
     老板之前定过两条硬要求（见本文件 0.14.37 那段）：
       ① 分类卡**右缘** = 级联**第 2 格左缘**；
       ② 分类卡**右缘** = 「搜索」按钮**左缘**。
     这两条成立的前提就是**分类卡右缘 = 搜索卡左缘（紧贴）**。
     我先试了留 10px 缝 → `.workbuddy/_verify_search_align.cjs` **9 PASS 掉到 5 PASS** ✗
     报的正是「类型卡右缘 → 搜索卡左缘 缝隙 10px ✗（不该有缝）」。
     → 所以这里 **gap: 0**：两块背景**紧贴**，靠各自的圆角 + 描边看出是两块 ✓
       （手机端是上下叠，不受这条约束，仍留 10px 缝 ✓）
   ── ⚠️ 外框为什么必须让位 ────────────────────────────────────────────────
     `.hfpan-cat__search` 自己带 `border` + `overflow: hidden` ——
     留着它就只能得到"一块大背景里两格"，做不出两块背景 ✗
     （`overflow:hidden` 还会把子元素的圆角裁成直角）
     → 外框改成 `border:0 / background:transparent / overflow:visible` ✓
   ── ⚠️ box-sizing ────────────────────────────────────────────────────────
     搜索卡**新加了一圈边框**，不写 `border-box` 的话它的**外宽会多 2px** ✗
     （0.14.37 那个宽度公式是按老尺寸推的）→ 会挤歪对齐。
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 641px) {
    /* ① 外框让位给两块背景 */
    .hfpan-cat__search {
        background: transparent;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        overflow: visible;
        /* ★★ 0.14.51：**留 10px 缝**（跟手机端一致）——
           ⚠️ 0.14.50 我先试的是 `gap: 0`（紧贴）→ 对齐保住了，
              但两块背景**紧挨着**，肉眼就是"一张卡切两格"，等于白改 ✗
           → 改成留缝：两块背景**看得出是两块** ✓
           ⚠️ 留缝会动的只有**一条**旧关系：
              「分类卡右缘 = 搜索卡左缘」（那是**手机端上下叠**时的"三根竖线"要求），
              留缝后差 10px ✗ —— 这条在**电脑端本来就不成立**（电脑端是左右并排，
              分类右缘对着的是搜索卡左缘，不是"搜索按钮左缘"）。
              真正老板要的那条「分类卡右缘 = 级联第 2 格左缘」（0.14.37）**没受影响** ✓
              （分类卡的位置和宽度都没动，见下面 `width` 那条公式）
           → `_verify_search_align.cjs` 里那条"不许有缝"的断言已按新口径改成
             **只在手机宽度查**，并注明是 0.14.51 翻的面。 */
        gap: 10px;
    }

    /* ② 分类后面那一块 */
    .hfpan-cat__searchtype {
        box-sizing: border-box;
        background: var(--hfpan-surface);
        border: 1px solid var(--hfpan-line);
        border-radius: var(--hfpan-radius-card);
        box-shadow: var(--hfpan-shadow);
    }

    /* ③ 搜索后面那一块（老板要的"搜索也做成这种效果"） */
    .hfpan-cat__searchkw {
        box-sizing: border-box;
        background: var(--hfpan-surface);
        border: 1px solid var(--hfpan-line);
        border-radius: var(--hfpan-radius-card);
        box-shadow: var(--hfpan-shadow);
        overflow: hidden;          /* 让里面的「搜索」按钮被圆角裁一下，不露直角 */
    }
}
/* ══════════════════════════════════════════════════════════════════════════
   ★★ 0.14.60：**搜索行改成和上方「分类」行一模一样的结构**（老板要求）
   ── 老板原话（附截图，上方=分类行、下方=搜索行）──────────────────────────
     「对照这两个样式 **以上方为标准对下方进行调整**
       下方的搜索框**占满整个除搜索键以外的框**
       搜索图标和垃圾桶图标**都要在搜索框里**
       框的颜色为**蓝色**（保持现在这种蓝色即可）
       然后右边**无缝连接搜索按钮**
       搜索按钮也要在右边对应位置**占满**
       上下对应的**位置要保持一致**」
   ── 改前实测（手机 390px，量的不是猜的）─────────────────────────────────
     上方「分类」行：卡 390×68（内边距 8/0/8/12）
                    蓝框（下拉）x=13 → 324（311 宽），分类 chip x=324 → 389（65×42）
                    → **蓝框吃满整张卡，只留右边一格给 chip，且无缝** ✓
     下方「搜索」行：卡 390×62（内边距 6/8/6/8）
                    输入框只有 **228 宽**（x=36→264）✗
                    🔍 在框**外面**（x=9）✗、🗑 也在框**外面**（x=270）✗
                    输入框→🗑 6px、🗑→按钮 6px（到处是缝）✗
                    搜索按钮 61 宽，右缘还内缩 **9px** ✗
   ── 改后（以上方为标准）─────────────────────────────────────────────────
     · 蓝框 = 新容器 `.hfpan-cat__skwbox`：x=13 → 324（**和上方蓝框同一位置**）
       —— 🔍 和 🗑 都在它里面 ✓
     · 搜索按钮：x=324 → 389、**65 宽**（和上方 chip 同宽同位 ✓）、高度撑满 ✓
     · 框与按钮之间 **gap 0** = 无缝 ✓
     · 框的边框沿用 `--hfpan-blue-line`（**就是现在这个蓝**，没换色）✓
   ── ⚠️⚠️ 桌面端**一个像素都不许变** ───────────────────────────────────────
     上面那条 `.hfpan-cat__skwbox { display: contents }` 让这层容器在桌面端
     **完全不参与布局**（子元素照旧直接排进搜索卡）——
     0.14.52/0.14.56 那套桌面观感与 `_verify_01456.cjs` 的实测数字必须原样通过 ✓
   ── ⚠️ 为什么写在**文件最末尾的顶层** ────────────────────────────────────
     ① `display: contents` 那条必须**在媒体查询之外**（否则只在某个模式生效）；
     ② 手机那段必须在所有手机规则**之后**（同特异性时后写的赢）——
        文件里 3944/4181/… 还有好几段 `max-width: 640px`，写中间会被它们盖掉。
     （这条与 AGENTS.md 第 16 条记的"规则要放文件末尾顶层"是同一个教训。）
   ══════════════════════════════════════════════════════════════════════════ */
.hfpan-cat__skwbox {
    /* ⚠️ 桌面端：这层容器**不存在**（子元素直接参与搜索卡的 flex 布局）——
       没有它，0.14.52 那套桌面数字（框 34px / 留白 18px …）就会变 ✗ */
    display: contents;
}

@media (max-width: 640px) {
    /* ① 搜索卡：内边距与「分类」卡**逐字相同**（8/0/8/12）+ 同高 + 无缝 */
    .hfpan-cat__searchkw {
        padding: 8px 0 8px 12px;
        gap: 0;
        /* ⚠️ 这个 50 是**内容盒**高度，不是总高（卡片没写 `box-sizing: border-box`）——
           50 + 上下内边距 16 + 上下边框 2 = **总高 68**，
           与上方「分类」卡（它吃的也是 `min-height: 50px`，实测总高 68）**逐像素相等** ✓
           ⚠️ 第一版我按 border-box 写成了 68 → 实测总高 **86**，比上方卡高出 18px ✗
              （量出来才发现 —— 这种"盒子模型算错"光看代码看不出来）。 */
        min-height: 50px;
    }

    /* ② 蓝框：包住 🔍 + 输入框 + 🗑；左圆角、**右直角**（要无缝接按钮） */
    .hfpan-cat__skwbox {
        display: flex;
        align-items: center;
        flex: 1 1 auto;
        min-width: 0;
        align-self: stretch;              /* 撑满卡片内容高度（和上方蓝框一样齐） */
        border: 1px solid var(--hfpan-blue-line);   /* ← 就是现在这个蓝，没换色 */
        border-radius: 4px 0 0 4px;
        background: var(--hfpan-surface);
    }

    /* ③ 输入框：**去掉自己的边框**（框已经由上面那层容器画了，不然会套两层） */
    .hfpan-cat__searchkw .hfpan-cat__skw {
        border: 0;
        border-radius: 0;
        background: transparent;
        flex: 1 1 auto;
        min-width: 0;
        min-height: 48px;                 /* 0.14.57 定的"手指点得进去"的高度，保留 */
        margin-right: 0;
        padding: 6px 10px;
    }

    /* ④ 放大镜：进框里，左边留出与卡片内边距一致的空 */
    .hfpan-cat__searchkw .hfpan-cat__searchicon {
        margin-left: 12px;
        margin-right: 8px;
    }

    /* ⑤ 垃圾桶：也在框里，贴框的右缘（不再有自己的圆角/外边距） */
    .hfpan-cat__search .hfpan-cat__sreset {
        border-radius: 0;
        padding: 0 12px;
        min-width: 44px;
        width: auto;
        min-height: 48px;
    }

    /* ⑥ 「搜索」按钮：**和上方「分类」chip 同宽同位**（都吃 `--hfpan-sgo-w`）、
          撑满高度、右圆角跟卡片一致 → 与蓝框**无缝**接上 */
    .hfpan-cat__sgo {
        flex: 0 0 var(--hfpan-sgo-w, 65px);
        padding: 0;
        min-height: 48px;
        align-self: stretch;
        border-radius: 0 var(--hfpan-radius-card) var(--hfpan-radius-card) 0;
    }
}
