` 包住;点已套用的片段可改类,Backspace 可整体删除。
面板里的两类与上表一一对应(字体 8 / 颜色 9),类清单单一事实源在 `public/admin/typography-classes.js`。
+## 三层排版架构(全站,不只文章正文)
+
+**层 1 · 页面文案富文本**:后台「页面文案」里的 tagline / subtitle / blurb / blurb_after / intro / 关于页 blocks 的 prose 块,全部走同一条富文本管线(markdown + raw + 内容净化 + class 白名单 + 链接卡片)。可以直接写:
+
+```yaml
+tagline:
+ zh: '写作者 · 读者 · 快门按压者,拥抱开源。'
+```
+
+渲染入口唯一:`src/lib/site-content.ts` 的 `renderRich()`(行内场景传 `{ inline: true }` 自动剥外层 ``,否则 `
` 套 `
` 会被浏览器拆散)。
+**不开放**:导航/页脚/按钮等硬编码界面外壳——那是 UI 不是内容。
+
+**层 2 · 页面级排版覆盖**:每个页面单例(`content/site/*.yaml`)可加:
+
+```yaml
+typography:
+ font: font-kai # 本页正文默认字体类(可选)
+ accent: c-blue # 本页强调色类(可选)
+ scale: 1.1 # 字号缩放 0.8–1.25(可选)
+```
+
+实现是在该页内容容器上挂 `.page-typo` + CSS 变量(`--page-font / --page-accent / --page-scale`),**不写全站 tokens**——其它页面零影响(已在图库/书架/文章/装备页验证隔离)。白名单外的类名会被忽略。
+后台入口:「页面文案 → 各自页面 → 页面排版覆盖」。
+
+**层 3 · 艺术字体**:`font-art-kuaile`(站酷快乐体,艺术字专用类)。⚠️ **仅用于标题/短句**:艺术字字形大,CJK 切片体积高(实测用到页 +163KB),长段使用会显著抬高单页字体成本。
+
+## 页面块(关于页 blocks,字段速查)
+
+关于页正文可由九个块拼成(后台拖拽排序,每块有「显示」开关)。完整操作见 [管理台](./管理台.md);这里是写内容时对照的字段表——文本字段一律 `{zh, en}`。
+
+| 块型 | 必填 | 可选 | 一句话 |
+|---|---|---|---|
+| `prose` | `body` | `title`、`width`(narrow/full) | markdown 长文 |
+| `tracks` | `title`、`items[].name` | `items[].icon`、`items[].desc` | 主线/能力面 |
+| `cards` | `items[].title` | `title`、`columns`(2/3)、`items[].desc/href/tag` | 并列卡片墙 |
+| `timeline` | `items[].time`、`items[].title` | `title`、`items[].desc` | 时间线(时间可自由文本) |
+| `quote` | `text` | `cite` | 单句引文 |
+| `figure` | `image` | `alt`、`caption` | 单图(必须上传,禁外链) |
+| `linklist` | `items[].label`、`items[].href` | `title`、`items[].note` | 链接清单 |
+| `cta` | `text`、`href`、`label` | — | 行动按钮 |
+| `divider` | — | `style`(line/space) | 分隔 |
+
+```yaml
+blocks:
+ - type: prose
+ body: { zh: 正文 markdown,可含排版类 span, en: Body markdown }
+ - type: cards
+ columns: 3
+ items:
+ - { title: { zh: 写作, en: Writing }, desc: { zh: 书评与技术文, en: Reviews & tech } }
+```
+
+边界:块数 ≤24、单块文本 ≤4000 字(超限截断并 WARN);未知块型跳过 + WARN;`blocks` 为空时回落 `intro` markdown,再空回落内置文案。图片字段走 `image()`,只能后台上传进 `content/site/assets/`。
+
## 发布提醒
- push main → webhook 自动构建发布(约 10 秒)
@@ -277,6 +343,9 @@ markdown 原生语法,无需任何配置:
| `latestPhotos` | 0-6 | 4 | 「最新影像」张数;**0 = 隐藏该区块** |
| `perTrackLimit` | 4-8 | 6 | 首页阅读/技术两轨各显示条数 |
| `sections` | `{tracks, photos, heatmap, projects}` 布尔 | 全开 | 区块开关,关掉即不渲染 |
+| `projectsLimit` | 1-99 | 6 | 首页项目墙条数(越界夹取) |
+| `announcement` | `{zh, en}`(markdown 富文本) | 空 | 名片区下方公告;空 = 不渲染 |
+| `postsTracks` | `{reading, tech, photo}` 布尔 | 全开 | 关掉某轨则该轨文章不在首页列出(归档页仍可见) |
越界值会被夹取(如 perTrackLimit=20 按 8 处理),不报错;**全部留空 = 现有形态不变**。
diff --git a/docs/管理台.md b/docs/管理台.md
index 0850027..14593a6 100644
--- a/docs/管理台.md
+++ b/docs/管理台.md
@@ -1,17 +1,148 @@
# 管理台(Sveltia CMS)使用指南
> 地址:`https://wait4x.online/admin/`(页脚「管理」入口)| 用途:照片上传与 sidecar 编辑的图形界面 | 保存即 commit 到 main → webhook 自动构建发布(约 10 秒上线)
+>
+> 这份是**操作手册**:每个入口能改什么、字段怎么填、改完会发生什么。写文章正文的排版技巧见 [写作指南](./写作指南.md)——两份分工:这里讲"后台怎么用",那里讲"正文怎么写"。
## 登录
选 **Sign In with Token** → 用 gitea 的 access token(宿主 `~/docker_apps/gitea/init-templates.txt` 里的 api-token,或 gitea 网页新建 scope=read/write:repository)。token 存浏览器 localStorage,下次免登。
+## 四类内容集合
+
+| 入口 | 文件位置 | 用来放什么 | 关键约束 |
+|---|---|---|---|
+| 文章 | `content/posts/.md` | 书评 / 技术文 / 摄影札记三轨 | `category` 三选一(`reading` / `tech` / `photo`),首页分轨由它派生 |
+| 瞬间 | `content/moments/*.md` | 一句话 + 一张图的时间线 | `text` 与 `image` **至少填一项**(后台无法表达条件必填,保存前自查) |
+| 照片 | `content/photos/*.json` + 图 | 图库(街拍 / 风景两组) | 标题**必填**(空标题会让构建炸,实测坑);EXIF 由构建期 loader 自动补全 |
+| 站点页面 | `content/site/*.yaml` | 首页、关于页、开源页、主题 | 后台改的是**单例文件**,没有"新建" |
+
+几条通用规则:
+
+- **双语字段成对出现**:中文 / 英文两个输入框。英文留空不是错误——构建期回落中文并在日志里打 WARN(`[blocks] 缺译…`),页面不会破版。
+- **留空 = 用默认**:任何字段清空都回到仓库自带的默认文案 / 默认值,构建永远成功。想让某段彻底消失,请看字段自带的"留空则不渲染"提示。
+- **文章英文版**:不在后台写。跑 `python3 scripts/translate/translate_posts.py` 生成 `content/posts-en/` 同名文件;手写润色过的译文在 frontmatter 写 `locked: true`,翻译脚本会无条件跳过它。
+- **保存即提交**:后台保存等于向仓库提交,push 后约 10 秒自动构建上线。
+
## 照片上传流
1. 图库照片 → New Entry:填标题(**必填**,空标题会让构建炸——实测坑)、选分组(street/landscape)、可写 alt
2. 图片字段 → 资产库上传 jpg(与 sidecar 同目录落位,零重压缩)
3. Save → 自动 commit + 构建 → 画廊出现(EXIF 构建期自动提取,exif 字段留空即可)
+## 块编辑:关于页的块式页面构建器
+
+关于页(`content/site/about.yaml`)的正文由 **blocks 列表**构成,后台里是一串可拖拽排序的卡片。每个块都有「显示」开关;关掉只是不渲染,块本身留在数据里。
+
+两条渲染纪律:
+
+- 列表为空(或全关)时,页面回落到 `intro` 字段的 markdown 正文;`intro` 也空则用内置默认文案。三级回落,任何一级为空都不会出白页。
+- 未知块型(手工编辑 yaml 写错的 `type`)会被**跳过并打印 `[blocks]` 警告**,不会炸构建;块数上限 24,单块文本上限 4000 字,超限截断并 WARN。
+
+九类块与字段(文本字段一律 `{zh, en}` 双语对象):
+
+| 块型 | 必填 | 可选 | 用途 |
+|---|---|---|---|
+| `prose` 正文 | `body` | `title`、`width`(`narrow` 版心 / `full` 通栏) | markdown 长文,最常用 |
+| `tracks` 版图 | `title`、`items[].name` | `items[].icon`、`items[].desc` | 几条主线 / 能力面,图标白名单外或留空显示首字占位 |
+| `cards` 卡片墙 | `items[].title` | `title`、`columns`(2 或 3,默认 3)、`items[].desc/href/tag` | 并列展示若干条目 |
+| `timeline` 时间线 | `items[].time`、`items[].title` | `title`、`items[].desc` | 时间列是自由文本(`2024 — 2026` 也行) |
+| `quote` 引文 | `text` | `cite` | 单句金句,配 `font-kai` 更出效果 |
+| `figure` 图片 | `image` | `alt`、`caption` | **只能后台上传**(落 `content/site/assets/`,走图片管线),禁止外链 |
+| `linklist` 链接清单 | `items[].label`、`items[].href` | `title`、`items[].note` | 相关阅读 / 外部资源 |
+| `cta` 行动按钮 | `text`、`href`、`label` | — | 一页建议不超过一个 |
+| `divider` 分隔 | — | `style`(`line` 细线 / `space` 纯留白) | 长页分段 |
+
+yaml 形态示例(手工编辑时照此写):
+
+```yaml
+blocks:
+ - type: prose
+ title: { zh: 关于这个站点, en: About this site }
+ body:
+ zh: 这里写 markdown 正文,支持列表、粗斜体、链接与排版类。
+ en: Markdown body here.
+ width: narrow
+ - type: quote
+ text: { zh: 所谓暮色,就是光慢慢地承认自己要走。, en: Dusk is light admitting it has to go. }
+ cite: { zh: 本站, en: this site }
+ - type: figure
+ image: ./assets/desk.jpg # 后台会替你写成这个相对路径
+ caption: { zh: 工作台一角, en: A corner of the desk }
+```
+
+其它可用字段:`layout.showIdCard`(关掉则不渲染名片区,默认开)、`typography`(见下一节)。
+
+**预览限制**:后台只提供字段编辑与列表摘要(摘要显示块型名),块的真实排版以下次构建后的页面为准——想调间距 / 字号,请用「主题设置」而不是在块里硬凑空行。
+
+## 页面排版覆盖(每页一处)
+
+首页 / 关于页 / 开源页各自有一个「页面排版覆盖(可选)」对象:
+
+| 字段 | 取值 | 说明 |
+|---|---|---|
+| `font` | 字族下拉(10 项) | 本页**正文**默认字体类 |
+| `accent` | 颜色下拉(18 项) | 本页强调色类 |
+| `scale` | 0.8–1.25 | 字号缩放,1 = 全站默认 |
+
+- 只作用于**该页内容容器**(挂 `.page-typo` + CSS 变量),不写全站 tokens,其它页面零影响。
+- **体积成本提醒**:整页换艺术/展示字族(`font-huiwen` 汇文、`font-kuaile` 快乐体)意味着整页正文都要下载对应切片——单页字体成本会明显抬升,见写作指南的体积账。
+- 白名单外的类名会被忽略(构建期过滤),写错不报错、也不生效。
+
+## 主题设置(全站 17 个旋钮)
+
+「主题设置」入口写 `content/site/theme.yaml`,17 项全部可选,留空 = 仓库默认值。**配错不会炸站**:越界值回落默认,组内单调性被破坏则整组回落。
+
+| 组 | 字段 | 范围 | 约束语义 |
+|---|---|---|---|
+| 强调色 | `accent_light` / `accent_dark` | `#rrggbb` | 明暗各一份;构建期对比度闸门断言正文 ≥4.5:1,不达标构建失败 |
+| 圆角 | `radius_img` | 4–16 | 图片圆角,建议 ≤14 |
+| 标题字号 | `text_h1` / `text_h2` / `text_h3` | h1/h2:22–32,h3:16–32 | **必须严格递减**(h1 > h2 > h3),否则三档一起回落默认 |
+| 正文字号 | `prose_size_reading` / `prose_size_tech` | 16–22 | 书评 / 技术文分轨独立 |
+| 行高 | `leading_reading` / `leading_tech` | 1.5–2.0 | 同上分轨 |
+| 间距梯度 | `space_3` / `space_4` / `space_5` / `space_6` | 8–80 | **必须严格递增**,否则整组回落 |
+| 流距 | `flow_p` / `flow_h2_post` | 0–2(em) | 段间距 / 标题下间距 |
+| 动效 | `dur` | 150–600(ms) | 过渡时长;`prefers-reduced-motion` 下自动归零 |
+
+不能配的东西(有意为止):版心宽度、断点、纸墨色、代码配色——它们牵动版面结构与分轨身份,属于设计红线。注入方式是构建期内联 `:root:root{…}`,运行时零 JS、零请求。
+
+## 首页与开源页的其余旋钮
+
+### 首页三字段(5g 新增)
+
+| 字段 | 取值 | 默认 | 作用 |
+|---|---|---|---|
+| `projectsLimit` | 1–99 | 6 | 首页项目墙条数(越界夹取) |
+| `announcement` | `{zh, en}` markdown | 空 | 名片区下方公告;**空 = 不渲染**,走富文本管线(可写排版类 span) |
+| `postsTracks` | `{reading, tech, photo}` 布尔 | 全开 | 关掉某轨,该轨文章不在首页列出(归档页仍可见) |
+
+### 开源页(opensource.yaml)
+
+| 字段 | 取值 | 说明 |
+|---|---|---|
+| `pinned` | 仓短名数组 | 置顶顺序即展示顺序 |
+| `mode` | `all` / `only` / `exclude` | 可见性模式 |
+| `include` / `exclude` | 仓短名数组 | 对应模式的白 / 黑名单 |
+| `sort` | `pinned-first` / `stars` / `updated` | 排序 |
+| `perSource` | `both` / `github` / `gitea` | 来源过滤 |
+| `intro_from` | `"off"` / `"github-readme"` | 开篇文案来源(**带引号写**,YAML 1.1 里裸 `off` 是布尔 false) |
+
+**`mode: only` 的"看不见"排查**:构建日志会给每个没显示出来的 include 项打一行 `[opensource] projects:include 里的「X」…`,并区分两种原因——双源结果里根本没有这个仓(拼写 / 私有仓 / 该源刚失败),或者命中了但被 `perSource` 过滤掉。看到哪一行就知道该改什么。
+
+**README 开篇(`intro_from: "github-readme"`)的回落矩阵**,构建日志逐级点名:
+
+1. 取到 → 内容有变化才刷新缓存 `content/.github-readme.md`(入仓,保证构建确定性)
+2. token 缺位 / HTTP 非 2xx / 内容为空 / 超时(10 秒)/ 网络异常 → 改用缓存(日志标注"可能陈旧")
+3. 缓存也不在 → 回落本文件 `blurb` 的叙述文案
+4. 缓存回写失败(构建仓只读挂载等)→ 只告警,本次渲染照常
+
+token 位在 `~/docker_apps/blog/github-token.txt`(本机,0600)。
+
+**两条已知限制**:
+
+- **README 里的相对链接不重写**(如 `./img/x.png`、`docs/foo.md`):它们相对 GitHub 仓根解析,在本站没有对应产物,点了多半 404。保原样比猜一个基址可信,所以不做改写。
+- **外部徽章图片加固但不参与构建**:shields.io、readme-typing-svg 这类第三方徽章在构建期**不抓取**,渲染时统一补 `loading="lazy"`(缺 alt 补空),它们慢、被墙或 404 都不影响页面渲染;尺寸已由样式限制在内容宽度内。
+
## 纪律(与写作指南同源)
- **图片体积**:上传前自行压缩(长边 ≤2400px)——Sveltia 内建优化**刻意关闭**(会抹 EXIF 断构建期提取管线)
diff --git a/infra/deploy/build.sh b/infra/deploy/build.sh
index 7d9d35b..d84a4ff 100755
--- a/infra/deploy/build.sh
+++ b/infra/deploy/build.sh
@@ -33,6 +33,8 @@ pnpm astro build
# 按页字体 CSS 子集化(车道 A 任务 1):裁 @font-face 声明数,构建仓与本地同链;
# 存在性守卫:新文件未推送到 main 前构建仓无此脚本,绝不让发布链因车道在途文件断掉
[ -f scripts/build-perf/subset-font-css.mjs ] && node scripts/build-perf/subset-font-css.mjs dist || echo "[build] subset 脚本未就绪,跳过"
+[ -f scripts/build-perf/config-check.py ] && python3 scripts/build-perf/config-check.py || echo "[build] config-check 未就绪,跳过"
+[ -f scripts/build-perf/contrast-check.mjs ] && node scripts/build-perf/contrast-check.mjs dist || echo "[build] contrast 脚本未就绪,跳过"
# 首页阻塞 CSS 内联(车道 D):守卫先行同上——脚本未到 main 前绝不炸链
[ -f scripts/build-perf/gen-sw-precache.mjs ] && node scripts/build-perf/gen-sw-precache.mjs dist || echo "[build] sw-precache 生成器未就绪,跳过"
[ -f scripts/build-perf/inline-home-css.mjs ] && node scripts/build-perf/inline-home-css.mjs || echo "[build] inline-home 脚本未就绪,跳过"
diff --git a/public/admin/config.yml b/public/admin/config.yml
index 36e1ec3..19ed8c1 100644
--- a/public/admin/config.yml
+++ b/public/admin/config.yml
@@ -58,6 +58,29 @@ collections:
- { label: 草稿, name: draft, widget: boolean, required: false, default: false }
- { label: 正文, name: body, widget: markdown }
+ # 主题旋钮(样式即数据 · 层 4):只放白名单内的 9 组,越界值会被构建期钳制
+ - name: site_theme
+ label: 主题设置
+ file: content/site/theme.yaml
+ fields:
+ - { label: 强调色(亮), name: accent_light, widget: color, required: false, hint: '亮色模式强调色,如 #3454d1;构建期校验正文对比度 ≥4.5' }
+ - { label: 强调色(暗), name: accent_dark, widget: color, required: false, hint: '暗色模式强调色,如 #8ea2ff' }
+ - { label: 图片圆角, name: radius_img, widget: number, required: false, value_type: int, min: 4, max: 16, hint: '范围 4–16(建议 ≤14)' }
+ - { label: 一级标题字号, name: text_h1, widget: number, required: false, value_type: int, min: 22, max: 32, hint: '22–32,且必须大于 h2' }
+ - { label: 二级标题字号, name: text_h2, widget: number, required: false, value_type: int, min: 22, max: 32, hint: '22–32,必须小于 h1、大于 h3' }
+ - { label: 三级标题字号, name: text_h3, widget: number, required: false, value_type: int, min: 16, max: 32, hint: '16–32,必须小于 h2' }
+ - { label: 书评正文字号, name: prose_size_reading, widget: number, required: false, value_type: int, min: 16, max: 22, hint: '16–22' }
+ - { label: 技术文正文字号, name: prose_size_tech, widget: number, required: false, value_type: int, min: 16, max: 22, hint: '16–22' }
+ - { label: 书评行高, name: leading_reading, widget: number, required: false, value_type: float, min: 1.5, max: 2.0, step: 0.05, hint: '1.5–2.0' }
+ - { label: 技术文行高, name: leading_tech, widget: number, required: false, value_type: float, min: 1.5, max: 2.0, step: 0.05, hint: '1.5–2.0' }
+ - { label: 间距 3, name: space_3, widget: number, required: false, value_type: int, min: 8, max: 80, hint: '8–80,必须 < 间距 4' }
+ - { label: 间距 4, name: space_4, widget: number, required: false, value_type: int, min: 8, max: 80, hint: '8–80,必须 > 间距 3 且 < 间距 5' }
+ - { label: 间距 5, name: space_5, widget: number, required: false, value_type: int, min: 8, max: 80, hint: '8–80,必须 > 间距 4 且 < 间距 6' }
+ - { label: 间距 6, name: space_6, widget: number, required: false, value_type: int, min: 8, max: 80, hint: '8–80,必须 > 间距 5' }
+ - { label: 段间距, name: flow_p, widget: number, required: false, value_type: float, min: 0, max: 2, step: 0.05, hint: '0–2(em)' }
+ - { label: 标题下间距, name: flow_h2_post, widget: number, required: false, value_type: float, min: 0, max: 2, step: 0.05, hint: '0–2(em)' }
+ - { label: 过渡时长, name: dur, widget: number, required: false, value_type: int, min: 150, max: 600, hint: '150–600(毫秒)' }
+
# 瞬间:随手发(text/image 至少其一——Sveltia 无法表达条件必填,两者都设可选,
# 保存前自查;pubDate 必填)。图片走图库媒体库(content/photos 同源可复用)
- name: moments
@@ -120,9 +143,47 @@ collections:
- label: 身份语
name: tagline
widget: object
+ required: false
+ hint: 首页大字身份语(双语,markdown 富文本);可写 … 做局部强调
fields:
- { label: 中文, name: zh, widget: string, required: false }
- { label: 英文, name: en, widget: string, required: false }
+ - label: 页面排版覆盖(可选)
+ name: typography
+ widget: object
+ required: false
+ hint: 本页正文默认字体 / 强调色 / 字号缩放(0.8–1.25);不填用全站默认,只影响本页
+ fields:
+ - label: 正文字体类
+ name: font
+ widget: select
+ required: false
+ hint: 整页正文换字族;艺术/展示类字族(汇文、快乐体)体积大,单页成本会上升
+ options: [font-serif, font-kai, font-sans, font-mono, font-song, font-kai-sys, font-hei-sys, font-fangsong, font-huiwen, font-kuaile]
+ - label: 强调色类
+ name: accent
+ widget: select
+ required: false
+ options: [ink-accent, ink-accent-soft, c-blue, c-blue-soft, c-teal, c-teal-soft, c-green, c-green-soft, c-yellow, c-yellow-soft, c-orange, c-orange-soft, c-red, c-red-soft, c-pink, c-pink-soft, c-purple, c-purple-soft]
+ - { label: 字号缩放, name: scale, widget: number, required: false, value_type: float, min: 0.8, max: 1.25, step: 0.05, hint: '0.8–1.25;1 = 全站默认' }
+ - label: 公告(可选,markdown)
+ name: announcement
+ widget: object
+ required: false
+ hint: 渲染在名片区下方;留空则不显示公告块
+ fields:
+ - { label: 中文, name: zh, widget: markdown, required: false }
+ - { label: 英文, name: en, widget: markdown, required: false }
+ - { label: 项目墙条数, name: projectsLimit, widget: number, required: false, value_type: int, min: 1, max: 99, hint: '首页项目墙显示几条(1–99,缺省 6)' }
+ - label: 轨细分开关(首页文章列表)
+ name: postsTracks
+ widget: object
+ required: false
+ hint: 关掉某轨则该轨文章不在首页列出(全开=现状)
+ fields:
+ - { label: 阅读轨, name: reading, widget: boolean, required: false, default: true }
+ - { label: 技术轨, name: tech, widget: boolean, required: false, default: true }
+ - { label: 照片轨, name: photo, widget: boolean, required: false, default: true }
- label: 副标题(可选,markdown 短文本)
name: subtitle
widget: object
@@ -183,14 +244,280 @@ collections:
- name: about
label: 关于页
file: content/site/about.yaml
+ # 块内图片上传落 content/site/assets/,yaml 写 ./assets/xxx(Astro 图片管线)
+ media_folder: content/site/assets
+ public_folder: ./assets
fields:
- - label: 正文(markdown,多段)
+ - label: 页面块(拖拽排序;每块可折叠)
+ name: blocks
+ widget: list
+ typeKey: type
+ required: false
+ summary: '{{fields.type}}'
+ hint: '点「+ 添加」选块型。关掉某块用该块内的「显示」开关'
+ types:
+ - label: 正文(markdown)
+ name: prose
+ widget: object
+ hint: markdown 正文块;可选小标题与版心/通栏宽度,长文分段改内容用
+ fields:
+ - { label: 显示, name: enabled, widget: boolean, required: false, default: true }
+ - label: 小标题(可选)
+ name: title
+ widget: object
+ required: false
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 正文(markdown)
+ name: body
+ widget: object
+ fields:
+ - { label: 中文, name: zh, widget: markdown, required: false }
+ - { label: 英文, name: en, widget: markdown, required: false }
+ - label: 宽度
+ name: width
+ widget: select
+ required: false
+ default: narrow
+ options: [{ label: 版心宽度, value: narrow }, { label: 通栏, value: full }]
+ - label: 版图(图标+名称+描述)
+ name: tracks
+ widget: object
+ hint: 版图块:图标 + 名称 + 描述,适合「几条主线/能力面」式介绍
+ fields:
+ - { label: 显示, name: enabled, widget: boolean, required: false, default: true }
+ - label: 标题
+ name: title
+ widget: object
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 条目
+ name: items
+ widget: list
+ summary: '{{fields.name.zh}}'
+ fields:
+ - label: 图标
+ name: icon
+ widget: select
+ required: false
+ options: [book, terminal, camera, code, git, rss, email, github, bilibili, x, star, link]
+ hint: 白名单外或留空 → 显示首字占位
+ - label: 名称
+ name: name
+ widget: object
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 描述
+ name: desc
+ widget: object
+ required: false
+ fields:
+ - { label: 中文, name: zh, widget: text, required: false }
+ - { label: 英文, name: en, widget: text, required: false }
+ - label: 卡片(2/3 列)
+ name: cards
+ widget: object
+ hint: 卡片墙(2/3 列):每卡 = 标题 + 描述 + 可选链接/角标
+ fields:
+ - { label: 显示, name: enabled, widget: boolean, required: false, default: true }
+ - label: 标题(可选)
+ name: title
+ widget: object
+ required: false
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - { label: 列数, name: columns, widget: number, required: false, default: 3, min: 2, max: 3, value_type: int }
+ - label: 卡片条目
+ name: items
+ widget: list
+ summary: '{{fields.title.zh}}'
+ fields:
+ - label: 标题
+ name: title
+ widget: object
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 描述
+ name: desc
+ widget: object
+ required: false
+ fields:
+ - { label: 中文, name: zh, widget: text, required: false }
+ - { label: 英文, name: en, widget: text, required: false }
+ - { label: 链接(可选), name: href, widget: string, required: false }
+ - label: 角标(可选)
+ name: tag
+ widget: object
+ required: false
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 时间线
+ name: timeline
+ widget: object
+ hint: 时间线:一条时间 + 标题 + 描述;时间可写自由文本(如 2024 — 2026)
+ fields:
+ - { label: 显示, name: enabled, widget: boolean, required: false, default: true }
+ - label: 标题(可选)
+ name: title
+ widget: object
+ required: false
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 条目
+ name: items
+ widget: list
+ summary: '{{fields.time}} · {{fields.title.zh}}'
+ fields:
+ - { label: 时间, name: time, widget: string, hint: '自由文本,如 2024 — 2026' }
+ - label: 标题
+ name: title
+ widget: object
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 描述(可选)
+ name: desc
+ widget: object
+ required: false
+ fields:
+ - { label: 中文, name: zh, widget: text, required: false }
+ - { label: 英文, name: en, widget: text, required: false }
+ - label: 引文
+ name: quote
+ widget: object
+ hint: 单句引文 + 可选署名;配 font-kai 排版效果更好
+ fields:
+ - { label: 显示, name: enabled, widget: boolean, required: false, default: true }
+ - label: 引文
+ name: text
+ widget: object
+ fields:
+ - { label: 中文, name: zh, widget: text, required: false }
+ - { label: 英文, name: en, widget: text, required: false }
+ - label: 出处(可选)
+ name: cite
+ widget: object
+ required: false
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 图片
+ name: figure
+ widget: object
+ hint: 单图 + 可选说明;图片只能后台上传(落 content/site/assets),禁外链
+ fields:
+ - { label: 显示, name: enabled, widget: boolean, required: false, default: true }
+ - { label: 图片(必填,请用后台上传), name: image, widget: image, hint: '禁止填外链:只能上传(落 content/site/assets/),走 Astro 图片管线' }
+ - { label: 替代文本(无障碍), name: alt, widget: string, required: false }
+ - label: 图注(可选)
+ name: caption
+ widget: object
+ required: false
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 链接清单
+ name: linklist
+ widget: object
+ hint: 链接清单(标签 + 链接 + 备注),适合「相关阅读 / 外部资源」
+ fields:
+ - { label: 显示, name: enabled, widget: boolean, required: false, default: true }
+ - label: 标题(可选)
+ name: title
+ widget: object
+ required: false
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 链接条目
+ name: items
+ widget: list
+ summary: '{{fields.label.zh}} → {{fields.href}}'
+ fields:
+ - label: 名称
+ name: label
+ widget: object
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - { label: 链接, name: href, widget: string }
+ - label: 备注(可选)
+ name: note
+ widget: object
+ required: false
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 行动按钮
+ name: cta
+ widget: object
+ hint: 行动按钮(文案 + 链接 + 按钮字);一页建议不超过一个
+ fields:
+ - { label: 显示, name: enabled, widget: boolean, required: false, default: true }
+ - label: 说明文字
+ name: text
+ widget: object
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - { label: 按钮链接, name: href, widget: string }
+ - label: 按钮文字
+ name: label
+ widget: object
+ fields:
+ - { label: 中文, name: zh, widget: string, required: false }
+ - { label: 英文, name: en, widget: string, required: false }
+ - label: 分隔
+ name: divider
+ widget: object
+ hint: 分隔块:细分隔线或纯留白,给长页分段
+ fields:
+ - { label: 显示, name: enabled, widget: boolean, required: false, default: true }
+ - label: 样式
+ name: style
+ widget: select
+ required: false
+ default: line
+ options: [{ label: 细分隔线, value: line }, { label: 纯留白, value: space }]
+ - label: 名片区开关
+ name: layout
+ widget: object
+ required: false
+ hint: 关掉则不显示头像/名字/社交(它们的数据在「主页设置」)
+ fields:
+ - { label: 显示名片区, name: showIdCard, widget: boolean, required: false, default: true }
+ - label: 正文回退(blocks 为空时用,markdown,多段)
name: intro
widget: object
- hint: 渲染在「关于」标题下方、名片之上;支持段落/列表/粗斜体/链接;留空用默认文案
+ required: false
+ hint: 仅在「页面块」为空时渲染;与块同时存在时以块为准
fields:
- { label: 中文, name: zh, widget: markdown, required: false }
- { label: 英文, name: en, widget: markdown, required: false }
+ - label: 页面排版覆盖(可选)
+ name: typography
+ widget: object
+ required: false
+ hint: 本页正文默认字体 / 强调色 / 字号缩放(0.8–1.25);不填用全站默认,只影响本页
+ fields:
+ - label: 正文字体类
+ name: font
+ widget: select
+ required: false
+ options: [font-serif, font-kai, font-sans, font-mono, font-song, font-kai-sys, font-hei-sys, font-fangsong, font-huiwen, font-kuaile]
+ - label: 强调色类
+ name: accent
+ widget: select
+ required: false
+ options: [ink-accent, ink-accent-soft, c-blue, c-blue-soft, c-teal, c-teal-soft, c-green, c-green-soft, c-yellow, c-yellow-soft, c-orange, c-orange-soft, c-red, c-red-soft, c-pink, c-pink-soft, c-purple, c-purple-soft]
+ - { label: 字号缩放, name: scale, widget: number, required: false, value_type: float, min: 0.8, max: 1.25, step: 0.05 }
- name: opensource
label: 开源页
file: content/site/opensource.yaml
@@ -198,9 +525,29 @@ collections:
- label: 叙述(链接前)
name: blurb
widget: object
+ required: false
+ hint: 富文本(markdown + 排版类),渲染在仓库链接之前
fields:
- { label: 中文, name: zh, widget: string, required: false }
- { label: 英文, name: en, widget: string, required: false }
+ - label: 页面排版覆盖(可选)
+ name: typography
+ widget: object
+ required: false
+ hint: 本页正文默认字体 / 强调色 / 字号缩放(0.8–1.25);不填用全站默认,只影响本页
+ fields:
+ - label: 正文字体类
+ name: font
+ widget: select
+ required: false
+ hint: 整页正文换字族;艺术/展示类字族(汇文、快乐体)体积大,单页成本会上升
+ options: [font-serif, font-kai, font-sans, font-mono, font-song, font-kai-sys, font-hei-sys, font-fangsong, font-huiwen, font-kuaile]
+ - label: 强调色类
+ name: accent
+ widget: select
+ required: false
+ options: [ink-accent, ink-accent-soft, c-blue, c-blue-soft, c-teal, c-teal-soft, c-green, c-green-soft, c-yellow, c-yellow-soft, c-orange, c-orange-soft, c-red, c-red-soft, c-pink, c-pink-soft, c-purple, c-purple-soft]
+ - { label: 字号缩放, name: scale, widget: number, required: false, value_type: float, min: 0.8, max: 1.25, step: 0.05, hint: '0.8–1.25;1 = 全站默认' }
- { label: 仓库链接地址, name: repo_url, widget: string, required: false }
- { label: 仓库链接文字, name: repo_label, widget: string, required: false }
- label: 叙述(链接后)
diff --git a/public/admin/typography-classes.js b/public/admin/typography-classes.js
index 53f4388..5e91788 100644
--- a/public/admin/typography-classes.js
+++ b/public/admin/typography-classes.js
@@ -18,6 +18,7 @@ window.TYPOGRAPHY_CLASSES = {
{ cls: 'font-fangsong', label: '仿宋族', family: 'FangSong, STFangsong, serif', kind: '系统回退' },
{ cls: 'font-huiwen', label: '汇文明朝体', family: '"WF-Hwmc", serif', kind: '自托管' },
{ cls: 'font-kuaile', label: '站酷快乐体', family: '"ZCOOL KuaiLe", serif', kind: '自托管' },
+ { cls: 'font-art-kuaile', label: '快乐体(艺术·仅标题)', family: '"ZCOOL KuaiLe", serif', kind: '艺术字' },
],
color: [
{ cls: 'ink-1', label: '最重(标题级)', swatch: '#111113' },
diff --git a/public/fonts/subset/hwmc/files/1-subset.woff2 b/public/fonts/subset/hwmc/files/1-subset.woff2
new file mode 100644
index 0000000..e6c55dc
Binary files /dev/null and b/public/fonts/subset/hwmc/files/1-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/100-subset.woff2 b/public/fonts/subset/hwmc/files/100-subset.woff2
new file mode 100644
index 0000000..1587559
Binary files /dev/null and b/public/fonts/subset/hwmc/files/100-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/101-subset.woff2 b/public/fonts/subset/hwmc/files/101-subset.woff2
new file mode 100644
index 0000000..f01275e
Binary files /dev/null and b/public/fonts/subset/hwmc/files/101-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/102-subset.woff2 b/public/fonts/subset/hwmc/files/102-subset.woff2
new file mode 100644
index 0000000..07fb974
Binary files /dev/null and b/public/fonts/subset/hwmc/files/102-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/103-subset.woff2 b/public/fonts/subset/hwmc/files/103-subset.woff2
new file mode 100644
index 0000000..84da896
Binary files /dev/null and b/public/fonts/subset/hwmc/files/103-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/104-subset.woff2 b/public/fonts/subset/hwmc/files/104-subset.woff2
new file mode 100644
index 0000000..cce673b
Binary files /dev/null and b/public/fonts/subset/hwmc/files/104-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/105-subset.woff2 b/public/fonts/subset/hwmc/files/105-subset.woff2
new file mode 100644
index 0000000..7ea93d6
Binary files /dev/null and b/public/fonts/subset/hwmc/files/105-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/106-subset.woff2 b/public/fonts/subset/hwmc/files/106-subset.woff2
new file mode 100644
index 0000000..03f77d3
Binary files /dev/null and b/public/fonts/subset/hwmc/files/106-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/107-subset.woff2 b/public/fonts/subset/hwmc/files/107-subset.woff2
new file mode 100644
index 0000000..ced12e5
Binary files /dev/null and b/public/fonts/subset/hwmc/files/107-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/109-subset.woff2 b/public/fonts/subset/hwmc/files/109-subset.woff2
new file mode 100644
index 0000000..b1901a4
Binary files /dev/null and b/public/fonts/subset/hwmc/files/109-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/110-subset.woff2 b/public/fonts/subset/hwmc/files/110-subset.woff2
new file mode 100644
index 0000000..d543c34
Binary files /dev/null and b/public/fonts/subset/hwmc/files/110-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/113-subset.woff2 b/public/fonts/subset/hwmc/files/113-subset.woff2
new file mode 100644
index 0000000..4aba20d
Binary files /dev/null and b/public/fonts/subset/hwmc/files/113-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/118-subset.woff2 b/public/fonts/subset/hwmc/files/118-subset.woff2
new file mode 100644
index 0000000..d79482c
Binary files /dev/null and b/public/fonts/subset/hwmc/files/118-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/119-subset.woff2 b/public/fonts/subset/hwmc/files/119-subset.woff2
new file mode 100644
index 0000000..4563ae0
Binary files /dev/null and b/public/fonts/subset/hwmc/files/119-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/120-subset.woff2 b/public/fonts/subset/hwmc/files/120-subset.woff2
new file mode 100644
index 0000000..bddfd3f
Binary files /dev/null and b/public/fonts/subset/hwmc/files/120-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/121-subset.woff2 b/public/fonts/subset/hwmc/files/121-subset.woff2
new file mode 100644
index 0000000..fdd9ae7
Binary files /dev/null and b/public/fonts/subset/hwmc/files/121-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/127-subset.woff2 b/public/fonts/subset/hwmc/files/127-subset.woff2
new file mode 100644
index 0000000..8bb5a4c
Binary files /dev/null and b/public/fonts/subset/hwmc/files/127-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/2-subset.woff2 b/public/fonts/subset/hwmc/files/2-subset.woff2
new file mode 100644
index 0000000..d4be482
Binary files /dev/null and b/public/fonts/subset/hwmc/files/2-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/245-subset.woff2 b/public/fonts/subset/hwmc/files/245-subset.woff2
new file mode 100644
index 0000000..6bb68df
Binary files /dev/null and b/public/fonts/subset/hwmc/files/245-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/247-subset.woff2 b/public/fonts/subset/hwmc/files/247-subset.woff2
new file mode 100644
index 0000000..9d7ee10
Binary files /dev/null and b/public/fonts/subset/hwmc/files/247-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/253-subset.woff2 b/public/fonts/subset/hwmc/files/253-subset.woff2
new file mode 100644
index 0000000..3d0247b
Binary files /dev/null and b/public/fonts/subset/hwmc/files/253-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/26-subset.woff2 b/public/fonts/subset/hwmc/files/26-subset.woff2
new file mode 100644
index 0000000..d6a9d74
Binary files /dev/null and b/public/fonts/subset/hwmc/files/26-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/27-subset.woff2 b/public/fonts/subset/hwmc/files/27-subset.woff2
new file mode 100644
index 0000000..086c7a0
Binary files /dev/null and b/public/fonts/subset/hwmc/files/27-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/28-subset.woff2 b/public/fonts/subset/hwmc/files/28-subset.woff2
new file mode 100644
index 0000000..21fa5e6
Binary files /dev/null and b/public/fonts/subset/hwmc/files/28-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/29-subset.woff2 b/public/fonts/subset/hwmc/files/29-subset.woff2
new file mode 100644
index 0000000..a3fb462
Binary files /dev/null and b/public/fonts/subset/hwmc/files/29-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/3-subset.woff2 b/public/fonts/subset/hwmc/files/3-subset.woff2
new file mode 100644
index 0000000..fa766ca
Binary files /dev/null and b/public/fonts/subset/hwmc/files/3-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/30-subset.woff2 b/public/fonts/subset/hwmc/files/30-subset.woff2
new file mode 100644
index 0000000..7b8190b
Binary files /dev/null and b/public/fonts/subset/hwmc/files/30-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/31-subset.woff2 b/public/fonts/subset/hwmc/files/31-subset.woff2
new file mode 100644
index 0000000..c49d3a0
Binary files /dev/null and b/public/fonts/subset/hwmc/files/31-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/32-subset.woff2 b/public/fonts/subset/hwmc/files/32-subset.woff2
new file mode 100644
index 0000000..fcd7407
Binary files /dev/null and b/public/fonts/subset/hwmc/files/32-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/33-subset.woff2 b/public/fonts/subset/hwmc/files/33-subset.woff2
new file mode 100644
index 0000000..58b387c
Binary files /dev/null and b/public/fonts/subset/hwmc/files/33-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/34-subset.woff2 b/public/fonts/subset/hwmc/files/34-subset.woff2
new file mode 100644
index 0000000..cf380bd
Binary files /dev/null and b/public/fonts/subset/hwmc/files/34-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/35-subset.woff2 b/public/fonts/subset/hwmc/files/35-subset.woff2
new file mode 100644
index 0000000..ed8a837
Binary files /dev/null and b/public/fonts/subset/hwmc/files/35-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/36-subset.woff2 b/public/fonts/subset/hwmc/files/36-subset.woff2
new file mode 100644
index 0000000..f440ba2
Binary files /dev/null and b/public/fonts/subset/hwmc/files/36-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/37-subset.woff2 b/public/fonts/subset/hwmc/files/37-subset.woff2
new file mode 100644
index 0000000..97dabc0
Binary files /dev/null and b/public/fonts/subset/hwmc/files/37-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/38-subset.woff2 b/public/fonts/subset/hwmc/files/38-subset.woff2
new file mode 100644
index 0000000..56f374e
Binary files /dev/null and b/public/fonts/subset/hwmc/files/38-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/39-subset.woff2 b/public/fonts/subset/hwmc/files/39-subset.woff2
new file mode 100644
index 0000000..32c3b31
Binary files /dev/null and b/public/fonts/subset/hwmc/files/39-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/4-subset.woff2 b/public/fonts/subset/hwmc/files/4-subset.woff2
new file mode 100644
index 0000000..a5e78bd
Binary files /dev/null and b/public/fonts/subset/hwmc/files/4-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/40-subset.woff2 b/public/fonts/subset/hwmc/files/40-subset.woff2
new file mode 100644
index 0000000..7ed7237
Binary files /dev/null and b/public/fonts/subset/hwmc/files/40-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/41-subset.woff2 b/public/fonts/subset/hwmc/files/41-subset.woff2
new file mode 100644
index 0000000..1436ac9
Binary files /dev/null and b/public/fonts/subset/hwmc/files/41-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/42-subset.woff2 b/public/fonts/subset/hwmc/files/42-subset.woff2
new file mode 100644
index 0000000..01efec2
Binary files /dev/null and b/public/fonts/subset/hwmc/files/42-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/43-subset.woff2 b/public/fonts/subset/hwmc/files/43-subset.woff2
new file mode 100644
index 0000000..2c55fe4
Binary files /dev/null and b/public/fonts/subset/hwmc/files/43-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/44-subset.woff2 b/public/fonts/subset/hwmc/files/44-subset.woff2
new file mode 100644
index 0000000..d08d4a1
Binary files /dev/null and b/public/fonts/subset/hwmc/files/44-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/45-subset.woff2 b/public/fonts/subset/hwmc/files/45-subset.woff2
new file mode 100644
index 0000000..071496b
Binary files /dev/null and b/public/fonts/subset/hwmc/files/45-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/46-subset.woff2 b/public/fonts/subset/hwmc/files/46-subset.woff2
new file mode 100644
index 0000000..df26d14
Binary files /dev/null and b/public/fonts/subset/hwmc/files/46-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/47-subset.woff2 b/public/fonts/subset/hwmc/files/47-subset.woff2
new file mode 100644
index 0000000..4146167
Binary files /dev/null and b/public/fonts/subset/hwmc/files/47-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/48-subset.woff2 b/public/fonts/subset/hwmc/files/48-subset.woff2
new file mode 100644
index 0000000..bdf5c18
Binary files /dev/null and b/public/fonts/subset/hwmc/files/48-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/49-subset.woff2 b/public/fonts/subset/hwmc/files/49-subset.woff2
new file mode 100644
index 0000000..6f04b61
Binary files /dev/null and b/public/fonts/subset/hwmc/files/49-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/5-subset.woff2 b/public/fonts/subset/hwmc/files/5-subset.woff2
new file mode 100644
index 0000000..b312040
Binary files /dev/null and b/public/fonts/subset/hwmc/files/5-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/50-subset.woff2 b/public/fonts/subset/hwmc/files/50-subset.woff2
new file mode 100644
index 0000000..c36b504
Binary files /dev/null and b/public/fonts/subset/hwmc/files/50-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/51-subset.woff2 b/public/fonts/subset/hwmc/files/51-subset.woff2
new file mode 100644
index 0000000..d0890ed
Binary files /dev/null and b/public/fonts/subset/hwmc/files/51-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/52-subset.woff2 b/public/fonts/subset/hwmc/files/52-subset.woff2
new file mode 100644
index 0000000..4cfe4bd
Binary files /dev/null and b/public/fonts/subset/hwmc/files/52-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/53-subset.woff2 b/public/fonts/subset/hwmc/files/53-subset.woff2
new file mode 100644
index 0000000..b4d49c5
Binary files /dev/null and b/public/fonts/subset/hwmc/files/53-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/54-subset.woff2 b/public/fonts/subset/hwmc/files/54-subset.woff2
new file mode 100644
index 0000000..9deccfb
Binary files /dev/null and b/public/fonts/subset/hwmc/files/54-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/55-subset.woff2 b/public/fonts/subset/hwmc/files/55-subset.woff2
new file mode 100644
index 0000000..017e1b6
Binary files /dev/null and b/public/fonts/subset/hwmc/files/55-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/56-subset.woff2 b/public/fonts/subset/hwmc/files/56-subset.woff2
new file mode 100644
index 0000000..5b9c433
Binary files /dev/null and b/public/fonts/subset/hwmc/files/56-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/57-subset.woff2 b/public/fonts/subset/hwmc/files/57-subset.woff2
new file mode 100644
index 0000000..149ccfd
Binary files /dev/null and b/public/fonts/subset/hwmc/files/57-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/58-subset.woff2 b/public/fonts/subset/hwmc/files/58-subset.woff2
new file mode 100644
index 0000000..239ffa0
Binary files /dev/null and b/public/fonts/subset/hwmc/files/58-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/59-subset.woff2 b/public/fonts/subset/hwmc/files/59-subset.woff2
new file mode 100644
index 0000000..8df36c1
Binary files /dev/null and b/public/fonts/subset/hwmc/files/59-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/6-subset.woff2 b/public/fonts/subset/hwmc/files/6-subset.woff2
new file mode 100644
index 0000000..3995a5c
Binary files /dev/null and b/public/fonts/subset/hwmc/files/6-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/60-subset.woff2 b/public/fonts/subset/hwmc/files/60-subset.woff2
new file mode 100644
index 0000000..084b453
Binary files /dev/null and b/public/fonts/subset/hwmc/files/60-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/61-subset.woff2 b/public/fonts/subset/hwmc/files/61-subset.woff2
new file mode 100644
index 0000000..1bbceb2
Binary files /dev/null and b/public/fonts/subset/hwmc/files/61-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/62-subset.woff2 b/public/fonts/subset/hwmc/files/62-subset.woff2
new file mode 100644
index 0000000..b0be52e
Binary files /dev/null and b/public/fonts/subset/hwmc/files/62-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/63-subset.woff2 b/public/fonts/subset/hwmc/files/63-subset.woff2
new file mode 100644
index 0000000..eb47555
Binary files /dev/null and b/public/fonts/subset/hwmc/files/63-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/64-subset.woff2 b/public/fonts/subset/hwmc/files/64-subset.woff2
new file mode 100644
index 0000000..9348555
Binary files /dev/null and b/public/fonts/subset/hwmc/files/64-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/65-subset.woff2 b/public/fonts/subset/hwmc/files/65-subset.woff2
new file mode 100644
index 0000000..8256e43
Binary files /dev/null and b/public/fonts/subset/hwmc/files/65-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/66-subset.woff2 b/public/fonts/subset/hwmc/files/66-subset.woff2
new file mode 100644
index 0000000..623b8a2
Binary files /dev/null and b/public/fonts/subset/hwmc/files/66-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/67-subset.woff2 b/public/fonts/subset/hwmc/files/67-subset.woff2
new file mode 100644
index 0000000..42656f1
Binary files /dev/null and b/public/fonts/subset/hwmc/files/67-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/68-subset.woff2 b/public/fonts/subset/hwmc/files/68-subset.woff2
new file mode 100644
index 0000000..48da260
Binary files /dev/null and b/public/fonts/subset/hwmc/files/68-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/69-subset.woff2 b/public/fonts/subset/hwmc/files/69-subset.woff2
new file mode 100644
index 0000000..b85dbe7
Binary files /dev/null and b/public/fonts/subset/hwmc/files/69-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/7-subset.woff2 b/public/fonts/subset/hwmc/files/7-subset.woff2
new file mode 100644
index 0000000..726a999
Binary files /dev/null and b/public/fonts/subset/hwmc/files/7-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/70-subset.woff2 b/public/fonts/subset/hwmc/files/70-subset.woff2
new file mode 100644
index 0000000..5778949
Binary files /dev/null and b/public/fonts/subset/hwmc/files/70-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/71-subset.woff2 b/public/fonts/subset/hwmc/files/71-subset.woff2
new file mode 100644
index 0000000..b59e3a9
Binary files /dev/null and b/public/fonts/subset/hwmc/files/71-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/72-subset.woff2 b/public/fonts/subset/hwmc/files/72-subset.woff2
new file mode 100644
index 0000000..040d67f
Binary files /dev/null and b/public/fonts/subset/hwmc/files/72-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/73-subset.woff2 b/public/fonts/subset/hwmc/files/73-subset.woff2
new file mode 100644
index 0000000..4825ffa
Binary files /dev/null and b/public/fonts/subset/hwmc/files/73-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/74-subset.woff2 b/public/fonts/subset/hwmc/files/74-subset.woff2
new file mode 100644
index 0000000..e38192e
Binary files /dev/null and b/public/fonts/subset/hwmc/files/74-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/75-subset.woff2 b/public/fonts/subset/hwmc/files/75-subset.woff2
new file mode 100644
index 0000000..87d4f13
Binary files /dev/null and b/public/fonts/subset/hwmc/files/75-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/76-subset.woff2 b/public/fonts/subset/hwmc/files/76-subset.woff2
new file mode 100644
index 0000000..d22c55b
Binary files /dev/null and b/public/fonts/subset/hwmc/files/76-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/77-subset.woff2 b/public/fonts/subset/hwmc/files/77-subset.woff2
new file mode 100644
index 0000000..a03ed17
Binary files /dev/null and b/public/fonts/subset/hwmc/files/77-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/78-subset.woff2 b/public/fonts/subset/hwmc/files/78-subset.woff2
new file mode 100644
index 0000000..5193281
Binary files /dev/null and b/public/fonts/subset/hwmc/files/78-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/79-subset.woff2 b/public/fonts/subset/hwmc/files/79-subset.woff2
new file mode 100644
index 0000000..adb3e98
Binary files /dev/null and b/public/fonts/subset/hwmc/files/79-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/80-subset.woff2 b/public/fonts/subset/hwmc/files/80-subset.woff2
new file mode 100644
index 0000000..986657a
Binary files /dev/null and b/public/fonts/subset/hwmc/files/80-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/81-subset.woff2 b/public/fonts/subset/hwmc/files/81-subset.woff2
new file mode 100644
index 0000000..4ab508e
Binary files /dev/null and b/public/fonts/subset/hwmc/files/81-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/82-subset.woff2 b/public/fonts/subset/hwmc/files/82-subset.woff2
new file mode 100644
index 0000000..41d299d
Binary files /dev/null and b/public/fonts/subset/hwmc/files/82-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/83-subset.woff2 b/public/fonts/subset/hwmc/files/83-subset.woff2
new file mode 100644
index 0000000..98ddb74
Binary files /dev/null and b/public/fonts/subset/hwmc/files/83-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/84-subset.woff2 b/public/fonts/subset/hwmc/files/84-subset.woff2
new file mode 100644
index 0000000..d4aa779
Binary files /dev/null and b/public/fonts/subset/hwmc/files/84-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/85-subset.woff2 b/public/fonts/subset/hwmc/files/85-subset.woff2
new file mode 100644
index 0000000..ecdbd86
Binary files /dev/null and b/public/fonts/subset/hwmc/files/85-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/86-subset.woff2 b/public/fonts/subset/hwmc/files/86-subset.woff2
new file mode 100644
index 0000000..6141a5c
Binary files /dev/null and b/public/fonts/subset/hwmc/files/86-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/87-subset.woff2 b/public/fonts/subset/hwmc/files/87-subset.woff2
new file mode 100644
index 0000000..6fde338
Binary files /dev/null and b/public/fonts/subset/hwmc/files/87-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/88-subset.woff2 b/public/fonts/subset/hwmc/files/88-subset.woff2
new file mode 100644
index 0000000..6f05fe6
Binary files /dev/null and b/public/fonts/subset/hwmc/files/88-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/89-subset.woff2 b/public/fonts/subset/hwmc/files/89-subset.woff2
new file mode 100644
index 0000000..df61bb1
Binary files /dev/null and b/public/fonts/subset/hwmc/files/89-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/90-subset.woff2 b/public/fonts/subset/hwmc/files/90-subset.woff2
new file mode 100644
index 0000000..aad472d
Binary files /dev/null and b/public/fonts/subset/hwmc/files/90-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/91-subset.woff2 b/public/fonts/subset/hwmc/files/91-subset.woff2
new file mode 100644
index 0000000..e56a8a2
Binary files /dev/null and b/public/fonts/subset/hwmc/files/91-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/92-subset.woff2 b/public/fonts/subset/hwmc/files/92-subset.woff2
new file mode 100644
index 0000000..bb3d091
Binary files /dev/null and b/public/fonts/subset/hwmc/files/92-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/93-subset.woff2 b/public/fonts/subset/hwmc/files/93-subset.woff2
new file mode 100644
index 0000000..44480e0
Binary files /dev/null and b/public/fonts/subset/hwmc/files/93-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/94-subset.woff2 b/public/fonts/subset/hwmc/files/94-subset.woff2
new file mode 100644
index 0000000..dc94751
Binary files /dev/null and b/public/fonts/subset/hwmc/files/94-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/95-subset.woff2 b/public/fonts/subset/hwmc/files/95-subset.woff2
new file mode 100644
index 0000000..fd96894
Binary files /dev/null and b/public/fonts/subset/hwmc/files/95-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/96-subset.woff2 b/public/fonts/subset/hwmc/files/96-subset.woff2
new file mode 100644
index 0000000..42ea4dd
Binary files /dev/null and b/public/fonts/subset/hwmc/files/96-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/97-subset.woff2 b/public/fonts/subset/hwmc/files/97-subset.woff2
new file mode 100644
index 0000000..edfe28c
Binary files /dev/null and b/public/fonts/subset/hwmc/files/97-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/98-subset.woff2 b/public/fonts/subset/hwmc/files/98-subset.woff2
new file mode 100644
index 0000000..e7ce933
Binary files /dev/null and b/public/fonts/subset/hwmc/files/98-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/files/99-subset.woff2 b/public/fonts/subset/hwmc/files/99-subset.woff2
new file mode 100644
index 0000000..5849e4c
Binary files /dev/null and b/public/fonts/subset/hwmc/files/99-subset.woff2 differ
diff --git a/public/fonts/subset/hwmc/fonts.css b/public/fonts/subset/hwmc/fonts.css
new file mode 100644
index 0000000..83dd9b9
--- /dev/null
+++ b/public/fonts/subset/hwmc/fonts.css
@@ -0,0 +1,100 @@
+@font-face{font-family:"WF-Hwmc";src: url('./files/253-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+25C7,U+25C9,U+25CB,U+25CE,U+25D0-25D3,U+25E6,U+25EF,U+2600-2603,U+2605-2606,U+2609-260E,U+2616-2617,U+261E,U+263C-263F;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/247-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+223D,U+2243,U+2245,U+2248,U+2252,U+2260-2262,U+2266-2267,U+226A-226B,U+2276-2277,U+2282-2287,U+228A-228B,U+2295-2296;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/245-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+2179-217B,U+2190-2194,U+2196-2199,U+21C4,U+21D2,U+21D4,U+21E6-21E9,U+2200,U+2202-2203;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/127-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E69,U+4F67,U+50A7,U+50E6,U+5363,U+5432,U+54AD,U+5575,U+5581,U+55CC,U+55FE,U+561E,U+5981,U+5AAA,U+5D74,U+5EF4,U+601B,U+6092,U+6661,U+68F9,U+69FF,U+6BF9,U+6C05,U+6CA9,U+6CF6-6CF7,U+6CFA,U+6DAB,U+6E54,U+7256,U+727E,U+73E5,U+750F,U+75AC,U+76B2,U+78A1,U+7905,U+7B2E,U+7B85,U+7B9C,U+7BCC,U+7BEA,U+7C74,U+7C9C,U+7E47,U+7E9F,U+7EE0,U+7EE8,U+7F27,U+7F7E,U+81A6,U+81C1,U+8234,U+82E1,U+83C0,U+8489,U+848C,U+84BD,U+8548,U+8785,U+8816,U+89DA,U+8D46,U+8D4D,U+9179,U+94AB,U+94D7,U+9515,U+952A,U+987C,U+9883,U+9B51,U+9CCE,U+9E37,U+9E39,U+9E41,U+9F2F,U+9F39,U+9F85;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/121-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F5E,U+4F76,U+4FAA,U+4FE6,U+5028,U+5048,U+53C1,U+5412,U+54DD,U+55F3,U+562C,U+575C,U+577C,U+5800,U+5D26,U+5F01,U+5FDD,U+629F,U+6332,U+63BC,U+65AB,U+65C3,U+669D,U+66BE,U+6800,U+68FC,U+690B,U+6978,U+6A3E,U+6A50,U+6A5B,U+6B24,U+6C54,U+6EBD,U+7292,U+72B8,U+75A0,U+779F,U+7AA8,U+7C1F,U+7ED4,U+7EFB,U+7FD5,U+8027,U+8167,U+81CA,U+82A9,U+82AB,U+8351,U+8368,U+83B8,U+83D8,U+858F,U+867B,U+86A9,U+877C,U+88DF,U+8BEE,U+8C20,U+8DF8,U+8E05,U+9021,U+908B,U+90EB,U+91AA,U+933E,U+9490,U+94D9,U+955E,U+95E9,U+960B,U+9612,U+9617,U+9A78,U+9AA0,U+9E28,U+9E6C,U+9F0B;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/120-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F25,U+4F32,U+5250,U+535F,U+538D,U+54D4,U+5541,U+55DD,U+5657-5658,U+5664,U+57B2,U+5AEB,U+5C3B,U+5D9D,U+5FB5,U+5FF8,U+6079,U+60B1,U+6222,U+63E0,U+6485,U+6924,U+6B8D,U+6D04,U+6D4D,U+6EB1,U+7110,U+7230,U+728D,U+72D2,U+7826,U+7877,U+7A39,U+7AE6,U+7B0F,U+7BAA,U+7BAC,U+7F0D,U+80DD,U+80FC,U+8132,U+815A,U+816D,U+8228,U+82CC,U+83EA,U+84C1,U+8722,U+876E,U+87E5,U+8919,U+8BCC,U+8BDF,U+8BE8,U+8D36,U+8F9A,U+90B4,U+90BA,U+90D0,U+948D,U+94AD,U+94BD,U+94D6,U+9507,U+956B,U+9604,U+9615,U+96B9,U+989A-989B,U+989E,U+9B3B,U+9C82,U+9CCA,U+9CD9,U+9E5A;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/119-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+54A6,U+5533,U+5550,U+5556,U+5627,U+567B,U+56D4,U+5A62,U+5CAC,U+5DB7,U+5F2D,U+623E,U+638A,U+64B8,U+66E9,U+67C1,U+67D2,U+67FD,U+6877,U+69C1,U+6A97,U+6BAA,U+6C18,U+6CEB,U+6CEE,U+6DE0,U+71F9,U+73B3,U+73D0,U+7511,U+75A5,U+75C8,U+75E7,U+7619,U+782C,U+7856,U+7ED0,U+7F1F,U+7F45,U+7FBF,U+7FE5,U+8052,U+80DB,U+8249,U+8315,U+8378,U+83AA,U+8538,U+859C,U+86CF,U+8BA7,U+8C30,U+8DB5,U+8E1F,U+8E2F,U+8E70,U+8F78,U+8F8B,U+8F8F,U+90C4,U+90FE,U+917D,U+9487,U+94CD,U+94EF,U+954A,U+96D2,U+9708,U+98A7,U+9A88,U+9AB6,U+9B47,U+9C9B,U+9E2C,U+9E5E,U+9F8A,U+9F8C;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/118-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E93,U+4EC4,U+4EF5,U+4F27,U+4F7B,U+4FE3,U+5080,U+5121,U+5208,U+52F0,U+5453,U+54D0,U+5549,U+55F5,U+571C,U+57B4,U+5807,U+58C5,U+59A4,U+59AF,U+5D03,U+5EBE,U+5FEA,U+6120,U+6221,U+64E2,U+68F0,U+6934,U+6998,U+6A84,U+6AA9,U+6B87,U+6BD6,U+6CD4,U+6ECF,U+70B7,U+7168,U+72D9,U+7352,U+75E8,U+7610,U+772D,U+784C,U+7850,U+789B,U+78F4,U+7B15,U+7B1E,U+7B24,U+7B5A,U+7BD9,U+7F71,U+80B1,U+81EC,U+8210,U+828A,U+828E,U+8369,U+83A8,U+83B4,U+85AE,U+86B4,U+8C07,U+8C47,U+8E85,U+8F87,U+948F,U+9609-960A,U+97EA,U+996C,U+9980,U+9991,U+9CC7,U+9E42,U+9E58,U+9ECD;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/113-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EE1,U+4FFE,U+525C,U+54E7,U+557E,U+5599,U+55D4,U+5623,U+5654,U+584D,U+58EC,U+59DD,U+5A32,U+5A75,U+5B71,U+5B73,U+5E5B,U+661D,U+6657,U+6867,U+6901,U+6B46,U+6C21,U+6C24,U+6CA3,U+6D39,U+6D63,U+71E7,U+72CD,U+72F0,U+7325,U+7350,U+7751,U+789C,U+7BE6,U+7EA3,U+7EB0,U+8171,U+821B,U+826E,U+82EB,U+830C,U+8314,U+843C,U+8564,U+8572,U+86A3,U+86C6,U+870D,U+8869,U+89D0,U+8B07,U+8BC2,U+8BF0,U+8C62,U+8D49,U+8D6D,U+8D94,U+8E3D,U+8E47,U+8E7F,U+9005,U+907D,U+9082,U+9088,U+90B0,U+94B9,U+94CB,U+9509,U+9512,U+9552-9553,U+9CB7,U+9E57,U+9E82;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/110-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EE8,U+4F22,U+4F43,U+502D,U+5482,U+55EF,U+5704,U+5958,U+599E,U+5CC4,U+603F,U+609A,U+61FF,U+622E,U+63AE,U+63CD,U+6410,U+6414,U+6448,U+680E,U+6954,U+6CA4,U+6E4E,U+74E4,U+753E,U+7548,U+75BD,U+75CD,U+7618,U+76F1,U+7791,U+7823,U+7827,U+79E3,U+7A95,U+7AA0,U+7B90,U+7BFE,U+7EC2,U+7F03,U+7F08,U+8174,U+82D5,U+852B,U+869D,U+87A8,U+8934,U+8BC5,U+8C15,U+8DC4,U+8DCE,U+8DDB,U+8E09,U+8E1D,U+8E42,U+8E49,U+8E8F,U+8F71-8F72,U+9097,U+90E2,U+90E6,U+90EF,U+9104,U+919A,U+91B4,U+938F,U+9563,U+9606,U+9974,U+9A90,U+9A9D,U+9CCD,U+9CDF;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/109-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F57,U+507B,U+53FB,U+54A7,U+54CC,U+5544,U+5594,U+55E8,U+564E,U+5785,U+57AD,U+5914,U+59AA,U+5A06,U+5AE1,U+5B40,U+5CCB,U+6078,U+607D,U+608C,U+60FA,U+621B,U+64D8,U+6710,U+6748,U+6772,U+69AB,U+6D2E,U+6E98,U+6FE0,U+7094,U+70E9,U+7119,U+723F,U+73C9,U+76C5,U+7708,U+77B3,U+7893,U+7949,U+7A14,U+7F04,U+828D,U+82C4,U+82F7,U+832D,U+840B,U+8438,U+86F0,U+8782,U+87E0,U+8839,U+8913,U+891B,U+8941,U+8A07,U+8BCB,U+8C11,U+8C29,U+8C32,U+8DFA,U+9004,U+9036,U+90DC,U+950F,U+9573,U+972D,U+97EB,U+988C,U+98A6,U+9977,U+997D,U+9E20,U+9F3E;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/107-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4FF3,U+500F,U+504E,U+5457,U+549B,U+54D2,U+558B,U+55D6,U+565C,U+57A9,U+5AE6,U+5B6A,U+5B93,U+5C99,U+5CC1,U+5FCF,U+6014,U+60C6,U+60DA,U+60F4,U+621F,U+62C8,U+631B,U+631E,U+6635,U+6641,U+67B7,U+695D,U+6D35,U+6DD9,U+6DEC,U+6F09,U+6F66,U+6F8D,U+6FC9,U+75C9,U+77DC,U+7800,U+782D,U+783C,U+78EC,U+7980,U+7B95,U+7C0C,U+7C41,U+7CC5,U+807F,U+8198,U+8537,U+8671,U+86A4,U+86F9,U+8737,U+873B,U+8815,U+8936,U+8BC3,U+8C0C,U+8E31,U+8E76,U+90D7,U+9485,U+94DB,U+9542,U+9549,U+95FE,U+970E,U+9968,U+996F,U+9984,U+9ACB,U+9E49,U+9E66;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/106-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F5A,U+4F8F,U+4FDF,U+52BE,U+5420,U+5499,U+54C6,U+55BD,U+567C,U+568E,U+5768,U+59F9,U+5A11,U+5BB8,U+5C15,U+5FD0-5FD1,U+6006,U+63E9,U+655D,U+6619,U+67E9,U+684E,U+688F,U+696B,U+69B7,U+6C26,U+6D43,U+6E6E,U+6E9F,U+6FC2,U+72C8,U+7566,U+7579,U+75E2,U+75FC,U+762A,U+7638,U+7678,U+76C2,U+76F9,U+77CD,U+7BDD,U+7CB3,U+7F19,U+80ED,U+8360,U+86CE,U+8BD8,U+8BE9,U+8C0F,U+8D5D,U+8D73,U+8FE4,U+9041,U+94A1,U+94C4,U+94C9,U+94E7,U+9503,U+9517,U+9537,U+9616,U+96C9,U+96F3,U+9739,U+9753,U+98D2,U+98DA,U+9B03,U+9C85,U+9CA8,U+9CAB;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/105-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EC9,U+501C,U+50A9,U+542E,U+5486,U+552C,U+556C,U+577B,U+5B17,U+5D3D,U+5D4A,U+5D82,U+5E1B,U+5EA5,U+5FD6,U+5FFF,U+60AF,U+60B4,U+612B,U+6194,U+61CA,U+64B5,U+65CC,U+664C,U+665F,U+6773,U+6845,U+6D5C,U+6EF9,U+6F78,U+714A,U+7337,U+74F4,U+7572,U+7762,U+77FD,U+795F,U+7B20,U+7BA9,U+7CBD,U+7EC9,U+7EF6,U+7F44,U+7F54,U+800B,U+809B,U+816E,U+817C,U+81C0,U+8392,U+83A0,U+8424,U+84AF,U+869C,U+8713,U+87C0,U+87CB,U+8821,U+89D1,U+8BB9,U+8F7C,U+9052,U+905B,U+9095,U+916A,U+92AE,U+9602,U+9621,U+9631,U+9A81,U+9EBE,U+9F10,U+9F8B;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/104-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F0E,U+4F64,U+510B,U+51A2,U+527D,U+5506,U+5511,U+5522,U+55B3,U+5639,U+5693,U+572A,U+5892,U+5B7D,U+5D34,U+5E1A,U+6035,U+60BB,U+61E6,U+61F5,U+6248,U+62A1,U+62D7,U+637B,U+65CE,U+66B9,U+6777,U+6787,U+693D,U+6994,U+6A35,U+6D8E,U+6F2A,U+704F,U+70EC,U+7118,U+724D,U+733E,U+73B7,U+7428,U+7837,U+78B4,U+7A1E,U+7BAB,U+7C7C,U+7CDC,U+7F94,U+8004,U+8019,U+80C4,U+8146,U+81FC,U+81FE,U+830F,U+8365,U+8385,U+8718,U+8D32,U+8D53,U+8DF7,U+8F95,U+909D,U+90C5,U+911E,U+9122,U+919B,U+9492,U+94B5,U+94BC,U+9511,U+9536,U+998B,U+9A9E;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/103-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E15,U+4E2B,U+4EB3,U+51BC,U+52D0,U+53FD,U+5429,U+54AF,U+55D2,U+55E6,U+561F,U+5659,U+5662,U+5992,U+59A9,U+5A76,U+5AE3,U+5E7A,U+5F0B,U+5F77,U+6026,U+6063,U+60D8,U+60EE,U+6376,U+652B,U+65D6,U+6666,U+6684,U+67DE,U+692D,U+6B59,U+6D54,U+6DD6,U+6EB4,U+7172,U+71B9,U+728A,U+7396,U+73CF,U+742C,U+742E,U+74EE,U+7525,U+753A,U+75D4,U+765C,U+768E,U+777D,U+7825,U+79ED,U+7B06,U+7F30,U+7F42,U+80AE,U+81C6,U+822B,U+832F,U+8340,U+8717,U+87FE,U+8902,U+8C12,U+8E7C,U+8FAB,U+948E,U+949A,U+94C6,U+94F1,U+956F-9570,U+99A5;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/102-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+536F,U+53A5,U+541D,U+5494,U+5520,U+553E,U+557B,U+55E1,U+55F7,U+5773,U+587E,U+5C8C,U+5CAB,U+5CB7,U+5D58,U+5EFF,U+5F89,U+5FA8,U+6005,U+6115,U+618E,U+64DE,U+6538,U+6631,U+6636,U+6654,U+67D8,U+6C69,U+6CE0,U+6DDE,U+6F15,U+7266,U+7329,U+7425,U+7455,U+7519,U+75B5,U+7656,U+795A,U+7A79,U+7B3A,U+7BB4,U+7BE1,U+7CBC,U+7F8C,U+7FF1,U+82A5,U+82AA,U+82DE,U+835E,U+854A,U+8568,U+85B0,U+86E4,U+8845,U+88F1,U+8D58,U+8DBE,U+9035,U+9149,U+9157,U+95EB,U+95F0,U+9611,U+9642,U+968D,U+9706,U+97ED,U+988A,U+98E8,U+9CDD,U+9EDD;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/101-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F2B,U+4FAC,U+5043,U+5140,U+5243,U+531D,U+5492,U+54A4,U+54AA,U+54CE,U+55C5,U+5608,U+5636,U+563B,U+5811,U+58D5,U+5A29,U+5A6A,U+5A7A,U+5AC9,U+5B95,U+5C49,U+5D02,U+5F29,U+5F9C,U+60EC,U+637A,U+6390,U+63B0,U+65EF,U+677C,U+6979,U+6C74,U+6CAE,U+6D95,U+6DE6,U+6DFC,U+6F29,U+70C3,U+715C,U+7317,U+731D,U+73E9,U+7490,U+75DE,U+7691,U+7729,U+783E,U+787C,U+7ABF,U+7B4F,U+7B8D,U+7BD3,U+7F1C,U+7FCE,U+810D,U+8343,U+8364,U+836A,U+853A,U+8543,U+8559,U+8C82,U+90A1,U+94C2,U+9619,U+970F,U+9A77,U+9AA1,U+9E2F,U+9E33,U+9E44;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/100-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+5055,U+5156,U+53AE,U+53F1,U+5431,U+547B,U+54FD,U+5509,U+563F,U+57A0,U+57C2,U+59E3,U+5B62,U+5E44,U+6043,U+60B8,U+60F0,U+630E,U+63A3,U+63AC,U+6525,U+65EE,U+67B8,U+683E,U+6886,U+68B5,U+6963,U+6988,U+6B9A,U+6C8C,U+6CEF,U+6DC5,U+6E1A,U+6EA7,U+7096,U+7131,U+7166,U+740F,U+74EF,U+7663,U+77FE,U+78D0,U+7B60,U+7B75,U+7EDB,U+7FB2,U+7FB9,U+8317,U+85B9,U+8715,U+8884-8885,U+88E8,U+8983,U+8BE1,U+8C1F,U+8C27,U+8C5A,U+8F98,U+9074,U+93D6,U+949D,U+94B4,U+94E3-94E4,U+9556,U+9893,U+9A87,U+9A8A,U+9E5C,U+9E9D;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/99-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4FD0,U+51BD,U+535E,U+542D,U+545B,U+548E,U+54AB,U+5600,U+5618,U+574D,U+579B,U+57B8,U+586C,U+58F9,U+5BA6,U+5C4E,U+5C96,U+5CE5,U+5F99,U+6059,U+60ED,U+61A9,U+62A8,U+62FD,U+642A,U+64A9,U+64AE,U+64B7,U+66F3,U+69DF,U+6AAC,U+6C76,U+6D52,U+6DB8,U+6FE1,U+736D,U+76BF,U+76D4,U+7728,U+776C,U+77F8,U+7A37,U+7A92,U+7AFA,U+7CEF,U+7FE1,U+808B,U+81C3,U+8431,U+84DF,U+8511,U+8638,U+86C0,U+8822,U+892A,U+8BA5,U+8BE0,U+8C1A,U+8E0C,U+8E74,U+8E87,U+8FC2,U+8FE6,U+900D,U+9068,U+90E7,U+9522,U+9A6E,U+9E3E,U+9E6D,U+9EDB;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/98-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F58,U+5323,U+54FC,U+5567,U+56F1,U+56FF,U+573B,U+5993,U+5996,U+59D7,U+5B7A,U+606C,U+6249,U+62ED,U+6342,U+6402,U+6413,U+659F,U+667E,U+67E0,U+6B86,U+6C50,U+6C5E,U+6C85,U+6CDE,U+6D19,U+6DA7,U+6E25,U+6E4D,U+6EC1,U+6F31,U+6F7A,U+6FA7,U+72E1,U+7315,U+73C0,U+73C2,U+7601,U+768B,U+77A0,U+783A,U+78FA,U+7977,U+80E5,U+80EB,U+812F,U+8235,U+82D4,U+8309,U+8469,U+84BF,U+8882,U+8892,U+8BD9,U+8BE7,U+8DDA,U+8E52,U+90AC,U+90B3,U+9119,U+94D0,U+94E2,U+965B,U+9981,U+998D,U+998F,U+9A7F,U+9B13,U+9C9F,U+9E43,U+9E92;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/97-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E56,U+4F6C,U+4F70,U+4FE8,U+5014,U+524C,U+5315,U+549A,U+556A,U+5669,U+595A,U+598D,U+5E4C,U+5EB6,U+602F,U+607A,U+620C,U+62C4,U+6345,U+6396,U+6400,U+6487,U+64AC,U+6556,U+65A1,U+6D31,U+6D93,U+6DAE,U+6E5F,U+6F5E,U+701B,U+70AB,U+717D,U+71A8,U+7252,U+72C4,U+73AE,U+752D,U+75A4,U+772F,U+77B0,U+7B71,U+7B94,U+7F28,U+8110,U+814C,U+828B,U+83C1,U+84D3,U+84E6,U+86DB,U+86FE,U+8757,U+88A4,U+88F3,U+8BFD,U+8C24,U+8D4A,U+8D4E,U+8D66,U+8F76,U+90B8,U+9131,U+94FF,U+9535,U+96F9,U+9774,U+9AB8,U+9E8B,U+9EEF;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/96-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E98,U+4FA5,U+5364,U+53E8,U+5406,U+54E6,U+54EE,U+5583,U+55E3,U+5944,U+59CA,U+5A7F,U+5F1B,U+608D,U+60CB,U+62F4,U+6382,U+63C9,U+645E,U+6593,U+6615,U+6805,U+6A80,U+6B83,U+6C30,U+6CAD,U+6DBF,U+6E85,U+6F7C,U+72B7,U+72E9,U+73BA,U+73D1,U+7435,U+745A,U+74E2,U+7599,U+759F,U+7629,U+7B19,U+7CB1,U+7CE0,U+7EF7,U+7F2B,U+7F81,U+8148,U+8165,U+819B,U+81BA,U+82AE,U+82B7,U+8338,U+837C,U+8393,U+8712,U+873F,U+874E,U+8783,U+8859,U+8BB7,U+8F8A,U+8FE5,U+912F,U+9163,U+94A8,U+94C0,U+955B,U+9C7F,U+9CA4,U+9E35;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/95-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E10,U+4F3A,U+4F5F,U+4F88,U+504C,U+52FA,U+5471,U+54DF,U+557C,U+55DC,U+5983,U+5A13,U+5B09,U+61A7,U+61AC,U+62A0,U+62EE,U+63EA,U+66E6,U+67DA,U+68A2,U+69AD,U+6A90,U+6BE1,U+6CB1,U+6CF1,U+6DC6,U+6E0D,U+6E3A,U+6EBA,U+71EE,U+7436,U+747E,U+7487,U+7504,U+752C,U+75CA,U+761F,U+7785,U+77A5,U+77BF,U+78D5,U+7934,U+79A7,U+7C95,U+7ECA,U+8046,U+82D3,U+8301,U+831C,U+83BA,U+853C,U+8654,U+8925,U+8BFF,U+8C1B,U+8C2C,U+8D61,U+8FF8,U+91DC,U+9539,U+954C,U+9550,U+962A,U+9685,U+988D,U+9975,U+9CB8,U+9E25,U+9E4A;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/94-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EC3,U+4F97,U+543C,U+545C,U+5480,U+5495,U+5815,U+5919,U+5955,U+59E5,U+5A34,U+5BD0,U+5C94,U+5DC5,U+5EB5,U+5F3C,U+60E6,U+61CB,U+62E7,U+634E,U+6479,U+6482,U+664F,U+672D,U+675E,U+6868,U+695E,U+6DA3,U+6DC7,U+6E43,U+6F3E,U+6F88,U+6FEE,U+70D9,U+722A,U+7409,U+7459,U+748B,U+759A,U+75A1,U+7738,U+796F,U+7B03,U+7BF1,U+7C38,U+7EAD,U+7F9A,U+7FCC,U+8237,U+8398,U+83E0,U+86DF,U+891A,U+8BB4,U+8C0D,U+8C19,U+8DB4,U+8E1E,U+8E6C,U+8F84,U+901E,U+90F4,U+94B3,U+94E8,U+9504,U+954D,U+9985,U+9A6F,U+9AA5;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/93-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EA5,U+4F36,U+4F84,U+501A,U+5201,U+54C7,U+5632,U+5676,U+56B7,U+5742,U+57A2-57A3,U+58D1,U+592D,U+5B70,U+5BF0,U+5C41,U+5CE6,U+5D69,U+5F95,U+604D,U+618B,U+62CE,U+631F,U+660A,U+6809,U+68F1,U+68FA,U+693F,U+6A71,U+6B89,U+6BD9,U+6D85,U+6DAA,U+73F2,U+749E,U+75D2,U+75EB,U+766B,U+773A,U+77AA,U+795B,U+7A20,U+7AA5,U+7B28,U+7B50,U+7EC5,U+7EF0,U+7F0E,U+7F2E,U+8098,U+80E7,U+8238,U+8299,U+82CE,U+8426,U+8475,U+871A,U+8BE3,U+8BEC,U+8C06,U+8DE4,U+8E66,U+9083,U+9165,U+91C9,U+9532,U+95FA,U+9704;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/92-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EA2,U+5029,U+516E,U+5321,U+53E9,U+56BC,U+56E4,U+5703,U+5A05,U+5A25,U+5BDD,U+5C79,U+5C91,U+5CED,U+6055,U+6123,U+62D9,U+634D,U+6452,U+64D2,U+6726,U+6942,U+6995,U+69B4,U+6BCB,U+6BD3,U+6C40,U+6CF8,U+6E0E,U+6E44,U+7099,U+70FD,U+7184,U+733F,U+749C,U+7620,U+7693,U+778E,U+78BE,U+7948,U+7A96,U+7B77,U+7EE2,U+7EFD,U+7F79,U+80F3,U+81E7,U+837B,U+83BD,U+83CF,U+85D5,U+85DC,U+888D,U+8BF2,U+8F97,U+94B0,U+94F5,U+956D,U+95F5,U+9668,U+9698,U+96BD,U+9773,U+997A,U+9A74,U+9A8B,U+9CC4,U+9CCC;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/91-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+51DB,U+5228,U+527F,U+5288,U+5450,U+5501,U+5729,U+575E,U+5A36,U+5A77,U+5A9B,U+5AB2,U+5FFB,U+60EB,U+60F6,U+6151,U+61A8,U+620D,U+6273,U+6289,U+62C7,U+6756,U+6862,U+68E3,U+69CC,U+6A44,U+6A59,U+6CBD,U+6CFE,U+6F8E,U+7095,U+70BD,U+70E8,U+715E,U+71CE,U+7235,U+7239,U+74A8,U+76CF,U+776B,U+7852,U+797A,U+79BA,U+79C3,U+7D6E,U+7F24,U+7F2D,U+818A,U+82B8,U+8339,U+8386,U+8747,U+88F4,U+8912,U+8C0E,U+8D31,U+8D48,U+8E4A,U+8F99,U+8FE9,U+914C,U+952F,U+96CD,U+96EF,U+9713,U+97EC,U+996A,U+9CBB;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/90-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4FAE,U+5189,U+5195,U+5484,U+5490,U+54C9,U+54E9,U+56A3,U+589F,U+5A04,U+5BC7,U+5CD9,U+5D0E,U+5E3C,U+5E87,U+5F64,U+6096,U+627C,U+6363,U+63B7,U+6518,U+66AE,U+6789,U+6829,U+6866,U+6893,U+6A1F,U+6C13,U+6CD3,U+6CD7,U+6D9F,U+6EA5,U+6EE6,U+6F2F,U+701A,U+709C,U+70AF,U+70DB,U+72F8,U+745C,U+7480,U+74A7,U+79BE,U+79C6,U+79F8,U+7A8D,U+7AFF,U+7CD9,U+7EEE,U+7FD8,U+800D,U+8151,U+82C7,U+82DB,U+8611,U+868C,U+8BBD,U+8D3B,U+8E35,U+9017,U+918B,U+94CE,U+951A,U+9672,U+9992,U+9A79,U+9CD7,U+9E93;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/89-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4FEF,U+50A3,U+51F3,U+53ED,U+5543,U+5578,U+55D3,U+5A23,U+5A9A,U+5AC2,U+5AD6,U+5C2C,U+5C34,U+5CB1,U+5FE1,U+5FF1,U+6064,U+606A,U+60F9,U+6252,U+62C2,U+62EF,U+634F,U+6361,U+63E3,U+6495,U+6984,U+6BA1,U+6C90,U+6D5A,U+6DCC,U+6E2D,U+6F13,U+6FA1,U+7011,U+71A0,U+7280,U+745B,U+76B1,U+76CE,U+7736,U+781A,U+789F,U+7941,U+7A98,U+7B1B,U+8116,U+8205,U+832C,U+8335,U+8446,U+846B,U+8587,U+8682,U+868A,U+88D8,U+8C41,U+8D3C,U+8DEA,U+8EAC,U+8F8D,U+8FE2,U+94F2,U+97A0,U+9A6D,U+9A85,U+9E26;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/88-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E4D,U+4E5E,U+533E,U+548B,U+54D7,U+560E,U+5830,U+58A9,U+59E8,U+5A07,U+5A3C,U+5B5A,U+5CE8,U+5CEA,U+5F87,U+601C,U+6177,U+62E3,U+62F1,U+6512,U+6577,U+65F7,U+6627,U+6714,U+67FF,U+6977,U+69BB,U+6A31,U+6B7C,U+6C72,U+6C79,U+6C81,U+6C93,U+6EC7,U+6F62,U+707C,U+7281,U+7357,U+75EA,U+7682,U+77D7,U+7A9C,U+7BF7,U+7C07,U+7EAB,U+7EDA,U+7F9E,U+7FDF,U+7FE9,U+803D,U+80B4,U+8155,U+82B9,U+82DF,U+8304,U+83B9,U+86D9,U+8862,U+889C,U+8BB6,U+8DCB,U+8E44,U+90F8,U+948A,U+9661,U+9761,U+9A8F;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/87-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+50DA,U+515C,U+51A4,U+5254,U+53EE,U+5435,U+5587,U+55A7,U+5760,U+576F,U+5777,U+5BB5,U+5BC5,U+5BDE,U+5C7F,U+5E18,U+5F57,U+5F5D,U+625B,U+6401,U+6467,U+64C2,U+6590,U+65A7,U+67D1,U+68D8,U+68E0,U+6930,U+6960,U+69D0,U+6BB4,U+6C7E,U+6CA5,U+6D3C,U+6DF3,U+6F33,U+708A,U+70C1,U+70EB,U+70F9,U+7316,U+7405,U+742A,U+763E,U+7792,U+77F6,U+79E4,U+7A1A,U+7B5D,U+7C3F,U+7C9F,U+7F09,U+7F15,U+7F2A,U+865E,U+8BB3,U+8EAF,U+9050,U+914B,U+94EE,U+962E,U+9647,U+96CF,U+9716,U+9A7C,U+9AE6,U+9CD6;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/86-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EA8,U+4F51,U+4F63,U+4FA0,U+5018,U+508D,U+54D1,U+5598,U+57AE,U+5978,U+5A49,U+5AB3,U+5BE5,U+5C09,U+6021,U+631D,U+64BC,U+6643,U+66DD,U+68A7,U+68CD,U+6BD7,U+6DE4,U+6E1D,U+6ED5,U+6F4D,U+7130,U+71AC,U+73CA,U+7422,U+7426,U+745F,U+75AF,U+7737,U+7741,U+77A7,U+77EE,U+788C,U+79FD,U+7A3C,U+7EE5,U+7F38,U+8018,U+8038,U+804B,U+81FB,U+82AD,U+8354,U+835F,U+8367,U+88D9,U+88F9,U+89C5,U+8C34,U+8D81,U+8E72,U+901B,U+9091,U+90AF,U+9524,U+952D,U+9576,U+97F6,U+98A4,U+9A86,U+9E3D;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/85-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F7C,U+4F83,U+4FD1,U+4FFA,U+50BB,U+50FB,U+5162,U+5319,U+5413,U+57E0,U+59AE,U+5B9B,U+5C27,U+5DCD,U+5E90,U+5E9A,U+5F8A,U+5F98,U+60BC,U+6254,U+626F,U+631A,U+6320,U+6346,U+63BA,U+663C,U+66D9,U+67AB,U+6817,U+6986,U+6B49,U+6B6A,U+6CBE,U+6E9C,U+6ED4,U+7529,U+762B,U+7696,U+7901,U+7A57,U+7A9F,U+7B0B,U+7C7D,U+7EB6,U+7F20,U+7FA1,U+803F,U+82D1,U+8327,U+836B,U+839E,U+8403,U+8471,U+849C,U+84C9,U+8517,U+851A,U+8D9F,U+8E0A,U+8E22,U+902E,U+915D,U+946B,U+9523,U+9551,U+9ED4;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/84-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E53,U+4FDE,U+502A,U+51F0,U+52C9,U+532A,U+53A2,U+54C4,U+54E8,U+561B,U+5764,U+5885,U+58F6,U+5C39,U+5C82,U+5C90,U+5E37,U+5F6A,U+6073,U+6328,U+6454,U+65ED,U+66A8,U+6749,U+674F,U+6854,U+6BEF,U+6C82,U+6DA4,U+6DC4,U+6E5B,U+6F47,U+6FD2,U+70AC,U+7476,U+7554,U+76EF,U+7766,U+7784,U+780D,U+7838,U+79E7,U+8086,U+8292,U+829C,U+838E,U+83F1,U+857E,U+87F9,U+8C05,U+8D42-8D43,U+8DFB,U+8EBA,U+8F69,U+8F9C,U+90B5,U+90DD,U+94A7,U+94C5,U+960E,U+9976,U+99A8,U+9B41,U+9C8D,U+9E9F;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/83-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E52,U+4FCF,U+4FE9,U+4FED,U+50B2,U+52CB,U+5306,U+5349,U+5395,U+5580,U+572D,U+574E,U+5AE9,U+5B5C,U+5D14,U+5D2D,U+5E06,U+5E62,U+5ED6,U+5F6C,U+6127,U+61BE,U+62DA,U+6367,U+6380,U+638F,U+655E,U+67A3,U+6A0A,U+6B79,U+6C55,U+6C5B,U+6D9D,U+6DD1,U+6DEB,U+6E24,U+6F6D,U+707F,U+70B3,U+70E4,U+725F,U+7261,U+72EE,U+7433,U+7750,U+7779,U+78CB,U+7F05,U+7FE0,U+8042,U+832B,U+8695,U+88B1,U+88E4,U+8C2D,U+8D4C,U+8D63,U+8F67,U+90A2,U+90B1,U+9493,U+949E,U+978D,U+9B44,U+9F9A;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/82-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+2500,U+4FA3,U+5197,U+51A5,U+51AF,U+52AB,U+5384,U+5401,U+54B1,U+5564,U+5589,U+56DA,U+575F,U+57D4,U+594E,U+59D1,U+59EC,U+5A1F,U+5C9A,U+5DFE,U+5E27,U+5F08,U+6233,U+6296,U+62E6,U+62F7,U+6628,U+6664,U+67EC,U+6853,U+68F5,U+6C5D,U+6CE3,U+6DA9,U+6F9C,U+7078,U+7115,U+73B2,U+741B,U+743C,U+75F9,U+77A9,U+77E2,U+7D0A,U+821C,U+840D,U+84B2,U+8749,U+8774,U+886B,U+895F,U+8D3F,U+8F7F,U+8FC4,U+8FED,U+90B9,U+9102,U+9171,U+94C3,U+9530,U+95EF,U+9608,U+964B,U+9A84,U+9ABC;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/81-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F50,U+51C4,U+51CB,U+5239,U+532E,U+533F,U+548F,U+54AC,U+55FD,U+5A20,U+5B75,U+5BE8,U+5D16,U+5F66,U+6084,U+611A,U+63A0,U+65A9,U+65BC,U+6656,U+6687,U+673D,U+6795,U+67C4,U+6850,U+68AD,U+69A8,U+6A58,U+6C9B,U+6CA7,U+6D74,U+7334,U+73AB,U+7538,U+7600,U+7626,U+7A91,U+7AA6,U+7AE3,U+7CDF,U+7E82,U+7EE3,U+7F00,U+7F9F,U+8113,U+8389,U+8482,U+85C9,U+8910,U+8A79,U+8BEB,U+8C79,U+8D29,U+8D50,U+8E29,U+8E81,U+8EB2,U+950C,U+9525,U+9540,U+961C,U+96C0,U+97AD,U+9E4F;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/80-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E1E,U+4EC6,U+4ED5,U+5026,U+51D1,U+5225,U+522E,U+5308,U+5475,U+54ED,U+5565,U+57A6,U+598A,U+5A1C,U+5D29,U+5ECA,U+6020,U+620A,U+620E,U+62E2,U+63FD,U+6405,U+658B,U+662D,U+6B47,U+6C1F,U+6CB8,U+6E58,U+6F84,U+723D,U+739B,U+7470,U+777F,U+78CA,U+79B9,U+7C27,U+7CD5,U+7ECE,U+7ED1-7ED2,U+7FC5,U+817B,U+841D,U+8549,U+864F,U+8681,U+8944,U+8B6C,U+8BC0,U+8C0A,U+8C1C,U+906E,U+949B,U+94A6,U+94AE,U+95FD,U+96A7,U+9885,U+9890,U+9896,U+9965,U+997F,U+9A9A,U+9F9F;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/79-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E38,U+4E9F,U+4F1E,U+4F8D,U+4FCA,U+51FF,U+540F,U+541F,U+5455,U+54C0,U+558A,U+566C,U+5BE1,U+5C51,U+5C60,U+5C6F,U+5F13,U+5F27,U+6094,U+6241,U+6284,U+632A,U+633D,U+655B,U+658C,U+6816,U+68D5,U+6905,U+6CA6,U+6CFC,U+6E32,U+70D8,U+70F7,U+7109,U+714E,U+718F,U+72E0,U+7410,U+780C,U+7CA5,U+7EDE,U+7FF0,U+8026,U+803B,U+8087,U+809A,U+80F1,U+8302,U+8346,U+85AF,U+86EE,U+8A93,U+8C26,U+8C6B,U+915A,U+9170,U+94EC,U+96C1,U+973E,U+9877,U+9882,U+997C,U+9CDE,U+9E2D;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/78-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EC7,U+51B6,U+5203,U+5351,U+54B8,U+5507,U+5566,U+5984,U+59DA,U+5BA0,U+5C38,U+5E05,U+5F0A,U+60D5,U+60DF,U+6124,U+6155,U+621A,U+6247,U+62D0,U+635E,U+640F,U+6614,U+6655,U+67EF,U+6808,U+68A8,U+6912,U+6BB7,U+6CAA,U+6CBC,U+6D3D,U+6DA1,U+6E34,U+6E89,U+716E,U+7194,U+72AC,U+785D,U+7940,U+79C9,U+7B52,U+7BC6,U+7F1A,U+80BD,U+819D,U+840E,U+859B,U+86C7,U+8700,U+8721,U+8877,U+88F8,U+8BCF,U+8D3E,U+8FB1,U+901D,U+916E,U+9177,U+917F,U+94BE,U+98D8,U+9E7F;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/77-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E11,U+4ED7,U+4FD8,U+50E7,U+5188,U+51F9,U+5320,U+5352,U+576A,U+584C,U+5962,U+5A18,U+5AC1,U+5C61,U+5DEB,U+5DF7,U+5E16,U+5ED3,U+606D,U+614C,U+6168,U+626D,U+62CC,U+6349,U+6674,U+6869,U+69DB,U+6C70,U+6D12,U+6DF9,U+6EA2,U+7199,U+75AE,U+75B9,U+76D2,U+78A7,U+78C5,U+79BD,U+7A3D,U+7A46,U+7EAC,U+7EF8,U+7F14,U+7FD4,U+80DA,U+8305,U+83C7,U+83E9,U+8427,U+88D4,U+8C23,U+8D2E,U+8FB0,U+90AA,U+90CA,U+916F,U+9175,U+9508,U+9541,U+95F8,U+96CC,U+971E,U+9738;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/76-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4ED1,U+4F3D,U+4FA8,U+5154,U+5179,U+5180,U+52FE-52FF,U+535C,U+5378,U+5415,U+543B,U+5446,U+5792,U+57AB,U+5986,U+59B9,U+5A46,U+5BB4,U+5BC2,U+5D1B,U+5E1C,U+5F17,U+60E8,U+62FE,U+6323,U+679A,U+6897,U+6CF3,U+6D51,U+6DAF,U+6DEE,U+72FC,U+7578,U+75F4,U+77BB,U+77EB,U+7898,U+7CA4,U+7CAA,U+7CB9,U+7EB1,U+7FC1,U+8000,U+8180,U+8328,U+840C,U+85E4,U+85E9,U+8650,U+8679,U+867E,U+8776,U+886C,U+8FA3,U+9489,U+94A9,U+9640,U+971C,U+987D,U+9E45,U+9E64;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/75-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E08,U+50F5,U+5265,U+537F,U+5389,U+538C,U+53A8,U+53D4,U+5440,U+5524,U+5CFB,U+5E7D,U+5F6D,U+6016,U+6068,U+6101,U+6170,U+6208,U+6251,U+633A,U+644A,U+65A5,U+6735,U+684C,U+6D47,U+6D4A,U+6D9B,U+6E23,U+6EE9,U+6F06,U+711A,U+714C,U+727A,U+72D0,U+752B,U+75D5,U+77AC,U+7897,U+7960,U+7AD6,U+7B3C,U+80D6,U+818F,U+8258,U+82A6,U+82EF,U+82F9,U+83CA,U+8513,U+8521,U+85FB,U+8D5A,U+8D74,U+8F70,U+904F,U+94A5,U+95F9,U+964C,U+970D,U+978B,U+9A73,U+9E70;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/74-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E22,U+5085,U+51F6,U+53DB,U+541E,U+54BD,U+54FA,U+5751,U+5824,U+59DC,U+5A03,U+5A31,U+5BB0,U+5D4C,U+5E15,U+5EB8,U+60A0,U+61C8,U+61D2,U+62AC,U+62B9,U+62F3,U+6324,U+6492,U+6572,U+6602,U+660F,U+6652,U+67A2,U+67AF,U+67CF,U+680B,U+6A61,U+6C6A,U+6C92,U+6CFB,U+6D4F,U+6DD8,U+70C2,U+731C,U+7574,U+75F0,U+7984,U+7EF5,U+7F62,U+8096,U+8273,U+82AC,U+82CD,U+830E,U+853D,U+871C,U+8D1E,U+8D2C,U+9063,U+90CE,U+95F7,U+9756,U+98A0,U+9A82,U+9B45;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/73-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EAD,U+4FA6,U+52A3,U+54B3,U+5582,U+5631,U+582A,U+5915,U+5948,U+59A8,U+5F26,U+6012,U+607C,U+6292,U+632B,U+65EC,U+6668,U+6691,U+6760,U+68B3,U+68D2,U+6BBF,U+6CAB,U+6CCA,U+6CEA,U+6E0A,U+6F58,U+7076,U+7092,U+72F1,U+730E,U+74E3,U+76FC,U+7A83,U+7EBA,U+7EF3,U+7F55,U+8036,U+804A,U+806A,U+80F0,U+81B3,U+8206,U+8236,U+83B2,U+8574,U+884D,U+8896,U+8D3A,U+8F9F,U+900A,U+9038,U+9502,U+9510,U+9709,U+9776,U+97E7,U+9A70,U+9AD3,U+9B54,U+9E3F;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/72-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E54,U+5077,U+5146,U+5256,U+529D,U+5366,U+53A6,U+5496,U+5784,U+592F,U+5937,U+5974,U+5CB3,U+5CE1,U+5F18,U+60DC,U+6109,U+626E,U+629B,U+64CE,U+64E6,U+676D,U+67DC,U+6813,U+68CB,U+6BC5,U+6C41,U+6D66,U+6EAF,U+6EE8,U+718A,U+71D5,U+722C,U+7237,U+7272,U+72ED,U+732B,U+7384,U+754F,U+7978,U+7A84,U+7AED,U+7B5B,U+7F06,U+80AA,U+813E,U+8231,U+829D,U+82BD,U+845B,U+84EC,U+8BDE,U+8E48,U+9022,U+90E1,U+94ED,U+9521,U+968B,U+96C7,U+97E6,U+9ECF;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/71-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E1B,U+4E7E,U+4E8F,U+51E4,U+51F8,U+52D8,U+5367,U+5439,U+543E,U+5561,U+5821,U+5858,U+5938,U+59D0,U+5BD3,U+5E10,U+5E3D,U+5E99,U+6028,U+60A6,U+62AB,U+62D6,U+62D8,U+6321,U+63A9,U+6478,U+64C5,U+6566,U+65A4,U+68DA,U+6B3A,U+6D69,U+6E83,U+6EAA,U+6F02,U+70AE,U+7709,U+77E3,U+78F7,U+7965,U+7985,U+7A9D,U+7BEE,U+7F50,U+8106,U+8247,U+848B,U+8881,U+888B,U+8BF5,U+8E0F,U+903C,U+94A0,U+9526,U+95EA,U+9600,U+966A,U+9972,U+9B3C,U+9ECE;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/70-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E18-4E19,U+51CC,U+51EF,U+524A,U+5251,U+5300,U+5353,U+5362,U+575D,U+5B5F,U+5CAD,U+5E7B,U+5F70,U+602A,U+604B,U+60E7,U+643A,U+6500,U+659C,U+6734,U+67F4,U+683D,U+6851,U+6876,U+68C9,U+690E,U+699C,U+6C83,U+6EDA,U+6EE5,U+72B9,U+73BB,U+7483,U+74DC,U+751C,U+7802,U+7891,U+7CCA,U+7F69,U+7FBD,U+80FA,U+814A,U+81ED,U+83B1,U+84C4,U+8F88,U+8FEA,U+903E,U+9065,U+9080,U+9189,U+94BB,U+94DD,U+9505,U+9699,U+96FE,U+9A91,U+9B42,U+9F0E;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/69-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F69,U+4FF1,U+5144,U+5151,U+5220,U+53F9,U+554A,U+55BB,U+5634,U+574A,U+57C3,U+5954,U+5960,U+5DE2,U+5E9E,U+5F25,U+5FCC,U+6350,U+642C,U+65F1,U+65FA,U+67F3,U+682A,U+6842,U+6C2E-6C2F,U+6C57,U+6C88,U+6CF5,U+6ECB,U+710A,U+72D7,U+74F7,U+755C,U+756A,U+796D,U+7BAD,U+80A9,U+810A,U+81A8,U+81C2,U+821F,U+827E,U+8352,U+83F2,U+8404,U+8461,U+846C,U+8702,U+88D5,U+8D2A,U+8D6B,U+8FBD,U+9042,U+9093,U+94F8,U+96B6,U+96D5,U+9971;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/68-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F2A,U+52DF,U+53C9,U+53E0,U+540A,U+5410,U+566A,U+57CB,U+5835,U+5939,U+59A5,U+59FB,U+59FF,U+5ACC,U+5B5D,U+5BF8,U+5F04,U+5F2F,U+5FCD,U+60D1,U+60E9,U+6148,U+6591,U+67D4,U+680F,U+69FD,U+6B20,U+6B67,U+6D46,U+6DC0,U+6F20,U+70EF,U+71E5,U+72C2,U+731B,U+75B2,U+76C6,U+76F2,U+775B,U+77E9,U+786B,U+795D,U+79D2,U+7A77,U+7EBD,U+80A2,U+817E,U+820C,U+8230,U+8428,U+88AD,U+8D24,U+8FC8,U+90C1,U+9601,U+97F5,U+9887,U+9E23,U+9F7F;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/67-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E32,U+4ED4,U+50AC,U+517D,U+51BB,U+52B2,U+5339,U+55B7,U+5893,U+58F3,U+59C6,U+5A74,U+5DE1,U+5FBD,U+5FE7,U+60AC,U+629A,U+62E8,U+62FC,U+641E,U+6447,U+64B0,U+6606,U+66FC,U+676F,U+6843,U+6CC4,U+6D8C,U+6DCB,U+70B8,U+70E6,U+7816,U+7845,U+7855,U+78B0-78B1,U+7A00,U+7A3B,U+7A74,U+7B4B,U+7F1D,U+7FFC,U+8058,U+80C1,U+8138,U+8170,U+817F,U+8361,U+864E,U+8680,U+87BA,U+8854,U+8C6A,U+8D64,U+8D76,U+8F9E,U+90ED,U+9988;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/66-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E27,U+4EA9,U+4ED9,U+4FAF,U+5076,U+5112,U+526A,U+52C3,U+559D,U+56CA,U+5733,U+575B,U+5951,U+5BBF,U+5C48,U+5E55,U+5FA1,U+5FD9,U+6212,U+62DC,U+649E,U+65C1,U+6653,U+67AA,U+68AF,U+6B23,U+6C1B,U+6C28,U+6C64,U+6CCC,U+6D78,U+6EDE,U+6EF4,U+70AD,U+7545,U+7586,U+75BC,U+76C8,U+76D7,U+788E,U+79E9,U+7A0D,U+7F8A,U+82B3,U+8D41,U+8D60,U+8E2A,U+8F89,U+8F90,U+90BB,U+9187,U+953B,U+9610,U+9655,U+9881,U+9E21,U+9F20,U+9F3B;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/65-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4F10,U+51C9,U+5200,U+5269,U+53D9,U+5782,U+5806,U+593A,U+59BB,U+5B55,U+5BAA,U+5BBE,U+5BC4,U+5BFA,U+5C18,U+5DE9,U+5EF7,U+5F7C,U+6052,U+6070,U+609F,U+60B2,U+6355,U+6377,U+6458,U+64A4,U+65E8,U+660C,U+6770,U+679D,U+6CC9,U+6E14,U+6E17,U+6F2B,U+732A,U+7434,U+745E,U+74F6,U+7720,U+7A3F,U+7D2B,U+7EB2,U+7EB9,U+84B8,U+852C,U+8BF1,U+8C28,U+8D1D,U+8D62,U+8FA8,U+8FF7,U+90AE,U+90D1,U+9176,U+9499,U+9888,U+9EA6;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/64-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EF0,U+5021,U+5272,U+5398,U+5427,U+54E5,U+5609,U+5761,U+58E4,U+5949,U+5999,U+5B64,U+5B99,U+5BFF,U+5C16,U+5C4F,U+5EC9,U+5F79,U+62A2,U+62B1,U+6302,U+63D2,U+63ED,U+642D,U+6446,U+654C,U+6676,U+66F0,U+6746,U+6BC1,U+6C22,U+6D45,U+6EE4,U+7089,U+7238,U+7275,U+7B11,U+7C97-7C98,U+80A4,U+80C0,U+80CE,U+8212,U+8270,U+85AA,U+89C8,U+8C46,U+8D5E,U+8F9B,U+916C,U+94FA,U+9635,U+96C5,U+9A7B,U+9AA4,U+9B4F,U+9E1F;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/63-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4ED3,U+5192,U+5237,U+52D2,U+5348,U+5375,U+5531,U+573E,U+5783,U+5B85,U+5C1D,U+5C3A,U+5E86,U+6069,U+6108,U+614E,U+6234,U+626B,U+6270,U+62C6,U+63F4,U+65CB,U+6696,U+66F9,U+6885,U+6CF0,U+6D2A,U+6DFB,U+704C,U+7070,U+7267,U+78E8,U+7A97,U+7AF9,U+8083,U+80E1,U+80F8,U+820D,U+84DD,U+8870,U+8DCC,U+8F68,U+8FDF,U+9003,U+9006,U+90A6,U+94DC,U+9501,U+950B,U+95F2,U+9614,U+9675-9676,U+9686,U+96EA,U+987F;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/62-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E39,U+4E43,U+4E95,U+4EFF,U+52E4,U+5766,U+58EE,U+594F,U+5976,U+5B8F,U+5CB8,U+5D07,U+5F1F,U+5FD8,U+60CA,U+61C2,U+62D2,U+62D4,U+6398,U+6469,U+6562,U+656C,U+6670,U+6717,U+675C,U+6846,U+6A2A,U+6F0F,U+6FB3,U+73CD,U+758F,U+7686,U+7ADF,U+7BB1,U+7EB5,U+8015,U+80BE,U+8154,U+8179,U+81E3,U+8350,U+83AB,U+8463,U+8A89,U+8BC8,U+8C8C,U+8D4B,U+8DC3,U+8DD1,U+8F74,U+8F96,U+8FA9,U+97E9,U+996D,U+9970,U+9EBB;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/61-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E4C,U+4F0A,U+4F19,U+5141,U+51B0,U+51FD,U+520A,U+5409,U+5434,U+54A8,U+54C8,U+5708,U+585E,U+5899,U+58A8,U+5987,U+5C3E,U+5CA9,U+5F90,U+5F92,U+5FFD,U+6089,U+624E,U+6316,U+6389,U+641C,U+664B,U+6697,U+6731,U+67F1,U+6CE1,U+6D1B,U+6D1E,U+6D59,U+6D6A,U+6D6E,U+6D82,U+6DE1,U+6E21,U+73E0,U+74E6,U+7518,U+8010,U+80AF,U+80C3,U+80C6,U+80F6,U+8584,U+8BAF,U+8C10,U+8C37,U+8FEB,U+906D,U+9897,U+9ED8;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/60-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E01,U+4E1D,U+4EC1,U+4EF2,U+4F0D,U+4F0F,U+4F26,U+4F38,U+503E,U+51E1,U+5385,U+54F2,U+5723,U+58C1,U+5988,U+5BD2,U+5E84,U+5FE0,U+6050,U+622A,U+6291,U+65D7,U+6682,U+6881,U+6CFD,U+6D25,U+6DB5,U+6ED1,U+70BC,U+7206,U+76DF,U+79E6,U+7C4D,U+7EA4,U+8033,U+808C,U+8102,U+811A,U+817A,U+82AF,U+866B,U+8BE6,U+8C0B,U+8C31,U+8D21,U+8D4F,U+8D56,U+8DF3,U+8FCE,U+8FD4,U+903B,U+9910,U+9A97,U+9C81;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/59-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E73,U+4F2F,U+4F73,U+5012,U+51ED,U+52C7,U+541B,U+5428,U+552F,U+5851,U+5B87,U+5CF0,U+5F03,U+5FC6,U+6015,U+6062,U+6263,U+62BC-62BD,U+62CD,U+6768,U+68A6,U+68B0,U+68EE,U+6B96,U+6BEB,U+6CE5,U+6D17,U+6EB6,U+6F6E,U+706F,U+7262,U+76FE,U+7761,U+77DB,U+79D8,U+7C92,U+7CAE,U+7ED8,U+809D,U+8150,U+8377,U+8499,U+8857,U+88C2,U+8C01,U+8D75,U+8FF9,U+9075,U+9192,U+9677,U+9694,U+989C,U+9A71;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/58-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E3D,U+4E58-4E59,U+4FC4,U+517C,U+51AC,U+53EC,U+5740,U+5750,U+5854,U+594B,U+5965,U+5B59,U+5DE7,U+5E78,U+60E0,U+62D3,U+6491,U+65E6,U+66FF,U+670B,U+6B32,U+6D01,U+6D53,U+6E20,U+6E7F,U+706D,U+70E7,U+7164,U+73A9,U+7537,U+7624,U+76D0,U+76DB,U+788D,U+78C1,U+7EA0,U+7EAF,U+7EEA,U+7F18,U+7F34,U+810F,U+8863,U+8BD1,U+8BDA,U+8BFA,U+8C22,U+8F85-8F86,U+8FC5,U+9012,U+91CE,U+9707;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/57-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E71,U+4EAE,U+4F1F,U+4FD7,U+51C0,U+51DD,U+523A,U+5706,U+590F,U+591C,U+5C3F,U+5C4A,U+5C65,U+5C97,U+5C9B,U+5DDD,U+5E97,U+5F39,U+6276,U+654F,U+66B4,U+672B,U+6740,U+6CBF,U+6DA8,U+6E7E,U+7259,U+7389,U+77FF,U+79CB,U+7B79,U+7C89,U+7FFB,U+80A0,U+80BF,U+80DC,U+821E,U+82D7,U+8BBC,U+8D26,U+8D34,U+8D54,U+8FC1,U+95ED,U+9634,U+96E8,U+96F7,U+9875-9876,U+9A76,U+9A7E,U+9C9C,U+9F84;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/56-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4FB5,U+500D,U+51A0,U+586B,U+59D3,U+5A5A,U+5A92,U+5B81,U+5C1A,U+5C3C,U+5E2D,U+5E9F,U+5F69,U+5F7B,U+6000,U+6076,U+6167,U+626C,U+6298,U+6311,U+632F,U+6444,U+65E7,U+665A,U+6865,U+695A,U+697C,U+6B22,U+6B8B,U+6C0F,U+6C9F,U+6DA6,U+70DF,U+71C3,U+725B,U+7591,U+7687,U+793C,U+7EB8,U+7ED5,U+7F72,U+80BA,U+8986,U+8D25,U+8D5B,U+904D,U+9274,U+949F,U+955C,U+95FB,U+9732,U+9F50;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/55-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E4F,U+4EA1,U+4EA6,U+4F34,U+4F5B,U+504F,U+5377,U+539A,U+547C,U+559C,U+5B8B,U+5BAB,U+5BFB,U+5C0A,U+5C4B,U+5FAA,U+60A8,U+60EF,U+6293,U+62FF,U+6863,U+6B4C,U+6BD5,U+6C38,U+707E,U+70C8,U+7126,U+7956,U+7981,U+79C0,U+7A7F,U+7EB7,U+8017,U+8089,U+80A5,U+8109,U+8239,U+8336,U+8363,U+83CC,U+83DC,U+86CB,U+89E6,U+8BF8,U+8C13,U+8D35,U+8DE8,U+963B,U+9646,U+96C4,U+9C7C;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/54-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EEA,U+521A,U+5238,U+52AA,U+53EB,U+5448,U+574F,U+5947,U+5A01,U+5B54,U+5B9C,U+5BBD,U+5DF4,U+5E45,U+5EA7,U+62B5,U+62DF,U+62E5,U+63CF,U+6620,U+675F,U+6B8A,U+6BDB,U+6C89,U+6C99,U+6CDB,U+6DF7,U+6F5C,U+7530,U+764C,U+786C,U+78B3,U+79C1,U+79DF,U+7CD6,U+7E41,U+7F13,U+819C,U+8BBF,U+8BCA,U+8BE2,U+8D2F,U+8F6E,U+8F91,U+9014,U+94A2,U+963F,U+96F6,U+996E,U+9986,U+9F13;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/53-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E45,U+4F11,U+4FA7,U+507F,U+5175,U+518C,U+51B7,U+5218,U+5267,U+5356,U+53F6,U+5417,U+542F,U+5510,U+5956,U+5B63,U+5C01,U+5C24,U+5E8A,U+5F31,U+6162,U+620F,U+62DB,U+6551,U+677E,U+6C27,U+6C60,U+6D0B,U+6D3E,U+6E2F,U+6E56,U+7075,U+708E,U+724C,U+76D8,U+7D2F,U+7F29,U+7F5A,U+82E6,U+88C1,U+8BEF,U+8D8B,U+8DA3,U+8DDD,U+8DDF,U+900F,U+9152,U+9648,U+9690,U+987E;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/52-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E4E,U+5170,U+51B2,U+5211,U+526F,U+5361,U+5382,U+53F3,U+592B,U+5957,U+5979,U+5DE8,U+5E0C,U+5E1D,U+5EF6,U+5F52,U+5F84,U+653B,U+6728,U+67B6,U+6B27,U+6C47,U+6D32,U+6E10,U+719F,U+7236,U+72AF,U+732E,U+7532,U+75DB,U+76D6,U+7B7E,U+7BC7,U+7ECD,U+7EE9,U+8131,U+85CF,U+8861,U+8B66,U+8BA2,U+8BA8,U+8D38,U+8F6F,U+94B1,U+94C1,U+9605,U+9759,U+987A,U+9AA8,U+9ED1;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/51-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E30,U+4F30,U+501F,U+50A8,U+52B1,U+535A,U+53CB,U+53E5,U+5403,U+5462,U+5473,U+5757,U+5802,U+5B88,U+5B97,U+5C81,U+5DE6,U+613F,U+638C,U+63E1,U+64AD,U+6563,U+6597,U+65C5,U+65E2,U+6C7D,U+767B,U+76AE,U+7801,U+7968,U+798F,U+7ADE,U+7AE5,U+7B14,U+80CC,U+822A,U+82CF,U+8349,U+8651,U+865A,U+8C08,U+8D2B,U+8D37,U+8FFD,U+9057,U+9644,U+9760,U+9999,U+9F99;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/50-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E5D,U+4E70,U+4F3C,U+503A,U+5047,U+505C,U+523B,U+5242,U+5343,U+5B9D,U+5BA3,U+5C04,U+5E01,U+5E2E,U+5E7C,U+5E93,U+600E,U+6025,U+627E,U+62C9,U+6388,U+6625,U+66F2,U+66FE,U+6742,U+6811,U+6B66,U+6D89,U+6DB2,U+75BE,U+7EFF,U+7F57,U+805A,U+8111,U+82E5,U+8457,U+867D,U+8FDD,U+9000,U+9010,U+9047,U+907F,U+9178,U+94FE,U+9519,U+9547,U+9891,U+98DE;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/49-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E03,U+4E91,U+4E9A,U+4EAB,U+4EB2,U+4ECD,U+4EE4,U+4F24,U+5178,U+51FB,U+534A,U+5370-5371,U+542C,U+54EA,U+552E,U+56F0,U+5EAD,U+5F85,U+6258,U+6269,U+6325,U+63AA,U+64CD,U+661F,U+671D,U+690D,U+6982,U+6BCD,U+6C49,U+6C61,U+6CE2,U+6F14,U+751A,U+77ED,U+7B26,U+7B51,U+7D27,U+7EC3,U+7EDD,U+7EFC,U+7F6A,U+80DE,U+9001,U+91CA,U+9488,U+952E;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/48-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E34,U+4E88,U+4EBF,U+4ED8,U+4EFD,U+4F59,U+516B,U+5224,U+5360,U+536B,U+5374,U+53E6,U+56FA,U+592E,U+5E95,U+6297,U+6362,U+63A2,U+671B,U+674E,U+677F,U+6B7B,U+6BD2,U+6CB9,U+706B,U+7231,U+7248,U+73ED,U+7533,U+7559,U+75C7,U+773C,U+7763,U+7AEF,U+7B54,U+7D22,U+7EA2,U+7EE7,U+8BD7,U+8D27,U+8D2D,U+8DF5,U+8F7B,U+8F7D,U+8F93,U+9636,U+9EC4;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/47-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E3E,U+4EAC,U+4ECB,U+53CC,U+542B,U+5438,U+56ED,U+5973,U+5B98,U+5BA4,U+5BCC,U+5BDF,U+5C14,U+5C3D,U+5C45,U+5DEE,U+5F02,U+5F55,U+5FAE,U+6279,U+62C5,U+635F,U+65E9,U+6B62,U+6CB3,U+6E29,U+6FC0,U+72EC,U+753B,U+75AB,U+79FB,U+7A33,U+7AD9,U+7EAA,U+7EB3,U+7F16,U+7F3A,U+822C,U+826F,U+89C9,U+8BC9,U+8BCD,U+8FB9,U+9633,U+9752,U+989D;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/46-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E50,U+4F4F,U+4FBF,U+4FC3,U+5019,U+50CF,U+514B,U+514D,U+516D,U+521D,U+53BF,U+5747,U+58EB,U+58F0,U+5BB3,U+5DDE,U+5EB7,U+5FD7,U+60A3,U+62E9,U+65AF,U+666E,U+6797,U+67D3,U+6C5F,U+6EE1,U+7565,U+77F3,U+7834,U+7A81,U+7B80,U+7C73,U+7EC8,U+80A1,U+827A,U+82F1,U+8865,U+89D2,U+8BAD,U+8BB2,U+8D70,U+8FDE,U+94F6,U+9500,U+969C;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/45-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E61,U+4EC5,U+4FEE,U+5065,U+5145,U+5174,U+51CF,U+5207,U+52B3,U+5426,U+56E2,U+575A,U+592A,U+5BA2,U+5BC6,U+5E8F,U+5F20,U+5F81,U+6267,U+627F,U+6392,U+6545,U+65CF,U+666F,U+667A,U+67D0,U+6B3E,U+6E38,U+7247,U+7AE0,U+7EDC,U+82B1,U+83B7,U+843D,U+8BB8,U+8D1F,U+8D22,U+8FDC,U+8FF0,U+961F,U+97F3,U+987B,U+9996,U+9A6C;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/44-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E14,U+4E25,U+4E89,U+4E92,U+5217,U+534E-534F,U+538B,U+53E4,U+5468,U+5584,U+56F4,U+591F,U+5931,U+5B69,U+5BA1,U+5C5E,U+5F80,U+5FF5,U+623F,U+62EC,U+6309,U+6750,U+70ED,U+7167,U+738B,U+7403,U+767D-767E,U+7840,U+79BB,U+7A0E,U+836F,U+8840,U+88C5,U+8BDD,U+8BF7,U+8D85,U+8DB3,U+914D,U+964D,U+9650,U+968F;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/43-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4EC0,U+4ECA,U+4F17,U+4F9D,U+5199,U+519B,U+51E0,U+52A9,U+52BF,U+53C8,U+53F7,U+544A,U+547D,U+571F,U+57F9,U+5934,U+59CB,U+59D4,U+5C40,U+5E72,U+5FB7,U+5FEB,U+6253,U+663E,U+6790,U+6838,U+7597,U+76CA,U+7701,U+771F,U+79F0,U+7EC7,U+7F6E,U+7FA4,U+878D,U+8BFB,U+8D8A,U+9002,U+9664,U+9769,U+9884,U+98DF;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/42-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E94,U+513F,U+518D,U+5212,U+529E,U+5347,U+5373,U+5386,U+53C2,U+54CD,U+57DF,U+5C42,U+5E03,U+5E26,U+5E7F,U+5E9C,U+6237,U+672A,U+6781,U+68C0,U+6BB5,U+6D88,U+72B6,U+795E,U+79EF,U+7A7A,U+7B56,U+7EA6,U+7EC6,U+7EED,U+7EF4,U+81F4,U+89C6,U+8A00,U+8BAE,U+8BC4,U+8BD5,U+8C61,U+901F,U+91C7,U+96BE;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/41-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E07,U+4F18,U+4F55,U+4F8B,U+5149,U+51B5,U+529F,U+5317,U+5357,U+53F0,U+53F2,U+56DE,U+56FE,U+5C71,U+5F8B,U+5FC5,U+628A,U+63A7,U+6599,U+65AD,U+6613,U+6751,U+6BCF,U+6D4B,U+6D77,U+6DF1,U+6E05,U+754C,U+76D1,U+7B97,U+7CBE,U+804C,U+8303,U+89C1,U+8BFE,U+8D23,U+8FD1,U+90A3,U+9632,U+9669;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/40-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E1C,U+4F4E,U+4F60,U+503C,U+515A,U+517B,U+5305,U+5668,U+5907,U+590D,U+5B57,U+5B83,U+5F15,U+5F71,U+6218,U+624D,U+6295,U+62A4,U+67E5,U+6821,U+6839,U+683C,U+6848,U+6B65,U+6CE8,U+76F4,U+7D20,U+7ED9,U+8001,U+8425,U+897F,U+8BA9,U+8BED,U+8D39,U+8F66,U+9009,U+9645,U+96C6,U+975E;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/39-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E16,U+4F9B,U+51B3,U+5219,U+522B,U+533B,U+53BB,U+53CD,U+53E3,U+53EA,U+56DB,U+57CE,U+5883,U+5B58,U+5B8C,U+5BB9,U+5C11,U+5DF1,U+6001,U+624B,U+62A5,U+653E,U+6A21,U+7387,U+793A,U+7EBF,U+8054,U+81F3,U+8272,U+89C2,U+8BB0,U+8BE5,U+8DEF,U+8EAB,U+8F6C,U+8FBE,U+9886,U+9A8C;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/38-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E13,U+4E24,U+4EF7,U+5143,U+5148,U+519C,U+51C6,U+53D6-53D7,U+53F8,U+540D,U+5546,U+578B,U+5DF2,U+5E08,U+5F88,U+601D,U+603B,U+606F,U+60F3,U+611F,U+63A8,U+652F,U+6574,U+65BD,U+6C14,U+6CA1,U+73AF,U+75C5,U+7EA7,U+8282,U+8BC1,U+8F83,U+8FD0,U+91CC,U+95E8,U+98CE;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/37-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E48-4E49,U+4E66,U+4EA4,U+4EFB,U+4F20,U+505A,U+5171,U+5177,U+521B,U+5355,U+5411,U+589E,U+6307,U+63A5,U+6536,U+6539,U+670D,U+6837,U+6D41,U+6D4E,U+6E90,U+770B,U+786E,U+7A76,U+7F51,U+7F8E,U+8003,U+88AB,U+8BA4,U+8BBA,U+8BC6,U+8C03,U+9020,U+9662,U+9879;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/36-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E60,U+4E9B,U+4EF6,U+4F01,U+4F46,U+5341,U+539F,U+53D8,U+5404,U+573A,U+5904,U+5929,U+5B89,U+5BFC,U+6301,U+6548,U+6708,U+6743,U+6761,U+6784,U+6B21,U+6B63,U+6C42,U+6CBB,U+7740,U+77E5,U+7814,U+7ACB,U+7C7B,U+7EC4,U+80B2,U+8D77,U+8FD8,U+9053;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/35-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E8C,U+4F4D,U+5229,U+5458,U+5916,U+5C06,U+5E38,U+5F3A,U+5F62,U+610F,U+6280,U+65E0,U+65E5,U+66F4,U+672F,U+679C,U+6807,U+6B64,U+6BD4,U+6D3B,U+7136,U+7279,U+7531,U+793E,U+79D1,U+7ED3,U+7EDF,U+89E3,U+8D28,U+90FD,U+91D1,U+95EE,U+9700;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/34-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E09,U+4ECE,U+4EE3,U+4F7F,U+4FE1,U+5165,U+524D,U+533A,U+54C1,U+56E0,U+597D,U+5C0F,U+5E73,U+5E76,U+5F0F,U+60C5,U+636E,U+660E,U+6700,U+671F,U+6C34,U+70B9,U+7535,U+76EE,U+8868,U+89C4,U+8BA1,U+8BF4,U+957F,U+95F4,U+9898;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/33-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E8B,U+4ED6,U+4FDD,U+5185,U+52A0-52A1,U+53CA,U+57FA,U+5B50,U+5E02,U+5F00,U+5F53,U+5F97,U+5FC3,U+6216,U+63D0,U+653F,U+6570,U+6C11,U+7269,U+76F8,U+79CD,U+7A0B,U+7B2C,U+7BA1,U+7CFB,U+8BBE,U+8D44,U+901A,U+91CF;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/32-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E0B,U+4E4B,U+4E5F,U+4EEC,U+516C,U+5173,U+5176,U+5236,U+540E,U+5982,U+5BB6,U+5C31,U+5C55,U+5E94,U+5EA6,U+5EFA,U+6240,U+6559,U+6587,U+65B0,U+672C,U+673A,U+8005,U+800C,U+90E8,U+91CD,U+9762;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/31-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E0E,U+4E3B,U+4EA7,U+4F53,U+5168,U+5206,U+5230,U+529B,U+52A8,U+5316,U+5408,U+540C,U+591A,U+5B9A,U+5DE5,U+6027,U+6211,U+6765,U+73B0,U+7B49,U+7ECF,U+81EA,U+8FC7,U+8FDB,U+9AD8;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/30-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E0A,U+4E1A,U+4E2A,U+4E8E,U+4F1A,U+4F5C,U+51FA,U+53D1,U+53EF,U+5730,U+5B9E,U+5BF9,U+5E74,U+6210,U+65B9,U+65F6,U+6CD5,U+7406,U+7528,U+80FD,U+884C,U+8FD9;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/29-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+4E00,U+4E0D,U+4E2D,U+4E3A,U+4E86,U+4EBA,U+4EE5,U+548C,U+56FD,U+5728,U+5927,U+5B66,U+662F,U+6709,U+751F,U+7684,U+8981;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/28-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+2022,U+25CF,U+3018-3019,U+FE41-FE44,U+FF0D,U+FF3F,U+FF5C-FF5D;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/27-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+2018-2019,U+201C-201D,U+3008-300B,U+300D-3011,U+3014-3017,U+FF08-FF09,U+FF3B,U+FF3D,U+FF5B;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/26-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+2013-2014,U+2026,U+203C,U+2047,U+3001-3002,U+300C,U+30FB,U+FF01,U+FF0C,U+FF0E-FF0F,U+FF1A-FF1B,U+FF1F,U+FF5E;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/7-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+C8-E0;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/6-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+B1-B4,U+B6-C7;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/5-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+A0-B0;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/4-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+79-7D;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/3-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+5E-6E,U+70-78;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/2-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+45-5D;}
+@font-face{font-family:"WF-Hwmc";src: url('./files/1-subset.woff2') format('woff2');font-style:normal;font-display:swap;font-weight:400;unicode-range:U+2F-44;}
diff --git a/scripts/build-perf/config-check.py b/scripts/build-perf/config-check.py
new file mode 100755
index 0000000..7213af6
--- /dev/null
+++ b/scripts/build-perf/config-check.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+"""
+站点 YAML 配置结构校验(2026-11-02 教训驱动)
+
+为什么需要:Python 默认 yaml.safe_load 对重复键是"后者覆盖前者"的静默行为,
+收编时用它验收会漏。本包实测 public/admin/config.yml 里 typography 被插进双语
+字段的 name: 与 widget: object 之间 → 同一 mapping 出现重复键 widget/fields,
+后台双语编辑器退化成字符串、排版选择器字段被劫持。本脚本用自定义构造器在
+解析阶段对重复键直接报错,并附带后台 hint 覆盖率体检。
+
+用法:python3 scripts/build-perf/config-check.py [repo根=.]
+退出码:0 通过;1 有失败项
+"""
+import sys
+from pathlib import Path
+
+try:
+ import yaml
+except ImportError:
+ print('[config-check] 缺少 pyyaml:pip install pyyaml')
+ sys.exit(1)
+
+FILES = [
+ 'public/admin/config.yml',
+ 'content/site/home.yaml',
+ 'content/site/about.yaml',
+ 'content/site/opensource.yaml',
+ 'content/site/theme.yaml',
+]
+
+
+class StrictLoader(yaml.SafeLoader):
+ """对重复键报错的 SafeLoader(默认行为是静默覆盖)。"""
+
+
+def _construct_mapping(loader, node, deep=False):
+ seen = set()
+ for key_node, _value_node in node.value:
+ key = loader.construct_object(key_node, deep=deep)
+ if key in seen:
+ raise yaml.YAMLError(
+ f'duplicate key {key!r} at line {key_node.start_mark.line + 1}'
+ )
+ seen.add(key)
+ return yaml.SafeLoader.construct_mapping(loader, node, deep=deep)
+
+
+StrictLoader.add_constructor(
+ yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, _construct_mapping
+)
+
+
+def main() -> int:
+ root = Path(sys.argv[1] if len(sys.argv) > 1 else '.')
+ failed = 0
+ loaded = {}
+
+ for rel in FILES:
+ path = root / rel
+ if not path.exists():
+ print(f'[config-check] SKIP {rel}(不存在)')
+ continue
+ try:
+ loaded[rel] = yaml.load(path.read_text(encoding='utf-8'), Loader=StrictLoader)
+ print(f'[config-check] OK {rel}')
+ except yaml.YAMLError as exc:
+ failed += 1
+ first = str(exc).splitlines()[0]
+ print(f'[config-check] FAIL {rel}\n {first}')
+
+ admin = loaded.get('public/admin/config.yml')
+ if admin:
+ fields = hints = 0
+
+ def walk(node):
+ nonlocal fields, hints
+ if isinstance(node, dict):
+ if 'name' in node:
+ fields += 1
+ if 'hint' in node:
+ hints += 1
+ for value in node.values():
+ walk(value)
+ elif isinstance(node, list):
+ for value in node:
+ walk(value)
+
+ walk(admin)
+ print(f'[config-check] 后台字段 {fields} 个,其中带 hint {hints} 个')
+ if hints < 20:
+ failed += 1
+ print('[config-check] FAIL hint 覆盖不足(<20),后台字段缺少中文说明')
+
+ if failed:
+ print(f'[config-check] {failed} 项未通过')
+ return 1
+ print('[config-check] 全部通过')
+ return 0
+
+
+if __name__ == '__main__':
+ raise SystemExit(main())
diff --git a/scripts/build-perf/contrast-check.mjs b/scripts/build-perf/contrast-check.mjs
new file mode 100644
index 0000000..0d12406
--- /dev/null
+++ b/scripts/build-perf/contrast-check.mjs
@@ -0,0 +1,141 @@
+#!/usr/bin/env node
+/**
+ * 主题对比度闸门(样式即数据 · 层 4):从**构建产物**里读实际生效的 CSS 变量,
+ * 断言正文与强调色在两态下的对比度都 ≥4.5:1。构建期跑,失败即 exit 1 拦住发布。
+ *
+ * 为什么读产物而不是读 yaml:断言的对象必须是"用户最终看到的颜色"——
+ * theme.yaml 经 theme.ts 钳制/回落后的真值只存在于 dist 内联样式里。
+ *
+ * 用法:node scripts/build-perf/contrast-check.mjs [distRoot]
+ */
+import { readFileSync, existsSync, readdirSync } from 'node:fs';
+import { join } from 'node:path';
+
+const distRoot = process.argv[2] ?? 'dist';
+const MIN = 4.5;
+
+const read = (p) => readFileSync(p, 'utf8');
+
+function normalize(hex) {
+ const h = hex.replace('#', '');
+ return '#' + (h.length === 3 ? h.split('').map((c) => c + c).join('') : h);
+}
+function lum(hex) {
+ const h = normalize(hex).replace('#', '');
+ const [r, g, b] = [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16) / 255);
+ const f = (c) => (c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4);
+ return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
+}
+function ratio(a, b) {
+ const [la, lb] = [lum(a), lum(b)];
+ const [hi, lo] = [Math.max(la, lb), Math.min(la, lb)];
+ return (hi + 0.05) / (lo + 0.05);
+}
+
+// ── 1. 从产物取主题变量(内联 style 的 :root:root / [data-theme=dark] 块) ──
+let html = '';
+if (!existsSync(distRoot)) {
+ console.error(`[contrast] dist 不存在:${distRoot}(先 build)`);
+ process.exit(1);
+}
+const htmlFile = join(distRoot, 'index.html');
+if (existsSync(htmlFile)) html = read(htmlFile);
+else {
+ // 兜底:任取一个页面
+ const walk = (d) => {
+ for (const e of readdirSync(d, { withFileTypes: true })) {
+ const p = join(d, e.name);
+ if (e.isDirectory()) {
+ const r = walk(p);
+ if (r) return r;
+ } else if (e.name === 'index.html') return p;
+ }
+ return null;
+ };
+ const f = walk(distRoot);
+ if (f) html = read(f);
+}
+if (!html) {
+ console.error('[contrast] 产物里找不到任何页面');
+ process.exit(1);
+}
+
+const varOf = (scope, name) => {
+ const re = new RegExp(`${scope.replace(/[[\]]/g, '\\$&')}[^{]*\\{([^}]*)\\}`, 'g');
+ let m;
+ while ((m = re.exec(html))) {
+ const hit = new RegExp(`${name}\\s*:\\s*(#[0-9a-fA-F]{3,6})`).exec(m[1]);
+ if (hit) return hit[1];
+ }
+ return null;
+};
+
+// tokens.css 的底色与正文色(不在主题旋钮白名单内,故从产物 CSS 取)
+const cssFiles = [];
+const walkCss = (d) => {
+ for (const e of readdirSync(d, { withFileTypes: true })) {
+ const p = join(d, e.name);
+ if (e.isDirectory()) walkCss(p);
+ else if (e.name.endsWith('.css')) cssFiles.push(p);
+ }
+};
+walkCss(distRoot);
+let tokensCss = '';
+for (const f of cssFiles) {
+ const c = read(f);
+ // 必须是**定义**(--bg:#xxx),而不是 var(--bg-soft) 这类引用——
+ // 后者会误命中只用到变量名、并不定义 base token 的页面级 CSS
+ if (/--ink-2\s*:\s*#/.test(c) && /--bg\s*:\s*#/.test(c)) { tokensCss = c; break; }
+}
+const tokenVar = (name) => {
+ const m = new RegExp(`${name}\\s*:\\s*(#[0-9a-fA-F]{3,6})`).exec(tokensCss);
+ return m ? m[1] : null;
+};
+
+const checks = [];
+const bgLight = tokenVar('--bg');
+const bgDark = (() => {
+ // 暗态 --bg 在 [data-theme=dark] 块里
+ const m = /\[data-theme=["']?dark["']?\][^{]*\{([^}]*)\}/.exec(tokensCss);
+ if (!m) return null;
+ const h = /--bg\s*:\s*(#[0-9a-fA-F]{3,6})/.exec(m[1]);
+ return h ? h[1] : null;
+})();
+const ink2Light = tokenVar('--ink-2');
+const ink2Dark = (() => {
+ const m = /\[data-theme=["']?dark["']?\][^{]*\{([^}]*)\}/.exec(tokensCss);
+ if (!m) return null;
+ const h = /--ink-2\s*:\s*(#[0-9a-fA-F]{3,6})/.exec(m[1]);
+ return h ? h[1] : null;
+})();
+
+const accentLight = varOf(':root:root', '--accent');
+const accentDark = (() => {
+ const m = /\[data-theme=["']?dark["']?\]:root:root\{([^}]*)\}/.exec(html);
+ if (!m) return null;
+ const h = /--accent\s*:\s*(#[0-9a-fA-F]{3,6})/.exec(m[1]);
+ return h ? h[1] : null;
+})();
+
+if (bgLight && ink2Light) checks.push(['正文(亮)', ink2Light, bgLight]);
+if (bgDark && ink2Dark) checks.push(['正文(暗)', ink2Dark, bgDark]);
+if (accentLight && bgLight) checks.push(['强调色(亮)', accentLight, bgLight]);
+if (accentDark && bgDark) checks.push(['强调色(暗)', accentDark, bgDark]);
+
+if (checks.length === 0) {
+ console.error('[contrast] 未能从产物解析出主题/正文色变量,请检查注入是否生效');
+ process.exit(1);
+}
+
+let failed = 0;
+for (const [label, fg, bg] of checks) {
+ const r = ratio(fg, bg);
+ const ok = r >= MIN;
+ if (!ok) failed++;
+ console.log(`[contrast] ${ok ? 'PASS' : 'FAIL'} ${label} ${fg} on ${bg} = ${r.toFixed(2)}:1`);
+}
+if (failed > 0) {
+ console.error(`[contrast] ${failed} 项低于 ${MIN}:1 —— 主题配色不可读,请调亮/调暗后再构建`);
+ process.exit(1);
+}
+console.log(`[contrast] 全部通过(${checks.length} 项 ≥ ${MIN}:1)`);
diff --git a/scripts/build-perf/subset-fonts.py b/scripts/build-perf/subset-fonts.py
new file mode 100755
index 0000000..66b66e4
--- /dev/null
+++ b/scripts/build-perf/subset-fonts.py
@@ -0,0 +1,274 @@
+#!/usr/bin/env python3
+"""
+字体子集化(Phase 5g T7):把切片字体再按「本站实际用字」裁一刀。
+
+背景:@fontsource / cn-font-split 的中文切片粒度粗(一片 10-20KB、含数百字),
+一篇用到 9-19 片就 163KB~535KB。中文艺术字体只用于标题/短句时,实际用字往往
+只有几十个——按用字裁切可把单页成本压到十分之一以下。
+
+做法:读字体 CSS 的 @font-face(含 unicode-range)→ 收集内容里实际出现的字符 →
+逐片求交集 → 空片丢弃、非空片用 pyftsubset 裁成只含所需字形的 woff2 →
+重写 CSS 指向新切片。输出目录结构与原 CSS 的 url 相对路径保持一致。
+
+用法:
+ subset-fonts.py --css node_modules/@fontsource/zcool-kuaile/index.css \
+ --out public/fonts/subset/kuaile \
+ --chars-from content/posts content/moments content/site/*.yaml \
+ [--chars-mode all|headings] [--min-bytes 4096]
+
+退出码:0 成功;1 参数/依赖错误。
+"""
+from __future__ import annotations
+
+import argparse
+import glob
+import io
+import os
+import re
+import shutil
+import subprocess
+import sys
+from pathlib import Path
+
+try:
+ from fontTools.ttLib import TTFont # noqa: F401 (pyftsubset 依赖同包)
+except ImportError: # pragma: no cover
+ sys.exit('[subset-fonts] 缺少 fonttools:pip install fonttools brotli')
+
+FACE_RE = re.compile(r'@font-face\s*\{(?P[^}]*)\}', re.S)
+URL_RE = re.compile(r'url\((?P["\']?)(?P[^)"\']+)(?P=q)\)')
+RANGE_RE = re.compile(r'unicode-range\s*:\s*(?P[^;]+);')
+UPLUS_RE = re.compile(r'U\+([0-9A-Fa-f]{1,6})(?:-([0-9A-Fa-f]{1,6}))?')
+
+
+def collect_chars(paths: list[str], mode: str) -> set[str]:
+ """从内容文件里收集需要的字符;headings 模式只取标题行(艺术字体常用于标题)。"""
+ chars: set[str] = set()
+ for pattern in paths:
+ for path in glob.glob(pattern, recursive=True):
+ try:
+ text = Path(path).read_text(encoding='utf-8')
+ except (OSError, UnicodeDecodeError):
+ continue
+ if mode == 'headings':
+ for line in text.splitlines():
+ if line.lstrip().startswith('#'):
+ chars.update(line)
+ elif line.strip().startswith('title:'):
+ chars.update(line)
+ else:
+ chars.update(text)
+ return {c for c in chars if c.strip()}
+
+
+def parse_ranges(spec: str) -> list[tuple[int, int]]:
+ out: list[tuple[int, int]] = []
+ for m in UPLUS_RE.finditer(spec):
+ start = int(m.group(1), 16)
+ end = int(m.group(2), 16) if m.group(2) else start
+ out.append((start, end))
+ return out
+
+
+def chars_in_ranges(chars: set[str], ranges: list[tuple[int, int]]) -> list[str]:
+ picked = []
+ for ch in chars:
+ cp = ord(ch)
+ if any(start <= cp <= end for start, end in ranges):
+ picked.append(ch)
+ return picked
+
+
+def subset_slice(src: Path, dst: Path, chars: list[str]) -> bool:
+ """用 pyftsubset 把 src 裁成只含 chars 的 woff2;返回是否成功产出。"""
+ dst.parent.mkdir(parents=True, exist_ok=True)
+ unicodes = ','.join(f'U+{ord(c):04X}' for c in chars)
+ cmd = [
+ sys.executable, '-m', 'fontTools.subset', str(src),
+ f'--unicodes={unicodes}',
+ '--flavor=woff2',
+ '--layout-features=*',
+ '--no-hinting',
+ '--desubroutinize',
+ f'--output-file={dst}',
+ ]
+ r = subprocess.run(cmd, capture_output=True, text=True)
+ if r.returncode != 0:
+ print(f' [warn] 裁切失败 {src.name}: {r.stderr.strip()[:160]}')
+ return False
+ return dst.exists() and dst.stat().st_size > 0
+
+
+def merge_subsets(subsets: list[Path], out: Path) -> bool:
+ """把多片已裁切的字体合并成一个字体,再输出单文件 woff2。
+
+ 为什么需要:切片字体按 unicode-range 分散,页面用到的字散落在十几片里,
+ 逐片裁剪只能省掉「片内空字」而省不掉「片头开销」;合并成单文件后
+ 页面只拉一个 woff2,缓存命中率与请求数都更好。
+ """
+ try:
+ from fontTools.merge import Merger
+ except ImportError:
+ print('[subset-fonts] 缺少 fontTools.merge')
+ return False
+ try:
+ merged = Merger().merge([str(p) for p in subsets])
+ out.parent.mkdir(parents=True, exist_ok=True)
+ tmp = out.with_suffix('.merged.ttf')
+ merged.save(str(tmp))
+ r = subprocess.run(
+ [sys.executable, '-m', 'fontTools.subset', str(tmp), '--flavor=woff2',
+ '--layout-features=*', '--no-hinting', '--desubroutinize',
+ f'--output-file={out}'],
+ capture_output=True, text=True,
+ )
+ tmp.unlink(missing_ok=True)
+ if r.returncode != 0:
+ print(f' [warn] 合并后输出失败: {r.stderr.strip()[:160]}')
+ return False
+ return out.exists()
+ except Exception as exc: # 合并对字表差异敏感,失败要能回落
+ print(f' [warn] 合并失败(回落到逐片模式): {type(exc).__name__}: {str(exc)[:120]}')
+ return False
+
+
+def do_merge_mode(css: str, css_path: Path, out_dir: Path, chars: set[str], min_bytes: int) -> int:
+ """--merge:所有用到的切片先各自裁切,再合成单文件 + 单 @font-face CSS。"""
+ base_dir = css_path.parent
+ tmp_dir = out_dir / '.slices'
+ tmp_dir.mkdir(parents=True, exist_ok=True)
+ families: dict[str, list[Path]] = {}
+ fam_name = ''
+ total_before = 0
+
+ for m in FACE_RE.finditer(css):
+ body = m.group('body')
+ url = URL_RE.search(body)
+ if not url:
+ continue
+ rng = RANGE_RE.search(body)
+ ranges = parse_ranges(rng.group('ranges')) if rng else [(0, 0x10FFFF)]
+ picked = chars_in_ranges(chars, ranges)
+ if not picked:
+ continue
+ fam = re.search(r'font-family\s*:\s*([^;]+);', body)
+ fam_name = fam.group(1).strip().strip('"\'') if fam else fam_name
+ src = (base_dir / url.group('url')).resolve()
+ if not src.exists():
+ continue
+ total_before += src.stat().st_size
+ dst = tmp_dir / f'{src.stem}-{len(families)}.woff2'
+ if not subset_slice(src, dst, picked):
+ continue
+ families.setdefault('all', []).append(dst)
+
+ slices = families.get('all', [])
+ if not slices:
+ print('[subset-fonts] merge 模式没有可合并切片')
+ return 0
+ out_font = out_dir / 'merged-subset.woff2'
+ if not merge_subsets(slices, out_font):
+ print('[subset-fonts] merge 失败,本次不产出(保留原 CSS 引用)')
+ return 1
+ after = out_font.stat().st_size
+ (out_dir / css_path.name).write_text(
+ '@font-face {\n'
+ f' font-family: \'{fam_name}\';\n'
+ f" src: url('./merged-subset.woff2') format('woff2');\n"
+ ' font-display: swap;\n'
+ ' font-weight: 400;\n'
+ ' font-style: normal;\n'
+ '}\n',
+ encoding='utf-8',
+ )
+ for f in slices:
+ f.unlink(missing_ok=True)
+ try:
+ tmp_dir.rmdir()
+ except OSError:
+ pass
+ print(f'[subset-fonts] merge:{len(slices)} 片 {total_before/1024:.0f}KB → 单文件 {after/1024:.0f}KB')
+ return 0
+
+
+def main() -> int:
+ ap = argparse.ArgumentParser()
+ ap.add_argument('--css', required=True, help='字体 CSS(含 @font-face 与 unicode-range)')
+ ap.add_argument('--out', required=True, help='输出目录(CSS 与切片都写这里)')
+ ap.add_argument('--chars-from', nargs='+', required=True, help='待扫描的内容文件/glob')
+ ap.add_argument('--chars-mode', choices=['all', 'headings'], default='all')
+ ap.add_argument('--min-bytes', type=int, default=4096, help='低于该字节数的切片视为已足够小,原样拷贝')
+ ap.add_argument('--merge', action='store_true', help='[实验性] 合并成单文件子集;fontTools.merge 对 CJK 切片字表冲突敏感,实测产出异常,暂不可用于生产')
+ args = ap.parse_args()
+
+ css_path = Path(args.css)
+ if not css_path.exists():
+ print(f'[subset-fonts] CSS 不存在:{css_path}')
+ return 1
+ css = css_path.read_text(encoding='utf-8')
+ chars = collect_chars(args.chars_from, args.chars_mode)
+ if not chars:
+ print('[subset-fonts] 未收集到任何字符,跳过')
+ return 0
+ print(f'[subset-fonts] 用字 {len(chars)} 个(mode={args.chars_mode})')
+
+ out_dir = Path(args.out)
+ if args.merge:
+ return do_merge_mode(css, css_path, out_dir, chars, args.min_bytes)
+ base_dir = css_path.parent
+ before = after = 0
+ kept = dropped = 0
+ out_css: list[str] = []
+ pos = 0
+
+ for m in FACE_RE.finditer(css):
+ body = m.group('body')
+ rng = RANGE_RE.search(body)
+ url = URL_RE.search(body)
+ if not url:
+ out_css.append(m.group(0)) # 无 src 的 face(异常件)原样保留
+ continue
+ # 无 unicode-range 的 face = 单文件全字集(latin 等):按全范围处理,
+ # 否则原样保留会残留指向未产出文件的 url(首版实测 kuaile 缺 58 个)
+ ranges = parse_ranges(rng.group('ranges')) if rng else [(0, 0x10FFFF)]
+ picked = chars_in_ranges(chars, ranges)
+ src = (base_dir / url.group('url')).resolve()
+ if not picked:
+ dropped += 1
+ continue # 整片不需要
+ try:
+ before += src.stat().st_size
+ except OSError:
+ print(f' [warn] 切片缺失:{src}')
+ dropped += 1
+ continue
+ # 统一产出 woff2 且重写 @font-face:原 CSS 每面常带多个格式(woff/woff2),
+ # 原样改写会残留指向未产出文件的引用(首版实测 kuaile 缺 58 个 .woff)
+ stem = src.stem.replace('.', '-')
+ dst = out_dir / 'files' / f'{stem}-subset.woff2'
+ if src.stat().st_size <= args.min_bytes:
+ dst.parent.mkdir(parents=True, exist_ok=True)
+ shutil.copyfile(src, dst)
+ elif not subset_slice(src, dst, picked):
+ dst.parent.mkdir(parents=True, exist_ok=True)
+ shutil.copyfile(src, dst) # 裁失败退回原片,保证可用
+ after += dst.stat().st_size if dst.exists() else src.stat().st_size
+ kept += 1
+ # 整段替换 src 声明(原 face 常有多格式:woff2 + woff,只换第一个 url 会
+ # 残留指向未产出文件的引用——首版实测 kuaile 缺 58 个 .woff)
+ new_body = re.sub(
+ r'src\s*:\s*[^;]+;',
+ f"src: url('./files/{stem}-subset.woff2') format('woff2');",
+ body,
+ count=1,
+ )
+ out_css.append(m.group(0).replace(body, new_body))
+
+ out_dir.mkdir(parents=True, exist_ok=True)
+ (out_dir / css_path.name).write_text(css[:0] + '\n'.join(out_css) + '\n', encoding='utf-8')
+ print(f'[subset-fonts] 切片:保留 {kept} / 丢弃 {dropped}|字节 {before/1024:.0f}KB → {after/1024:.0f}KB')
+ return 0
+
+
+if __name__ == '__main__':
+ raise SystemExit(main())
diff --git a/src/components/blocks/BlockRenderer.astro b/src/components/blocks/BlockRenderer.astro
new file mode 100644
index 0000000..cc345f0
--- /dev/null
+++ b/src/components/blocks/BlockRenderer.astro
@@ -0,0 +1,34 @@
+---
+// 块统一渲染器:switch(type) → 子组件;外壳带 data-block 属性(E2E 断言抓手)
+import type { ResolvedBlock } from '../../lib/page-blocks';
+import Prose from './Prose.astro';
+import Tracks from './Tracks.astro';
+import Cards from './Cards.astro';
+import Timeline from './Timeline.astro';
+import Quote from './Quote.astro';
+import Figure from './Figure.astro';
+import LinkList from './LinkList.astro';
+import Cta from './Cta.astro';
+import Divider from './Divider.astro';
+
+interface Props {
+ block: ResolvedBlock;
+}
+const { block } = Astro.props;
+---
+
+
+ {block.type === 'prose' && }
+ {block.type === 'tracks' && }
+ {block.type === 'cards' && }
+ {block.type === 'timeline' && }
+ {block.type === 'quote' &&
}
+ {block.type === 'figure' && }
+ {block.type === 'linklist' && }
+ {block.type === 'cta' && }
+ {block.type === 'divider' && }
+
+
+
diff --git a/src/components/blocks/Cards.astro b/src/components/blocks/Cards.astro
new file mode 100644
index 0000000..42917ec
--- /dev/null
+++ b/src/components/blocks/Cards.astro
@@ -0,0 +1,75 @@
+---
+// cards 块:技能/资源卡(2 或 3 列;复用 .track-row 的边框与内距语言)
+import type { ResolvedBlock } from '../../lib/page-blocks';
+
+interface Props {
+ block: Extract;
+}
+const { block } = Astro.props;
+---
+
+{block.title && {block.title}
}
+
+ {block.items.map((item) => {
+ const body = (
+ <>
+ {item.tag && {item.tag}}
+ {item.title}
+ {item.desc && {item.desc}
}
+ >
+ );
+ return (
+ -
+ {item.href ? (
+ {body}
+ ) : (
+
{body}
+ )}
+
+ );
+ })}
+
+
+
diff --git a/src/components/blocks/Cta.astro b/src/components/blocks/Cta.astro
new file mode 100644
index 0000000..76825ed
--- /dev/null
+++ b/src/components/blocks/Cta.astro
@@ -0,0 +1,48 @@
+---
+// cta 块:单按钮行动点(克制:同屏最多 1 个,由编辑纪律保证)
+import type { ResolvedBlock } from '../../lib/page-blocks';
+
+interface Props {
+ block: Extract;
+}
+const { block } = Astro.props;
+const isExternal = block.href.startsWith('http');
+---
+
+
+
+
diff --git a/src/components/blocks/Divider.astro b/src/components/blocks/Divider.astro
new file mode 100644
index 0000000..4e1bce0
--- /dev/null
+++ b/src/components/blocks/Divider.astro
@@ -0,0 +1,20 @@
+---
+// divider 块:节奏控制(line = hairline 分隔;space = 纯留白)
+import type { ResolvedBlock } from '../../lib/page-blocks';
+
+interface Props {
+ block: Extract;
+}
+const { block } = Astro.props;
+---
+
+{block.style === 'space' ? :
}
+
+
diff --git a/src/components/blocks/Figure.astro b/src/components/blocks/Figure.astro
new file mode 100644
index 0000000..c5df9ab
--- /dev/null
+++ b/src/components/blocks/Figure.astro
@@ -0,0 +1,38 @@
+---
+// figure 块:图片(Astro 图片管线,宽度自适应;caption 图注)
+import { Image } from 'astro:assets';
+import type { ResolvedBlock } from '../../lib/page-blocks';
+
+interface Props {
+ block: Extract;
+}
+const { block } = Astro.props;
+---
+
+
+
+ {block.caption && {block.caption}}
+
+
+
diff --git a/src/components/blocks/LinkList.astro b/src/components/blocks/LinkList.astro
new file mode 100644
index 0000000..8729a18
--- /dev/null
+++ b/src/components/blocks/LinkList.astro
@@ -0,0 +1,58 @@
+---
+// linklist 块:外链清单(比裸 markdown 链接可控:带 note 与统一行距)
+import type { ResolvedBlock } from '../../lib/page-blocks';
+
+interface Props {
+ block: Extract;
+}
+const { block } = Astro.props;
+
+const isExternal = (href: string) => href.startsWith('http');
+---
+
+{block.title && {block.title}
}
+
+
+
diff --git a/src/components/blocks/Prose.astro b/src/components/blocks/Prose.astro
new file mode 100644
index 0000000..a3eb237
--- /dev/null
+++ b/src/components/blocks/Prose.astro
@@ -0,0 +1,46 @@
+---
+// prose 块:自由正文(markdown 已由读取层渲染为 HTML,净化在 site-content 的插件链)
+import type { ResolvedBlock } from '../../lib/page-blocks';
+
+interface Props {
+ block: Extract;
+}
+const { block } = Astro.props;
+---
+
+{block.title && {block.title}
}
+
+
+
diff --git a/src/components/blocks/Quote.astro b/src/components/blocks/Quote.astro
new file mode 100644
index 0000000..3d13e0e
--- /dev/null
+++ b/src/components/blocks/Quote.astro
@@ -0,0 +1,36 @@
+---
+// quote 块:引文(复用 .quote-line 语言 + 楷体)
+import type { ResolvedBlock } from '../../lib/page-blocks';
+
+interface Props {
+ block: Extract;
+}
+const { block } = Astro.props;
+---
+
+
+ {block.text}
+ {block.cite && — {block.cite}}
+
+
+
diff --git a/src/components/blocks/Timeline.astro b/src/components/blocks/Timeline.astro
new file mode 100644
index 0000000..17ed981
--- /dev/null
+++ b/src/components/blocks/Timeline.astro
@@ -0,0 +1,66 @@
+---
+// timeline 块:经历/项目时间线(竖线语言,仅用既有 token)
+import type { ResolvedBlock } from '../../lib/page-blocks';
+
+interface Props {
+ block: Extract;
+}
+const { block } = Astro.props;
+---
+
+{block.title && {block.title}
}
+
+ {block.items.map((item) => (
+ -
+ {item.time}
+
+
{item.title}
+ {item.desc &&
{item.desc}
}
+
+
+ ))}
+
+
+
diff --git a/src/components/blocks/Tracks.astro b/src/components/blocks/Tracks.astro
new file mode 100644
index 0000000..3a900ea
--- /dev/null
+++ b/src/components/blocks/Tracks.astro
@@ -0,0 +1,70 @@
+---
+// tracks 块:兴趣/能力版图(复用原 AboutPage 的 .track-row 视觉语言)
+import type { ResolvedBlock } from '../../lib/page-blocks';
+import { iconPath } from '../../lib/icons';
+
+interface Props {
+ block: Extract;
+}
+const { block } = Astro.props;
+---
+
+{block.title}
+
+ {block.items.map((item) => (
+ -
+
+ {iconPath(item.icon) ? (
+
+ ) : (
+ {item.name.slice(0, 1)}
+ )}
+
+
+
{item.name}
+ {item.desc &&
{item.desc}
}
+
+
+ ))}
+
+
+
diff --git a/src/components/pages/AboutPage.astro b/src/components/pages/AboutPage.astro
index 00835f0..dbc1af6 100644
--- a/src/components/pages/AboutPage.astro
+++ b/src/components/pages/AboutPage.astro
@@ -3,70 +3,86 @@ import BaseLayout from '../../layouts/BaseLayout.astro';
import IdCard from '../../components/IdCard.astro';
import { t } from '../../i18n/ui';
import type { Locale } from '../../lib/locale';
-import { aboutIntroMarkdown, renderMarkdown } from '../../lib/site-content';
+import { aboutIntroMarkdown, pageTypography, renderMarkdown } from '../../lib/site-content';
+import { getAboutPage } from '../../lib/page-blocks';
+import BlockRenderer from '../blocks/BlockRenderer.astro';
// /en/ 侧由 T4 薄页传 locale='en';zh 路由无人传参,默认 zh 零回归
interface Props {
locale?: Locale;
}
const { locale = 'zh' } = Astro.props;
-// 身份陈述段改由 content/site/about.yaml 供给(多段 markdown,后台可改),缺值回落默认
-const introHtml = await renderMarkdown(await aboutIntroMarkdown(locale));
+// 三级回落(零回归):blocks 驱动 → intro markdown → 内置默认文案
+const { blocks, showIdCard } = await getAboutPage(locale);
+const introHtml =
+ blocks.length === 0 ? await renderMarkdown(await aboutIntroMarkdown(locale)) : '';
+const typo = await pageTypography('siteAbout', 'about');
---
{t('about_title', locale)}
-
+
+ {blocks.length > 0 ? (
+ <>
+ {blocks.map((block) =>
)}
+ {showIdCard &&
}
+ >
+ ) : (
+ <>
+
-
+
-
- {t('about_tracks_title', locale)}
-
- -
-
-
-
-
-
{t('about_track_reading_name', locale)}
-
{t('about_track_reading_desc', locale)}
-
-
- -
-
-
-
-
-
{t('about_track_tech_name', locale)}
-
{t('about_track_tech_desc', locale)}
-
-
- -
-
-
-
-
-
{t('about_track_photo_name', locale)}
-
{t('about_track_photo_desc', locale)}
-
-
-
-
+
+ {t('about_tracks_title', locale)}
+
+ -
+
+
+
+
+
{t('about_track_reading_name', locale)}
+
{t('about_track_reading_desc', locale)}
+
+
+ -
+
+
+
+
+
{t('about_track_tech_name', locale)}
+
{t('about_track_tech_desc', locale)}
+
+
+ -
+
+
+
+
+
{t('about_track_photo_name', locale)}
+
{t('about_track_photo_desc', locale)}
+
+
+
+
-
- {t('about_build_title', locale)}
- {t('about_build_desc', locale)}
-
+
+ {t('about_build_title', locale)}
+ {t('about_build_desc', locale)}
+
+ >
+ )}
+
diff --git a/src/content.config.ts b/src/content.config.ts
index eb4c203..86b843f 100644
--- a/src/content.config.ts
+++ b/src/content.config.ts
@@ -18,6 +18,92 @@ export type PostTrack = (typeof POST_TRACKS)[PostCategory];
/** 双语文案字段:两语言各自可选,缺一回落一(回退逻辑在 src/lib/site-content.ts) */
const bilingual = z.object({ zh: z.string().optional(), en: z.string().optional() });
+/** 块型清单(5g 页面构建器 v1 九类):访问器据此判未知 type */
+export const BLOCK_TYPES = [
+ 'prose',
+ 'tracks',
+ 'cards',
+ 'timeline',
+ 'quote',
+ 'figure',
+ 'linklist',
+ 'cta',
+ 'divider',
+] as const;
+
+type ImageHelper = (opts?: unknown) => z.ZodTypeAny;
+
+/** 关于页块型 union:图片字段强制 image()(外链字符串在 schema 层即失败,永不渲染) */
+const aboutBlockUnion = (image: ImageHelper) =>
+ z.discriminatedUnion('type', [
+ z.object({
+ type: z.literal('prose'),
+ enabled: z.boolean().optional(),
+ title: bilingual.optional(),
+ body: bilingual,
+ width: z.enum(['narrow', 'full']).optional(),
+ }),
+ z.object({
+ type: z.literal('tracks'),
+ enabled: z.boolean().optional(),
+ title: bilingual,
+ items: z.array(
+ z.object({ icon: z.string().optional(), name: bilingual, desc: bilingual.optional() }),
+ ),
+ }),
+ z.object({
+ type: z.literal('cards'),
+ enabled: z.boolean().optional(),
+ title: bilingual.optional(),
+ columns: z.union([z.literal(2), z.literal(3)]).optional(),
+ items: z.array(
+ z.object({
+ title: bilingual,
+ desc: bilingual.optional(),
+ href: z.string().optional(),
+ tag: bilingual.optional(),
+ }),
+ ),
+ }),
+ z.object({
+ type: z.literal('timeline'),
+ enabled: z.boolean().optional(),
+ title: bilingual.optional(),
+ items: z.array(z.object({ time: z.string(), title: bilingual, desc: bilingual.optional() })),
+ }),
+ z.object({
+ type: z.literal('quote'),
+ enabled: z.boolean().optional(),
+ text: bilingual,
+ cite: bilingual.optional(),
+ }),
+ z.object({
+ type: z.literal('figure'),
+ enabled: z.boolean().optional(),
+ image: image(),
+ alt: z.string().optional(),
+ caption: bilingual.optional(),
+ }),
+ z.object({
+ type: z.literal('linklist'),
+ enabled: z.boolean().optional(),
+ title: bilingual.optional(),
+ items: z.array(z.object({ label: bilingual, href: z.string(), note: bilingual.optional() })),
+ }),
+ z.object({
+ type: z.literal('cta'),
+ enabled: z.boolean().optional(),
+ text: bilingual,
+ href: z.string(),
+ label: bilingual,
+ }),
+ z.object({
+ type: z.literal('divider'),
+ enabled: z.boolean().optional(),
+ style: z.enum(['line', 'space']).optional(),
+ }),
+ ]);
+
export function trackOf(category: PostCategory): PostTrack {
return POST_TRACKS[category];
}
@@ -82,6 +168,14 @@ export const collections = {
z.object({
tagline: bilingual.optional(),
avatar: image().optional(),
+ /** 页面级排版覆盖(层 2):正文默认字体类 / 强调色类 / 字号缩放;不配置即全站默认 */
+ typography: z
+ .object({
+ font: z.string().optional(),
+ accent: z.string().optional(),
+ scale: z.number().optional(),
+ })
+ .optional(),
/** 站点图标:public 下的路径(.svg/.ico 直出,不经图片管线);缺省回退 /favicon.svg */
favicon: z.string().optional(),
/** 副标题(markdown 短文本,渲染在身份语下);空 = 不渲染 */
@@ -90,6 +184,18 @@ export const collections = {
latestPhotos: z.number().int().optional(),
/** 首页每轨条数:4-8(越界由访问器夹取,缺省 6) */
perTrackLimit: z.number().int().optional(),
+ /** 首页项目墙条数:1-99(缺省 6;越界夹取) */
+ projectsLimit: z.number().int().optional(),
+ /** 首页公告(markdown 富文本,走富文本管线);空 = 不渲染 */
+ announcement: bilingual.optional(),
+ /** 首页轨细分开关:分开关阅读/技术/照片三轨(缺省全开) */
+ postsTracks: z
+ .object({
+ reading: z.boolean().optional(),
+ tech: z.boolean().optional(),
+ photo: z.boolean().optional(),
+ })
+ .optional(),
/** 区块开关:缺省全开 */
sections: z
.object({
@@ -111,16 +217,65 @@ export const collections = {
.optional(),
}),
}),
+ // 主题旋钮(样式即数据 · 层 4):只放 9 组白名单旋钮,钳制与单调性在 src/lib/theme.ts
+ siteTheme: defineCollection({
+ loader: glob({ pattern: 'theme.yaml', base: './content/site' }),
+ schema: z.object({
+ accent_light: z.string().optional(),
+ accent_dark: z.string().optional(),
+ radius_img: z.number().optional(),
+ text_h1: z.number().optional(),
+ text_h2: z.number().optional(),
+ text_h3: z.number().optional(),
+ prose_size_reading: z.number().optional(),
+ prose_size_tech: z.number().optional(),
+ leading_reading: z.number().optional(),
+ leading_tech: z.number().optional(),
+ space_3: z.number().optional(),
+ space_4: z.number().optional(),
+ space_5: z.number().optional(),
+ space_6: z.number().optional(),
+ flow_p: z.number().optional(),
+ flow_h2_post: z.number().optional(),
+ dur: z.number().optional(),
+ }),
+ }),
siteAbout: defineCollection({
loader: glob({ pattern: 'about.yaml', base: './content/site' }),
- // intro = 多段 markdown 正文(页面用 createMarkdownProcessor 渲染),字段级空值回落默认
- schema: z.object({ intro: bilingual.optional() }),
+ // intro = 多段 markdown 正文(二级回退:blocks 为空时才用)
+ // blocks = 块式页面构建器(5g):文本一律 {zh,en},图片字段必须 image();未知 type 落宽松分支
+ // → src/lib/page-blocks.ts warn + skip,保证后台填错块型不炸构建
+ schema: ({ image }) =>
+ z.object({
+ intro: bilingual.optional(),
+ /** 页面级排版覆盖(层 2,T3 车道):正文默认字体类 / 强调色类 / 字号缩放 */
+ typography: z
+ .object({
+ font: z.string().optional(),
+ accent: z.string().optional(),
+ scale: z.number().optional(),
+ })
+ .optional(),
+ /** 版式:是否渲染名片区(头像/名字/社交),默认 true */
+ layout: z.object({ showIdCard: z.boolean().optional() }).optional(),
+ blocks: z
+ .array(z.union([aboutBlockUnion(image), z.looseObject({ type: z.string() })]))
+ .optional(),
+ }),
}),
siteOpenSource: defineCollection({
loader: glob({ pattern: 'opensource.yaml', base: './content/site' }),
schema: z.object({
blurb: bilingual.optional(),
blurb_after: bilingual.optional(),
+ /** 页面级排版覆盖(层 2):正文默认字体类 / 强调色类 / 字号缩放;不配置即全站默认 */
+ typography: z
+ .object({
+ font: z.string().optional(),
+ accent: z.string().optional(),
+ scale: z.number().optional(),
+ })
+ .optional(),
repo_url: z.string().optional(),
repo_label: z.string().optional(),
/** 置顶仓短名,顺序即展示顺序(原 projects.ts 硬编码名单迁于此) */
diff --git a/src/data/projects-fallback.json b/src/data/projects-fallback.json
index fe3abcf..280d33c 100644
--- a/src/data/projects-fallback.json
+++ b/src/data/projects-fallback.json
@@ -7,5 +7,68 @@
"stars": 0,
"url": "https://git.wait4x.online/wait4x/blog",
"updatedAt": ""
+ },
+ {
+ "source": "github",
+ "name": "open-earth-data-guide",
+ "description": "A one-stop index of public earth-system (meteo · ocean · climate · environment) data sources — download channels & access notes. Companion CLI toolkit: open-earth-data-kit.",
+ "language": "Python",
+ "stars": 58,
+ "url": "https://github.com/wait4xx/open-earth-data-guide",
+ "updatedAt": ""
+ },
+ {
+ "source": "github",
+ "name": "AI-CLI",
+ "description": "Run Terminal or AI coding assistants (Claude Code, Aider, etc.) on your phone/tablet — a responsive web IDE with terminal, split-pane editor, file browser, and real-time collaboration",
+ "language": "TypeScript",
+ "stars": 2,
+ "url": "https://github.com/wait4xx/AI-CLI",
+ "updatedAt": ""
+ },
+ {
+ "source": "github",
+ "name": "open-earth-data-kit",
+ "description": "Unified CLI toolkit for public meteorological, oceanographic, climate and environmental data access.",
+ "language": "Python",
+ "stars": 2,
+ "url": "https://github.com/wait4xx/open-earth-data-kit",
+ "updatedAt": ""
+ },
+ {
+ "source": "github",
+ "name": "pi-mesh",
+ "description": "Live agent-to-agent communication for Pi — local broker, mesh.v1 protocol, honest delivered/read/answered statuses, hash-only ledger. Zero runtime deps.",
+ "language": "TypeScript",
+ "stars": 0,
+ "url": "https://github.com/wait4xx/pi-mesh",
+ "updatedAt": ""
+ },
+ {
+ "source": "github",
+ "name": "pi-board",
+ "description": "Shared context board for pi-mesh — typed entries, bounded store, boolean grep. CLI-first; the mesh stays the router, never the database.",
+ "language": "TypeScript",
+ "stars": 1,
+ "url": "https://github.com/wait4xx/pi-board",
+ "updatedAt": ""
+ },
+ {
+ "source": "github",
+ "name": "pi-jobd",
+ "description": "Detached local job runner for Pi — per-user daemon, honest statuses, crash adoption, cross-platform. Zero runtime dependencies.",
+ "language": null,
+ "stars": 0,
+ "url": "https://github.com/wait4xx/pi-jobd",
+ "updatedAt": ""
+ },
+ {
+ "source": "github",
+ "name": "ai-code-style-kit",
+ "description": "Comment & commit-message style kit for AI-assisted coding: cross-tool skills, cross-platform git hook, pi extension",
+ "language": "Shell",
+ "stars": 0,
+ "url": "https://github.com/wait4xx/ai-code-style-kit",
+ "updatedAt": ""
}
]
diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro
index ed12e81..df17650 100644
--- a/src/layouts/BaseLayout.astro
+++ b/src/layouts/BaseLayout.astro
@@ -5,9 +5,9 @@
import sansVar from '@fontsource-variable/noto-sans-sc/index.css?url';
import mono400 from '@fontsource/jetbrains-mono/400.css?url';
import mono700 from '@fontsource/jetbrains-mono/700.css?url';
+import kuaile from '@fontsource/zcool-kuaile/index.css?url';
import serifVar from '@fontsource-variable/noto-serif-sc/index.css?url';
import kai from 'lxgw-wenkai-screen-webfont/lxgwwenkaiscreen.css?url';
-import kuaile from '@fontsource/zcool-kuaile/index.css?url';
import '../styles/global.css';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
@@ -18,6 +18,7 @@ import { siteFavicon } from '../lib/site-content';
import SearchDialog from '../components/SearchDialog.astro';
import BuildInfo from '../components/geek/BuildInfo.astro';
import { ClientRouter } from 'astro:transitions';
+import { themeCss } from '../lib/theme';
interface Props {
title: string;
@@ -36,6 +37,7 @@ const withSlash = (p: string) => (p.endsWith('/') ? p : `${p}/`);
const favicon = await siteFavicon();
// 自指 canonical(T2):SEO 权重收敛到当前页自身,与 hreflang 组合覆盖双轨
const canonicalUrl = new URL(withSlash(rawPath), Astro.site).href;
+const themeStyle = await themeCss();
---
@@ -77,7 +79,7 @@ const canonicalUrl = new URL(withSlash(rawPath), Astro.site).href;
-
+
>
)}