diff --git a/sql/edge_seed_visual.sql b/sql/edge_seed_visual.sql
index 93cf330..a023f81 100644
--- a/sql/edge_seed_visual.sql
+++ b/sql/edge_seed_visual.sql
@@ -21,10 +21,10 @@ WHERE code = 'demo';
UPDATE cms_banner SET status = 0 WHERE id = 5;
-- 2) 院系子站(demo 的子站:header 出"专业院系"下拉;不配 public_base_url=按请求派生)
--- 主题应用:jdx→cherry-bloom(樱语粉韵)、xxgc→violet-iris(鸢尾紫韵)——两套新皮肤随种子落地可视验收
+-- 主题应用:jdx→academic-navy(学府藏蓝)、xxgc→campus-azure(青蓝校园)——两套高校官网风皮肤随种子落地可视验收
INSERT INTO cms_site (id, code, parent_site_id, sch_id, sch_name, name, theme, config_json, status, create_by, create_time) VALUES
-(6, 'jdx', 1, 990001, '云海大学', '机电学院', 'cherry-bloom', '{"copyright": "机电学院"}', 1, 'cmssuper', NOW()),
-(7, 'xxgc', 1, 990001, '云海大学', '信息工程学院', 'violet-iris', '{"copyright": "信息工程学院"}', 1, 'cmssuper', NOW());
+(6, 'jdx', 1, 990001, '云海大学', '机电学院', 'academic-navy', '{"copyright": "机电学院"}', 1, 'cmssuper', NOW()),
+(7, 'xxgc', 1, 990001, '云海大学', '信息工程学院', 'campus-azure', '{"copyright": "信息工程学院"}', 1, 'cmssuper', NOW());
INSERT INTO cms_category (id, site_id, parent_id, name, type, link_url, content, sort_no, status, create_by, create_time) VALUES
(61, 6, 0, '学院概况', 2, NULL, '
机电学院(视觉精修种子)。
', 1, 1, 'cmssuper', NOW()),
(62, 6, 0, '学院新闻', 1, NULL, NULL, 2, 1, 'cmssuper', NOW()),
diff --git a/sql/upgrade_theme_academic_skins.sql b/sql/upgrade_theme_academic_skins.sql
new file mode 100644
index 0000000..cd059fc
--- /dev/null
+++ b/sql/upgrade_theme_academic_skins.sql
@@ -0,0 +1,21 @@
+-- ============================================================
+-- 皮肤升级脚本:粉/紫两包下线 → 高校官网风两包接管(幂等,存量库执行一次即可)
+-- 背景:cherry-bloom(樱语粉韵)/ violet-iris(鸢尾紫韵)不符合高校门户视觉,已从模板库删除;
+-- 存量站点若仍指向这两个主题,ThemeRegistry 匹配不到会静默回落 default(皮肤全丢),
+-- 故必须把 theme 列改到新包:academic-navy(学府藏蓝)/ campus-azure(青蓝校园)。
+-- 目标库:存量 bsch_cms(生产/预发);干净环境无需本脚本
+-- 顺序:备份查询 → 回填 → 校验
+-- ============================================================
+
+-- 1) 先看受影响站点(人工确认后再执行第 2 步)
+SELECT id, path, name, theme FROM cms_site WHERE theme IN ('cherry-bloom', 'violet-iris');
+
+-- 2) 回填:粉韵→学府藏蓝,紫韵→青蓝校园(仅命中旧值,重复执行无副作用)
+UPDATE cms_site SET theme = 'academic-navy' WHERE theme = 'cherry-bloom';
+UPDATE cms_site SET theme = 'campus-azure' WHERE theme = 'violet-iris';
+
+-- 3) 校验(应返回 0 行)
+SELECT id, path, theme FROM cms_site WHERE theme IN ('cherry-bloom', 'violet-iris');
+
+-- 备注:站点快照走 Caffeine CacheNames.SITE,TTL 30 分钟(±60s 抖动,见 CacheConfig),
+-- 实测改库后 400s 门户仍是旧皮肤——改库后请重启服务,或在管理端重新保存一次站点(换肤会主动清缓存)。
diff --git a/src/main/resources/templates/themes/academic-navy/README.md b/src/main/resources/templates/themes/academic-navy/README.md
new file mode 100644
index 0000000..7562bf7
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/README.md
@@ -0,0 +1,33 @@
+# academic-navy(学府藏蓝)
+
+高校官网风皮肤包:以 `scholar-blue` 为基座派生,配色与首页区块形态按综合类大学官网(浙江理工大学一类)重做。
+配了 `home_layout` 的站点,首页正文区块由本主题 `fragments/home-blocks.html` 渲染——派生包不自带区块形态时,
+正文会落到 `themes/common` 的通用骨架,换肤就只剩页头页脚(线上事故根因,见《审计验收清单-20260919》)。
+
+## 风格定位
+
+- 主色藏蓝 `#0b4a8f` + 加深 `#063161` + 点缀金 `#b8934a`(标题左竖条与居中线脚走金线,区别于基座的全蓝语言)。
+- 圆角收紧到 4/8px、页脚 `#0a2b4d`,行高压到 40px 一档,整体比基座更「机关报」而非「校园活动页」。
+- 全部 11 个颜色参数可在站点 theme_params 微调(`primary/primaryDark/primaryLight/accent/navBg/footerBg/text/textLight/bg/cardBg/border`)。
+
+## 首页区块形态(布局模式与回落模式同构)
+
+| homeStyle | 呈现 | 类名 |
+| -- | -- | -- |
+| `news_grid` | 双栏要闻:左 3 份图文头条(16:7 封面 + 摘要 + 元信息)、右 2 份紧凑行;区块背景可取站点 `news_bg_image` | `an-split` / `an-feat-*` |
+| `compact` | 日期方块行:46px 见方的「日 + 年月」方块,hover 反白 | `an-date-chip` |
+| `media_focus` | 媒体聚焦:来源徽标 + 双列密行 | `an-src` / `an-block-list--two` |
+| `image_wall` | 四列图片墙:封面 + 底部渐变遮罩标题,hover 抬图 | `an-wall` |
+| (空/未知) | 整宽区块卡:头条 + 行式列表 | `an-block--flow` |
+| `ticker` | 藏蓝要闻速递横条(单行不换行、超长省略,中文不塌列) | `an-ticker*` |
+| `gallery` | 线上展厅:居中双语文区头 + 四列图墙 | `an-gallery` |
+| `links` | 友情链接分组(胶囊标签行) | `an-links` |
+
+## 契约要点
+
+- 结构类前缀 `an-`,CSS 变量前缀 `--an-`;`:root` 把 `--an-*` 别名到皮肤契约变量(`--primary`/`--text`/`--card-bg`/`--border`…),
+ 使 `themes/common` 兜底骨架也能跟随本皮肤着色。
+- 空态文案「栏目暂无内容」只在 `block.items` 为空时出现;守卫必须写在 `th:block` 外层——
+ `th:replace`(优先级 100)先于 `th:if`(300)求值,写在同一标签上等于没写。
+- 回归防线:`AcademicSkinContractTest`(自带区块 fragment + 中文不塌列 + 契约变量别名 + 主色必须学术蓝)、
+ `PortalHomeLayoutIT#academicNavy_layoutUsesOwnFragments`(布局模式不落通用骨架)、`ThemeContractIT`(7 条路由)。
diff --git a/src/main/resources/templates/themes/academic-navy/assets/css/main.css b/src/main/resources/templates/themes/academic-navy/assets/css/main.css
new file mode 100644
index 0000000..4b6886f
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/assets/css/main.css
@@ -0,0 +1,1497 @@
+/* =====================================================================
+ academic-navy · 学府藏蓝(基座 scholar-blue,参考语言:综合类高校官网门户)
+ 设计语言:藏蓝顶栏/品牌行 + 白底主导航(吸顶反蓝) + 金线标题 + 日期方块行
+ + 布局模式双栏要闻(左图文右密行)+ 藏蓝要闻速递条 + 深色圆环页脚
+ 色彩令牌全部走 CSS 变量,theme.json color 参数经 :root 覆盖真实生效。
+ ===================================================================== */
+
+/* ---------------------------------------------------------------------
+ 1. 设计令牌(与 theme.json params 一一对应,禁止出现未消费的声明)
+ --------------------------------------------------------------------- */
+:root {
+ --an-primary: #0b4a8f; /* 主色:藏蓝,顶栏/品牌行/标题/强调 */
+ --an-primary-dark: #063161; /* 主色加深:hover/渐变端/页脚深端 */
+ --an-primary-light: #1a6cb5; /* 主色提亮:亮线条/hover 链接/角标 */
+ --an-accent: #b8934a; /* 点缀金:标题下划细线/日期方块描边(高校官网常见金线) */
+ --an-nav-bg: #ffffff; /* 主导航条底色(白条学院风) */
+ --an-footer-bg: #0a2b4d; /* 页脚主底 */
+ --an-text: #2b3644; /* 正文 */
+ --an-text-light: #6b7889; /* 次要文字 */
+ --an-bg: #f1f4f9; /* 页面底色 */
+ --an-card-bg: #ffffff; /* 卡片底 */
+ --an-border: #dbe3ee; /* 边框/分隔线 */
+
+ --an-ink-on-dark: #ffffff; /* 深底主文字 */
+ --an-ink-on-dark-soft: rgba(255,255,255,.74); /* 深底次要文字 */
+ --an-ink-on-dark-faint: rgba(255,255,255,.46);
+ --an-panel: rgba(11,74,143,.95); /* 下拉面板(主色半透明) */
+ --an-shadow-sm: 0 1px 4px rgba(6,49,97,.08);
+ --an-shadow-md: 0 6px 18px rgba(6,49,97,.12);
+ --an-shadow-lg: 0 14px 34px rgba(6,49,97,.18);
+ --an-radius: 4px;
+ --an-radius-lg: 8px;
+ --an-speed: .28s;
+ --an-font: "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Helvetica Neue", Arial, sans-serif;
+
+ /* 皮肤契约别名:站点配了 home_layout 时首页走 common/fragments/home-blocks 骨架,
+ 该骨架只认契约变量(--primary/--text/…)。不别名过去,换肤就只换了页头页脚、正文区块仍是骨架内置色。 */
+ --primary: var(--an-primary);
+ --primary-dark: var(--an-primary-dark);
+ --primary-light: var(--an-primary-light);
+ --text: var(--an-text);
+ --text-light: var(--an-text-light);
+ --bg: var(--an-bg);
+ --card-bg: var(--an-card-bg);
+ --border: var(--an-border);
+ --radius: var(--an-radius-lg);
+}
+
+/* ---------------------------------------------------------------------
+ 2. Reset 与基础
+ --------------------------------------------------------------------- */
+* { margin: 0; padding: 0; box-sizing: border-box; }
+
+html { -webkit-text-size-adjust: 100%; }
+
+body {
+ font-family: var(--an-font);
+ font-size: 14px;
+ line-height: 1.7;
+ color: var(--an-text);
+ background: var(--an-bg);
+ word-break: break-word;
+}
+
+ul, ol { list-style: none; }
+
+a { color: var(--an-primary); text-decoration: none; transition: color var(--an-speed) ease; }
+a:hover { color: var(--an-primary-light); }
+
+img { max-width: 100%; display: block; border: 0; }
+
+button { font-family: inherit; cursor: pointer; }
+
+input, button, select, textarea { font-size: inherit; color: inherit; }
+
+::selection { background: var(--an-primary); color: #fff; }
+
+/* 跳转链接:仅键盘聚焦时可见 */
+.skip-link {
+ position: absolute; left: -999px; top: 0; z-index: 300;
+ background: var(--an-primary-dark); color: #fff;
+ padding: 8px 18px; border-radius: 0 0 var(--an-radius) 0;
+}
+.skip-link:focus { left: 0; color: #fff; }
+
+/* 通用容器 */
+.an-container {
+ width: 1200px; max-width: calc(100% - 40px);
+ margin: 0 auto;
+}
+
+/* 屏幕阅读器专用 */
+.an-visually-hidden {
+ position: absolute; width: 1px; height: 1px;
+ margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
+}
+
+/* 置顶徽章 */
+.an-top-badge {
+ display: inline-block; flex: none;
+ padding: 0 7px; line-height: 18px;
+ font-size: 12px; color: #fff;
+ background: var(--an-primary-light);
+ border-radius: 2px;
+ letter-spacing: 1px;
+}
+
+/* 空状态 */
+.an-empty {
+ padding: 56px 20px;
+ text-align: center;
+ color: var(--an-text-light);
+}
+.an-empty p:first-child { font-size: 16px; margin-bottom: 8px; }
+.an-empty-hint { font-size: 13px; color: var(--an-text-light); opacity: .75; }
+
+/* ---------------------------------------------------------------------
+ 3. 顶栏(深蓝细条:日期 + 院系切换)
+ --------------------------------------------------------------------- */
+.an-topbar {
+ background: linear-gradient(90deg, var(--an-primary-dark), var(--an-primary));
+ color: var(--an-ink-on-dark-soft);
+ font-size: 13px;
+}
+
+.an-topbar-inner {
+ width: 1200px; max-width: calc(100% - 40px);
+ margin: 0 auto;
+ display: flex; align-items: center; justify-content: space-between;
+ min-height: 36px;
+}
+
+.an-topbar-date { letter-spacing: .5px; }
+
+.an-topbar-side { position: relative; }
+
+/* 院系切换:细字 + 箭头,展开为深蓝面板 */
+.an-colleges { position: relative; }
+
+.an-colleges-toggle {
+ display: inline-flex; align-items: center; gap: 6px;
+ padding: 4px 2px;
+ cursor: pointer;
+}
+.an-colleges-toggle a { color: var(--an-ink-on-dark-soft); }
+.an-colleges-toggle a:hover { color: #fff; }
+
+.an-colleges-arrow {
+ font-style: normal; font-size: 10px;
+ transition: transform var(--an-speed) ease;
+}
+.an-colleges:hover .an-colleges-arrow { transform: rotate(180deg); }
+
+.an-colleges-menu {
+ position: absolute; right: 0; top: calc(100% + 6px);
+ min-width: 180px; max-height: 280px; overflow: auto;
+ background: var(--an-panel);
+ backdrop-filter: blur(4px);
+ border-top: 2px solid var(--an-primary-light);
+ border-radius: 0 0 var(--an-radius) var(--an-radius);
+ box-shadow: var(--an-shadow-lg);
+ padding: 6px 0;
+ opacity: 0; visibility: hidden; transform: translateY(-6px);
+ transition: opacity var(--an-speed) ease, transform var(--an-speed) ease, visibility var(--an-speed);
+ z-index: 120;
+}
+.an-colleges:hover .an-colleges-menu,
+.an-colleges:focus-within .an-colleges-menu {
+ opacity: 1; visibility: visible; transform: translateY(0);
+}
+
+.an-colleges-menu li a {
+ display: block;
+ padding: 7px 16px;
+ color: var(--an-ink-on-dark);
+ font-size: 13px;
+ border-left: 2px solid transparent;
+ transition: background var(--an-speed) ease, border-color var(--an-speed) ease, padding-left var(--an-speed) ease;
+}
+.an-colleges-menu li a:hover {
+ background: var(--an-primary-dark);
+ border-left-color: var(--an-primary-light);
+ padding-left: 20px;
+ color: #fff;
+}
+.an-colleges-menu li.active a {
+ background: rgba(255,255,255,.08);
+ border-left-color: var(--an-primary-light);
+ color: #fff;
+}
+
+/* ---------------------------------------------------------------------
+ 4. 品牌行(深蓝主区:徽标 + 站名 + 圆角搜索)
+ --------------------------------------------------------------------- */
+.an-brandbar {
+ background: linear-gradient(100deg, var(--an-primary-dark) 0%, var(--an-primary) 62%, var(--an-primary-light) 130%);
+ color: var(--an-ink-on-dark);
+ position: relative;
+ overflow: hidden;
+}
+/* 品牌行右侧淡圆环装饰(CSS 绘制,无图片依赖) */
+.an-brandbar::before,
+.an-brandbar::after {
+ content: "";
+ position: absolute;
+ border-radius: 50%;
+ border: 26px solid rgba(255,255,255,.05);
+ pointer-events: none;
+}
+.an-brandbar::before { width: 320px; height: 320px; right: -80px; top: -170px; }
+.an-brandbar::after { width: 200px; height: 200px; right: 180px; bottom: -140px; border-width: 16px; }
+
+.an-brandbar-inner {
+ width: 1200px; max-width: calc(100% - 40px);
+ margin: 0 auto;
+ display: flex; align-items: center; justify-content: space-between;
+ gap: 24px;
+ padding: 22px 0;
+ position: relative; z-index: 1;
+}
+
+.an-brand {
+ display: flex; align-items: center; gap: 14px;
+ min-width: 0;
+}
+
+/* 徽标容器:白衬圆角方块,校徽任何底色都干净 */
+.an-brand-badge {
+ flex: none;
+ width: 58px; height: 58px;
+ display: inline-flex; align-items: center; justify-content: center;
+ background: rgba(255,255,255,.94);
+ border-radius: var(--an-radius);
+ box-shadow: 0 2px 8px rgba(6,49,97,.35);
+ overflow: hidden;
+}
+.an-brand-badge--plain { color: var(--an-primary); }
+.an-logo { width: 100%; height: 100%; object-fit: contain; }
+
+.an-site-name {
+ color: var(--an-ink-on-dark);
+ font-size: 27px;
+ font-weight: 700;
+ letter-spacing: 2px;
+ line-height: 1.3;
+ text-shadow: 0 2px 6px rgba(6,49,97,.4);
+ white-space: nowrap;
+ overflow: hidden; text-overflow: ellipsis;
+ max-width: 560px;
+}
+.an-site-name:hover { color: #fff; }
+
+/* 搜索:白色胶囊(学院风记忆点) */
+.an-search {
+ flex: none;
+ display: flex; align-items: center;
+ width: 300px; max-width: 36%;
+ background: #fff;
+ border-radius: 999px;
+ padding: 3px 4px 3px 18px;
+ box-shadow: 0 3px 10px rgba(6,49,97,.28);
+}
+.an-search input {
+ flex: 1; min-width: 0;
+ border: 0; outline: none;
+ background: transparent;
+ font-size: 13px; color: var(--an-text);
+ line-height: 30px;
+}
+.an-search input::placeholder { color: #a9b3c0; }
+.an-search button {
+ flex: none;
+ width: 32px; height: 32px;
+ border: 0; border-radius: 50%;
+ background: var(--an-primary);
+ color: #fff;
+ display: inline-flex; align-items: center; justify-content: center;
+ transition: background var(--an-speed) ease, transform var(--an-speed) ease;
+}
+.an-search button:hover { background: var(--an-primary-light); transform: scale(1.06); }
+
+/* ---------------------------------------------------------------------
+ 5. 主导航(白底条 + 主蓝半透明下拉面板 + 吸顶反蓝)
+ --------------------------------------------------------------------- */
+.an-nav {
+ background: var(--an-nav-bg);
+ box-shadow: var(--an-shadow-sm);
+ position: relative;
+ z-index: 100;
+}
+/* 顶部主蓝细线:把导航条与品牌行缝在一起 */
+.an-nav::before {
+ content: "";
+ display: block; height: 3px;
+ background: linear-gradient(90deg, var(--an-primary), var(--an-primary-light));
+}
+
+.an-nav-inner {
+ width: 1200px; max-width: calc(100% - 40px);
+ margin: 0 auto;
+ position: relative;
+}
+
+.an-nav-toggle { display: none; }
+
+.an-nav-list {
+ display: flex;
+ justify-content: space-between;
+}
+
+.an-nav-list > li { position: relative; flex: 1 1 auto; text-align: center; }
+
+.an-nav-list > li > a {
+ display: flex; align-items: center; justify-content: center; gap: 5px;
+ position: relative;
+ padding: 0 10px;
+ height: 52px;
+ font-size: 16px;
+ font-weight: 600;
+ letter-spacing: 1px;
+ color: var(--an-primary-dark);
+ white-space: nowrap;
+ transition: color var(--an-speed) ease, background var(--an-speed) ease;
+}
+/* 底部指示条:hover/当前项 */
+.an-nav-list > li > a::after {
+ content: "";
+ position: absolute; left: 50%; bottom: 0;
+ width: 0; height: 3px;
+ background: var(--an-primary);
+ transform: translateX(-50%);
+ transition: width var(--an-speed) ease;
+}
+.an-nav-list > li:hover > a,
+.an-nav-list > li.active > a {
+ color: var(--an-primary);
+ background: rgba(11,74,143,.06);
+}
+.an-nav-list > li:hover > a::after,
+.an-nav-list > li.active > a::after { width: 56%; }
+
+.an-caret {
+ font-style: normal; font-size: 11px;
+ opacity: .65;
+ transition: transform var(--an-speed) ease;
+}
+.an-nav-list > li:hover .an-caret { transform: rotate(180deg); }
+
+/* —— 下拉面板:主蓝半透明、顶部亮线、项 hover 加深 + 左亮条(红线第一优先级) —— */
+.an-sub {
+ position: absolute; left: 50%; top: 100%;
+ transform: translate(-50%, 10px);
+ min-width: 176px;
+ background: var(--an-panel);
+ backdrop-filter: blur(6px);
+ border-top: 3px solid var(--an-primary-light);
+ border-radius: 0 0 var(--an-radius) var(--an-radius);
+ box-shadow: var(--an-shadow-lg);
+ padding: 6px 0;
+ text-align: left;
+ opacity: 0; visibility: hidden;
+ transition: opacity var(--an-speed) ease, transform var(--an-speed) ease, visibility var(--an-speed);
+ z-index: 110;
+}
+.an-nav-list > li:hover .an-sub,
+.an-nav-list > li:focus-within .an-sub {
+ opacity: 1; visibility: visible;
+ transform: translate(-50%, 0);
+}
+
+/* 面板小尖角 */
+.an-sub::before {
+ content: "";
+ position: absolute; left: 50%; top: -8px;
+ width: 12px; height: 12px;
+ background: var(--an-primary);
+ transform: translateX(-50%) rotate(45deg);
+ border-radius: 2px 0 0 0;
+}
+
+.an-sub li a {
+ display: block;
+ position: relative;
+ margin: 2px 8px;
+ padding: 9px 14px 9px 22px;
+ font-size: 14px;
+ color: var(--an-ink-on-dark);
+ border-radius: 4px;
+ white-space: nowrap;
+ transition: background var(--an-speed) ease, padding-left var(--an-speed) ease, color var(--an-speed) ease;
+}
+/* 项前细刻度线 */
+.an-sub li a::before {
+ content: "";
+ position: absolute; left: 10px; top: 50%;
+ width: 4px; height: 4px;
+ margin-top: -2px;
+ background: rgba(255,255,255,.5);
+ border-radius: 50%;
+ transition: background var(--an-speed) ease, box-shadow var(--an-speed) ease;
+}
+.an-sub li a:hover {
+ background: var(--an-primary-dark);
+ padding-left: 26px;
+ color: #fff;
+}
+.an-sub li a:hover::before {
+ background: var(--an-primary-light);
+ box-shadow: 0 0 6px var(--an-primary-light);
+}
+
+/* —— 吸顶反蓝(.an-nav--fixed 由 main.js 滚动加挂) —— */
+.an-nav--fixed {
+ position: fixed; left: 0; right: 0; top: 0;
+ background: linear-gradient(90deg, var(--an-primary-dark), var(--an-primary));
+ box-shadow: var(--an-shadow-md);
+ animation: an-nav-drop var(--an-speed) ease;
+}
+@keyframes an-nav-drop {
+ from { transform: translateY(-100%); }
+ to { transform: translateY(0); }
+}
+.an-nav--fixed::before { height: 0; }
+.an-nav--fixed .an-nav-list > li > a { color: var(--an-ink-on-dark); }
+.an-nav--fixed .an-nav-list > li:hover > a,
+.an-nav--fixed .an-nav-list > li.active > a {
+ color: #fff;
+ background: rgba(255,255,255,.1);
+}
+.an-nav--fixed .an-nav-list > li > a::after { background: var(--an-primary-light); }
+/* 吸顶态下拉:底色更沉,与蓝条衔接 */
+.an-nav--fixed .an-sub { background: rgba(6,49,97,.96); }
+.an-nav--fixed .an-sub::before { background: var(--an-primary-dark); }
+
+/* 吸顶占位,防跳变(main.js 加挂时同步高度,解锁即移除) */
+.an-nav-holder { display: block; }
+
+/* ---------------------------------------------------------------------
+ 6. 首页 banner(通栏轮播 + 圆形箭头 + 底部圆点)
+ --------------------------------------------------------------------- */
+.an-banner {
+ position: relative;
+ overflow: hidden;
+ background: var(--an-primary-dark);
+}
+.an-banner-slides { position: relative; height: 520px; }
+
+.an-banner-slide {
+ position: absolute; inset: 0;
+ opacity: 0; visibility: hidden;
+ transition: opacity .8s ease, visibility .8s ease;
+}
+.an-banner-slide.active { opacity: 1; visibility: visible; z-index: 1; }
+
+.an-banner-slide img {
+ width: 100%; height: 100%;
+ object-fit: cover;
+}
+/* 底部渐隐遮罩上承标题 */
+.an-banner-slide::after {
+ content: "";
+ position: absolute; left: 0; right: 0; bottom: 0;
+ height: 120px;
+ background: linear-gradient(180deg, transparent, rgba(6,49,97,.66));
+ pointer-events: none;
+}
+.an-banner-slide.active img { animation: an-banner-zoom 6.5s ease forwards; }
+@keyframes an-banner-zoom {
+ from { transform: scale(1); }
+ to { transform: scale(1.045); }
+}
+
+.an-banner-title {
+ position: absolute; left: 6%; bottom: 34px;
+ z-index: 2;
+ max-width: 70%;
+ color: #fff;
+ font-size: 24px;
+ font-weight: 600;
+ letter-spacing: 1px;
+ text-shadow: 0 2px 8px rgba(6,49,97,.6);
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+}
+
+/* 圆形半透明箭头(建平语言) */
+.an-banner-arrow {
+ position: absolute; top: 50%; z-index: 3;
+ width: 52px; height: 52px; margin-top: -26px;
+ border: 2px solid rgba(255,255,255,.75);
+ border-radius: 50%;
+ background: rgba(6,49,97,.25);
+ color: #fff;
+ font-size: 26px; line-height: 1;
+ display: inline-flex; align-items: center; justify-content: center;
+ padding-bottom: 4px;
+ opacity: 0;
+ transition: opacity var(--an-speed) ease, background var(--an-speed) ease, border-color var(--an-speed) ease;
+}
+.an-banner:hover .an-banner-arrow { opacity: 1; }
+.an-banner-arrow:hover { background: var(--an-primary); border-color: #fff; }
+.an-banner-arrow.prev { left: 26px; }
+.an-banner-arrow.next { right: 26px; }
+
+/* 圆点指示器 */
+.an-banner-dots {
+ position: absolute; left: 0; right: 0; bottom: 18px;
+ z-index: 3;
+ display: flex; justify-content: center; gap: 10px;
+}
+.an-banner-dots button {
+ width: 10px; height: 10px;
+ border: 0; border-radius: 50%;
+ background: rgba(255,255,255,.55);
+ transition: background var(--an-speed) ease, transform var(--an-speed) ease;
+}
+.an-banner-dots button:hover { background: #fff; }
+.an-banner-dots button.active {
+ background: #fff;
+ transform: scale(1.25);
+ box-shadow: 0 0 0 3px rgba(255,255,255,.25);
+}
+
+/* ---------------------------------------------------------------------
+ 7. 区块标题(居中双线 + 下短横)与区块通用
+ --------------------------------------------------------------------- */
+.an-section { margin-top: 40px; }
+
+.an-block-head {
+ position: relative;
+ text-align: center;
+ padding: 14px 0 12px;
+ border-top: 1px solid var(--an-border);
+ border-bottom: 1px solid var(--an-border);
+}
+.an-block-head h2 {
+ display: inline-block;
+ position: relative;
+ font-size: 22px;
+ font-weight: 700;
+ letter-spacing: 3px;
+ color: var(--an-primary-dark);
+}
+/* 标题下短横:主蓝 3px */
+.an-block-tick {
+ position: absolute; left: 50%; bottom: -2px;
+ width: 42px; height: 3px;
+ transform: translateX(-50%);
+ background: var(--an-primary);
+ border-radius: 2px;
+}
+
+/* 栏目卡头变体:左右布局(标题居左 + 更多居右) */
+.an-block-head--bar {
+ text-align: left;
+ padding: 0 0 10px;
+ border-top: 0;
+ border-bottom: 2px solid var(--an-primary);
+ display: flex; align-items: baseline; justify-content: space-between;
+}
+.an-block-head--bar h2 {
+ font-size: 19px;
+ letter-spacing: 1px;
+ padding-left: 12px;
+ position: relative;
+}
+/* 标题左侧竖条 */
+.an-block-head--bar h2::before {
+ content: "";
+ position: absolute; left: 0; top: 6px; bottom: 6px;
+ width: 4px;
+ background: var(--an-primary);
+ border-radius: 2px;
+}
+.an-block-head--bar .an-block-tick { display: none; }
+
+.an-more {
+ font-size: 13px;
+ font-weight: 400;
+ color: var(--an-text-light);
+ letter-spacing: 0;
+ transition: color var(--an-speed) ease, transform var(--an-speed) ease;
+}
+.an-more:hover { color: var(--an-primary); transform: translateX(3px); }
+
+/* ---------------------------------------------------------------------
+ 8. 头条区(左:头条推荐列表 / 右:图片新闻)
+ --------------------------------------------------------------------- */
+.an-headline {
+ display: grid;
+ grid-template-columns: 7fr 5fr;
+ gap: 28px;
+}
+/* grid 项允许收缩到轨道内:否则 nowrap 省略文本会把 auto 最小宽撑破容器(移动端横向溢出) */
+.an-headline > * { min-width: 0; }
+
+.an-headline-card,
+.an-focus-card {
+ background: var(--an-card-bg);
+ border-radius: var(--an-radius-lg);
+ box-shadow: var(--an-shadow-sm);
+ padding: 6px 22px 18px;
+}
+
+/* 头条推荐 */
+.an-headline-list li {
+ display: flex; align-items: center; gap: 10px;
+ padding: 10px 2px;
+ border-bottom: 1px dashed var(--an-border);
+}
+.an-headline-list li:last-child { border-bottom: 0; }
+.an-headline-list li a {
+ flex: 1; min-width: 0;
+ color: var(--an-text);
+ font-size: 15px;
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+ transition: color var(--an-speed) ease, padding-left var(--an-speed) ease;
+}
+.an-headline-list li a:hover { color: var(--an-primary); padding-left: 4px; }
+.an-headline-list time { flex: none; color: var(--an-text-light); font-size: 13px; }
+
+/* 头条头条:大标题 + 元信息 */
+.an-headline-lead {
+ display: block !important;
+ padding: 14px 2px 16px !important;
+}
+.an-lead-title {
+ display: block;
+ font-size: 19px !important;
+ font-weight: 700;
+ color: var(--an-primary-dark) !important;
+ line-height: 1.5;
+ white-space: normal !important;
+ overflow: hidden;
+ max-height: 3em;
+}
+.an-lead-title:hover { color: var(--an-primary) !important; padding-left: 0 !important; }
+.an-lead-meta {
+ display: flex; align-items: center; gap: 10px;
+ margin-top: 8px;
+ font-size: 13px; color: var(--an-text-light);
+}
+
+/* 图片新闻 */
+.an-focus-lead {
+ display: block;
+ margin-top: 14px;
+ border-radius: var(--an-radius);
+ overflow: hidden;
+ position: relative;
+}
+.an-focus-cover { display: block; aspect-ratio: 16/9; overflow: hidden; background: var(--an-bg); }
+.an-focus-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
+.an-focus-lead:hover .an-focus-cover img { transform: scale(1.05); }
+.an-focus-title {
+ position: absolute; left: 0; right: 0; bottom: 0;
+ padding: 26px 14px 10px;
+ color: #fff; font-size: 15px; font-weight: 600;
+ background: linear-gradient(180deg, transparent, rgba(6,49,97,.82));
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+}
+
+.an-focus-rows { margin-top: 10px; }
+.an-focus-rows li a {
+ display: flex; align-items: center; gap: 12px;
+ padding: 8px 0;
+}
+.an-row-cover {
+ flex: none;
+ width: 104px; height: 66px;
+ border-radius: 4px;
+ overflow: hidden;
+ background: var(--an-bg);
+}
+.an-row-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
+.an-focus-rows li a:hover .an-row-cover img { transform: scale(1.06); }
+.an-row-title {
+ flex: 1; min-width: 0;
+ color: var(--an-text);
+ font-size: 14px;
+ line-height: 1.55;
+ max-height: 3.1em;
+ overflow: hidden;
+ transition: color var(--an-speed) ease;
+}
+.an-focus-rows li a:hover .an-row-title { color: var(--an-primary); }
+
+/* ---------------------------------------------------------------------
+ 9. 栏目区块(白卡三列 + 日期方块行)
+ --------------------------------------------------------------------- */
+.an-blocks {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 24px;
+ margin-top: 14px;
+}
+
+.an-block {
+ background: var(--an-card-bg);
+ border-radius: var(--an-radius-lg);
+ box-shadow: var(--an-shadow-sm);
+ padding: 18px 20px 14px;
+ display: flex; flex-direction: column;
+ min-width: 0;
+ transition: box-shadow var(--an-speed) ease, transform var(--an-speed) ease;
+}
+.an-block:hover { box-shadow: var(--an-shadow-md); transform: translateY(-2px); }
+
+.an-block-list { flex: 1; }
+
+/* 区块头条(有封面图文 / 无封面纯文) */
+.an-block-featured { border-bottom: 1px solid var(--an-border); }
+.an-block-featured > a {
+ display: block;
+ padding: 12px 0 14px;
+}
+.an-feat-cover {
+ display: block;
+ aspect-ratio: 16/9;
+ border-radius: var(--an-radius);
+ overflow: hidden;
+ background: var(--an-bg);
+ margin-bottom: 10px;
+}
+.an-feat-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
+.an-block-featured > a:hover .an-feat-cover img { transform: scale(1.04); }
+
+.an-feat-title {
+ display: block;
+ font-size: 16px; font-weight: 700;
+ color: var(--an-primary-dark);
+ line-height: 1.5;
+ max-height: 3em;
+ overflow: hidden;
+ transition: color var(--an-speed) ease;
+}
+.an-block-featured > a:hover .an-feat-title { color: var(--an-primary); }
+.an-feat-summary {
+ display: block;
+ margin-top: 6px;
+ font-size: 13px; color: var(--an-text-light);
+ line-height: 1.65;
+ max-height: 3.3em;
+ overflow: hidden;
+}
+.an-feat-meta {
+ display: flex; align-items: center; gap: 10px;
+ margin-top: 8px;
+ font-size: 12px; color: var(--an-text-light);
+}
+
+/* 列表行:日期方块 + 标题(建平通知公告语言) */
+.an-block-item {
+ display: flex; align-items: center; gap: 12px;
+ padding: 8px 0;
+ border-bottom: 1px dashed var(--an-border);
+}
+.an-block-item:last-child { border-bottom: 0; }
+
+.an-date-chip {
+ flex: none;
+ width: 46px;
+ text-align: center;
+ border-radius: 4px;
+ overflow: hidden;
+ background: var(--an-bg);
+ border: 1px solid var(--an-border);
+ transition: background var(--an-speed) ease, border-color var(--an-speed) ease;
+}
+.an-date-chip b {
+ display: block;
+ font-size: 17px; line-height: 24px;
+ font-weight: 700;
+ color: var(--an-primary);
+ background: rgba(11,74,143,.08);
+ transition: color var(--an-speed) ease;
+}
+.an-date-chip i {
+ display: block;
+ font-style: normal;
+ font-size: 10px; line-height: 16px;
+ color: var(--an-text-light);
+ transform: scale(.92);
+}
+.an-block-item:hover .an-date-chip {
+ background: var(--an-primary);
+ border-color: var(--an-primary);
+}
+.an-block-item:hover .an-date-chip b { color: #fff; background: transparent; }
+.an-block-item:hover .an-date-chip i { color: rgba(255,255,255,.8); }
+
+.an-block-item-title {
+ flex: 1; min-width: 0;
+ font-size: 14px;
+ color: var(--an-text);
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+ transition: color var(--an-speed) ease;
+}
+.an-block-item:hover .an-block-item-title { color: var(--an-primary); }
+
+/* ---------------------------------------------------------------------
+ 10. 列表/详情/单页公共:页面卡 + 面包屑 + 页题
+ --------------------------------------------------------------------- */
+.an-page { padding: 28px 0 48px; }
+
+.an-page-card {
+ background: var(--an-card-bg);
+ border-radius: var(--an-radius-lg);
+ box-shadow: var(--an-shadow-sm);
+ padding: 26px 32px 34px;
+ min-height: 420px;
+}
+
+.an-crumb {
+ display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
+ font-size: 13px;
+ color: var(--an-text-light);
+ padding-bottom: 14px;
+ border-bottom: 1px solid var(--an-border);
+ margin-bottom: 20px;
+}
+.an-crumb a { color: var(--an-text-light); }
+.an-crumb a:hover { color: var(--an-primary); }
+.an-crumb-sep { color: #c3cad4; }
+.an-crumb-current { color: var(--an-primary); }
+
+.an-page-title {
+ position: relative;
+ font-size: 23px;
+ font-weight: 700;
+ letter-spacing: 1px;
+ color: var(--an-primary-dark);
+ padding-left: 16px;
+ margin-bottom: 22px;
+}
+.an-page-title::before {
+ content: "";
+ position: absolute; left: 0; top: 5px; bottom: 5px;
+ width: 5px;
+ border-radius: 3px;
+ background: linear-gradient(180deg, var(--an-primary), var(--an-primary-light));
+}
+
+/* ---------------------------------------------------------------------
+ 11. 列表页:图文行 + 行式列表 + 分页
+ --------------------------------------------------------------------- */
+.an-article-list > li { border-bottom: 1px solid var(--an-border); }
+.an-article-list > li:last-child { border-bottom: 0; }
+
+/* 图文行 */
+.an-article-row {
+ display: flex; gap: 20px;
+ padding: 18px 2px;
+}
+.an-item-cover {
+ flex: none;
+ width: 216px; aspect-ratio: 3/2;
+ border-radius: var(--an-radius);
+ overflow: hidden;
+ background: var(--an-bg);
+}
+.an-item-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
+.an-article-row:hover .an-item-cover img { transform: scale(1.05); }
+
+.an-item-body { flex: 1; min-width: 0; padding-top: 4px; }
+.an-item-title a {
+ font-size: 17px; font-weight: 600;
+ color: var(--an-text);
+ line-height: 1.5;
+ transition: color var(--an-speed) ease;
+}
+.an-item-title a:hover { color: var(--an-primary); }
+.an-item-summary {
+ margin-top: 8px;
+ font-size: 13px; color: var(--an-text-light);
+ line-height: 1.7;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+.an-item-meta {
+ display: flex; align-items: center; gap: 12px;
+ margin-top: 10px;
+ font-size: 12px; color: var(--an-text-light);
+}
+
+/* 行式(无封面):刻度符号 + 标题 + 右侧日期 */
+.an-article-line {
+ display: flex; align-items: center; gap: 12px;
+ padding: 13px 2px;
+}
+.an-line-tick {
+ flex: none;
+ width: 6px; height: 6px;
+ background: var(--an-primary);
+ transform: rotate(45deg);
+ opacity: .85;
+ transition: transform var(--an-speed) ease;
+}
+.an-article-line:hover .an-line-tick { transform: rotate(45deg) scale(1.35); }
+
+.an-line-main { flex: 1; min-width: 0; }
+.an-line-title {
+ display: block;
+ font-size: 15px;
+ color: var(--an-text);
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+ transition: color var(--an-speed) ease, padding-left var(--an-speed) ease;
+}
+.an-article-line:hover .an-line-title { color: var(--an-primary); padding-left: 4px; }
+.an-article-line .an-item-summary { margin-top: 4px; -webkit-line-clamp: 1; }
+
+.an-line-side {
+ flex: none;
+ display: flex; align-items: center; gap: 10px;
+ font-size: 13px; color: var(--an-text-light);
+}
+
+/* 分页 */
+.an-pagination {
+ display: flex; justify-content: center; flex-wrap: wrap; gap: 8px;
+ margin-top: 30px;
+}
+.an-pagination a {
+ min-width: 36px; height: 36px;
+ display: inline-flex; align-items: center; justify-content: center;
+ padding: 0 10px;
+ font-size: 14px;
+ color: var(--an-text);
+ background: var(--an-bg);
+ border: 1px solid var(--an-border);
+ border-radius: 4px;
+ transition: all var(--an-speed) ease;
+}
+.an-pagination a:hover {
+ color: #fff;
+ background: var(--an-primary);
+ border-color: var(--an-primary);
+}
+.an-pagination a.active {
+ color: #fff;
+ background: var(--an-primary);
+ border-color: var(--an-primary);
+ font-weight: 700;
+ box-shadow: 0 3px 8px rgba(11,74,143,.35);
+}
+.an-pagination a.disabled {
+ opacity: .45; pointer-events: none;
+}
+
+/* ---------------------------------------------------------------------
+ 12. 详情/单页:文章排版
+ --------------------------------------------------------------------- */
+.an-article-title {
+ text-align: center;
+ font-size: 24px;
+ font-weight: 700;
+ color: var(--an-primary-dark);
+ line-height: 1.5;
+ padding: 6px 20px 0;
+}
+
+.an-article-meta {
+ display: flex; justify-content: center; flex-wrap: wrap; gap: 6px 22px;
+ padding: 14px 0 18px;
+ margin-bottom: 24px;
+ font-size: 13px; color: var(--an-text-light);
+ border-bottom: 1px solid var(--an-border);
+ position: relative;
+}
+/* 标题下居中短横(与区块标题语言呼应) */
+.an-article-meta::before {
+ content: "";
+ position: absolute; left: 50%; top: -12px;
+ width: 42px; height: 3px;
+ transform: translateX(-50%);
+ background: var(--an-primary);
+ border-radius: 2px;
+}
+
+.an-article-content {
+ font-size: 15px;
+ line-height: 1.9;
+ color: var(--an-text);
+}
+.an-article-content p { margin: 0 0 14px; }
+.an-article-content h1, .an-article-content h2,
+.an-article-content h3, .an-article-content h4 {
+ margin: 22px 0 12px;
+ color: var(--an-primary-dark);
+ font-weight: 700;
+}
+.an-article-content h2 { font-size: 19px; }
+.an-article-content h3 { font-size: 17px; }
+.an-article-content h4 { font-size: 15px; }
+.an-article-content img {
+ max-width: 100%;
+ height: auto;
+ border-radius: var(--an-radius);
+ margin: 6px auto 14px;
+ box-shadow: var(--an-shadow-sm);
+}
+.an-article-content ul, .an-article-content ol {
+ margin: 0 0 14px; padding-left: 26px;
+}
+.an-article-content ul li { list-style: disc; }
+.an-article-content ol li { list-style: decimal; }
+.an-article-content li { margin-bottom: 6px; }
+.an-article-content blockquote {
+ margin: 14px 0;
+ padding: 12px 18px;
+ background: rgba(11,74,143,.05);
+ border-left: 4px solid var(--an-primary);
+ border-radius: 0 var(--an-radius) var(--an-radius) 0;
+ color: var(--an-text-light);
+}
+.an-article-content table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 14px 0;
+ font-size: 14px;
+}
+.an-article-content th, .an-article-content td {
+ border: 1px solid var(--an-border);
+ padding: 8px 12px;
+ text-align: left;
+}
+.an-article-content th {
+ background: rgba(11,74,143,.06);
+ color: var(--an-primary-dark);
+ font-weight: 600;
+}
+.an-article-content a { color: var(--an-primary-light); text-decoration: underline; }
+.an-article-content hr {
+ border: 0; height: 1px;
+ background: var(--an-border);
+ margin: 20px 0;
+}
+.an-article-content video, .an-article-content audio { max-width: 100%; }
+
+/* 上下篇 */
+.an-sibling {
+ display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
+ margin-top: 34px;
+ padding-top: 22px;
+ border-top: 1px solid var(--an-border);
+}
+.an-sib, .an-sib-none {
+ display: block;
+ padding: 12px 16px;
+ border: 1px solid var(--an-border);
+ border-radius: var(--an-radius);
+ background: var(--an-bg);
+ min-width: 0;
+ transition: border-color var(--an-speed) ease, background var(--an-speed) ease, box-shadow var(--an-speed) ease;
+}
+.an-sib:hover {
+ border-color: var(--an-primary);
+ background: var(--an-card-bg);
+ box-shadow: var(--an-shadow-sm);
+}
+.an-sib.next { text-align: right; }
+.an-sib-label {
+ display: block;
+ font-size: 12px;
+ color: var(--an-primary);
+ letter-spacing: 2px;
+ margin-bottom: 4px;
+}
+.an-sib-title {
+ display: block;
+ font-size: 14px;
+ color: var(--an-text);
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+}
+.an-sib-none { opacity: .6; }
+.an-sib-none .an-sib-label { color: var(--an-text-light); }
+
+/* ---------------------------------------------------------------------
+ 13. 页脚(深蓝渐变 + 同心圆环纹理 + 三栏 + 底条)
+ --------------------------------------------------------------------- */
+.an-footer {
+ position: relative;
+ margin-top: 56px;
+ color: var(--an-ink-on-dark);
+ background: linear-gradient(160deg, var(--an-footer-bg) 0%, var(--an-primary-dark) 100%);
+ overflow: hidden;
+}
+
+/* 同心圆环纹理(CSS 绘制,呼应校徽环形语言) */
+.an-ring {
+ position: absolute;
+ border-radius: 50%;
+ border: 2px solid rgba(255,255,255,.06);
+ pointer-events: none;
+}
+.an-ring--1 { width: 460px; height: 460px; right: -140px; top: -160px; border-width: 30px; }
+.an-ring--2 { width: 300px; height: 300px; right: -60px; top: -80px; border-width: 18px; }
+.an-ring--3 { width: 520px; height: 520px; left: -200px; bottom: -300px; border-width: 34px; }
+
+.an-footer-inner {
+ width: 1200px; max-width: calc(100% - 40px);
+ margin: 0 auto;
+ position: relative; z-index: 1;
+ display: grid;
+ grid-template-columns: 1.1fr 1.2fr 1.4fr;
+ gap: 40px;
+ padding: 44px 0 36px;
+}
+.an-footer-inner > * { min-width: 0; }
+
+.an-footer-brand {
+ display: flex; align-items: center; gap: 14px;
+}
+.an-footer-badge {
+ flex: none;
+ width: 66px; height: 66px;
+ display: inline-flex; align-items: center; justify-content: center;
+ background: rgba(255,255,255,.94);
+ border-radius: var(--an-radius);
+ overflow: hidden;
+ box-shadow: 0 2px 10px rgba(6,49,97,.4);
+}
+.an-footer-badge--plain { color: var(--an-primary); }
+.an-footer-logo { width: 100%; height: 100%; object-fit: contain; }
+.an-footer-site {
+ font-size: 21px;
+ font-weight: 700;
+ letter-spacing: 1.5px;
+ line-height: 1.45;
+ text-shadow: 0 2px 6px rgba(6,49,97,.4);
+}
+
+.an-footer-info { padding-top: 6px; }
+.an-footer-line {
+ display: flex; align-items: baseline; gap: 10px;
+ margin-bottom: 10px;
+ font-size: 13px;
+ color: var(--an-ink-on-dark-soft);
+ line-height: 1.7;
+}
+.an-dot {
+ flex: none;
+ width: 6px; height: 6px;
+ background: var(--an-primary-light);
+ border-radius: 50%;
+ transform: translateY(-2px);
+ box-shadow: 0 0 6px rgba(17,103,187,.9);
+}
+
+.an-footer-links {
+ padding-top: 6px;
+ display: grid; grid-template-columns: 1fr 1fr; gap: 8px 28px;
+}
+.an-group-name {
+ display: inline-block;
+ font-size: 13px; font-weight: 600;
+ color: #fff;
+ padding-bottom: 4px;
+ margin-bottom: 6px;
+ border-bottom: 2px solid var(--an-primary-light);
+}
+.an-links-row {
+ display: flex; flex-wrap: wrap; gap: 4px 14px;
+ margin-bottom: 10px;
+}
+.an-links-row a {
+ font-size: 13px;
+ color: var(--an-ink-on-dark-soft);
+ transition: color var(--an-speed) ease, padding-left var(--an-speed) ease;
+}
+.an-links-row a:hover { color: #fff; padding-left: 2px; }
+
+.an-footer-bottom {
+ position: relative; z-index: 1;
+ border-top: 1px solid rgba(255,255,255,.14);
+ text-align: center;
+ padding: 16px 0;
+ font-size: 13px;
+ color: var(--an-ink-on-dark-faint);
+ letter-spacing: 1px;
+}
+
+/* ---------------------------------------------------------------------
+ 14. 响应式:1200 / 992 / 768 三档
+ --------------------------------------------------------------------- */
+@media (max-width: 1240px) {
+ .an-container, .an-topbar-inner, .an-brandbar-inner, .an-nav-inner { max-width: calc(100% - 40px); }
+}
+
+@media (max-width: 992px) {
+ .an-site-name { font-size: 22px; max-width: 380px; }
+ .an-search { width: 240px; }
+
+ .an-nav-list { flex-wrap: wrap; justify-content: flex-start; }
+ .an-nav-list > li { flex: 0 0 auto; }
+ .an-nav-list > li > a { height: 46px; font-size: 15px; padding: 0 12px; }
+
+ .an-headline { grid-template-columns: 1fr; }
+ .an-blocks { grid-template-columns: repeat(2, 1fr); }
+
+ .an-banner-slides { height: 380px; }
+ .an-banner-title { font-size: 19px; bottom: 28px; }
+
+ .an-footer-inner { grid-template-columns: 1fr 1fr; }
+}
+
+@media (max-width: 768px) {
+ /* —— 品牌行收纳 —— */
+ .an-brandbar-inner { flex-direction: column; align-items: stretch; gap: 14px; padding: 16px 0; }
+ .an-site-name { font-size: 19px; max-width: none; white-space: normal; }
+ .an-brand { justify-content: center; }
+ .an-search { width: 100%; max-width: none; }
+
+ /* —— 移动端导航:抽屉展开 —— */
+ .an-nav-toggle {
+ display: inline-flex; flex-direction: column; justify-content: center; gap: 5px;
+ width: 44px; height: 40px;
+ padding: 8px;
+ border: 1px solid var(--an-border);
+ border-radius: var(--an-radius);
+ background: var(--an-card-bg);
+ }
+ .an-nav-toggle span {
+ display: block; height: 2px;
+ background: var(--an-primary);
+ border-radius: 2px;
+ transition: transform var(--an-speed) ease, opacity var(--an-speed) ease;
+ }
+ .an-nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
+ .an-nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
+ .an-nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
+
+ .an-nav-inner { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; }
+ /* 吸顶在移动端直接融入文档流配色 */
+ .an-nav--fixed { position: sticky; animation: none; }
+
+ .an-nav-list {
+ display: none;
+ position: absolute; left: -20px; right: -20px; top: 100%;
+ flex-direction: column;
+ background: var(--an-card-bg);
+ box-shadow: var(--an-shadow-md);
+ border-top: 1px solid var(--an-border);
+ padding: 6px 16px 12px;
+ max-height: 68vh; overflow: auto;
+ }
+ .an-nav-list.an-open { display: flex; }
+ .an-nav-list > li { text-align: left; border-bottom: 1px solid var(--an-border); }
+ .an-nav-list > li:last-child { border-bottom: 0; }
+ .an-nav-list > li > a { height: 46px; justify-content: flex-start; }
+ .an-nav-list > li > a::after { display: none; }
+
+ /* 移动端二级:手风琴内联展开(.an-sub-open 由 main.js 控制) */
+ .an-sub {
+ position: static;
+ display: none;
+ transform: none;
+ opacity: 1; visibility: visible;
+ background: var(--an-bg);
+ border-top: 0;
+ box-shadow: none;
+ border-radius: 0;
+ margin: 0 -8px 8px;
+ padding: 4px 0;
+ }
+ .an-sub::before { display: none; }
+ .an-sub li a { color: var(--an-text); margin: 0 8px; }
+ .an-sub li a:hover { background: rgba(11,74,143,.08); color: var(--an-primary); }
+ .an-sub li a::before { background: var(--an-primary); opacity: .5; }
+ .an-nav-list li.an-sub-open .an-sub { display: block; }
+ .an-nav-list li.has-sub > a { cursor: pointer; }
+
+ /* —— 内容收纳 —— */
+ .an-banner-slides { height: 240px; }
+ .an-banner-title { font-size: 15px; left: 16px; bottom: 20px; max-width: 85%; }
+ .an-banner-arrow { display: none; }
+
+ .an-section { margin-top: 28px; }
+ .an-blocks { grid-template-columns: 1fr; }
+ .an-block-head h2 { font-size: 19px; }
+
+ .an-article-row { flex-direction: column; gap: 12px; }
+ .an-item-cover { width: 100%; }
+ .an-article-line { flex-wrap: wrap; }
+ .an-line-side { width: 100%; padding-left: 18px; }
+
+ .an-page-card { padding: 18px 16px 24px; }
+ .an-article-title { font-size: 20px; padding: 0; }
+ .an-article-meta { gap: 4px 14px; }
+ .an-sibling { grid-template-columns: 1fr; }
+ .an-sib-title { white-space: normal; }
+
+ .an-footer-inner { grid-template-columns: 1fr; gap: 26px; padding: 32px 0 26px; }
+ .an-footer-links { grid-template-columns: 1fr; }
+ .an-ring--1 { width: 300px; height: 300px; border-width: 20px; }
+}
+
+/* ---------------------------------------------------------------------
+ 15. 动效偏好:尊重系统减弱动态设置
+ --------------------------------------------------------------------- */
+@media (prefers-reduced-motion: reduce) {
+ *, *::before, *::after {
+ animation-duration: .01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: .01ms !important;
+ }
+}
+
+/* B4 友链 Logo:与名称并排小图(高度 ~20px,垂直居中;过宽截断不撑破页脚) */
+.links-group a .link-logo,
+.an-links-row a .link-logo {
+ height: 20px;
+ width: auto;
+ max-width: 64px;
+ object-fit: contain;
+ vertical-align: middle;
+ margin-right: 4px;
+ border-radius: 2px;
+}
+
+/* ===== 左侧栏目导航(docs/11):有二级节点的模块,栏目/文章页左侧展示兄弟目录 ===== */
+.an-cols { display: flex; align-items: flex-start; gap: 28px; }
+.an-cols .an-page-card { flex: 1; min-width: 0; }
+.an-side-nav {
+ flex: none;
+ width: 230px;
+ background: var(--an-card-bg);
+ border: 1px solid var(--an-border);
+ border-top: 3px solid var(--an-primary);
+ box-shadow: var(--an-shadow-md);
+}
+.an-side-nav-head {
+ background: var(--an-primary);
+ color: #fff;
+ font-size: 20px;
+ font-weight: 700;
+ text-align: center;
+ padding: 18px 12px;
+ letter-spacing: 3px;
+}
+.an-side-nav-list { list-style: none; margin: 0; padding: 0; }
+.an-side-nav-item + .an-side-nav-item { border-top: 1px solid var(--an-border); }
+.an-side-nav-item a {
+ display: block;
+ padding: 13px 18px;
+ color: var(--an-text);
+ text-decoration: none;
+ font-size: 15px;
+ border-left: 3px solid transparent;
+ transition: background .15s ease, color .15s ease, border-color .15s ease;
+}
+.an-side-nav-item a:hover { color: var(--an-primary); background: var(--an-panel); }
+.an-side-nav-item.active a {
+ background: var(--an-primary);
+ color: #fff;
+ font-weight: 600;
+ text-decoration: none;
+ border-left-color: var(--an-primary-light);
+}
+/* 顶导航二级下拉当前项高亮(docs/11 顺带) */
+.an-nav-list ul.an-sub li.active a { color: var(--an-primary-light); }
+@media (max-width: 768px) {
+ .an-cols { flex-direction: column; gap: 16px; }
+ .an-side-nav { width: 100%; }
+ .an-side-nav-list { display: flex; overflow-x: auto; -webkit-overflow-scrolling: touch; }
+ .an-side-nav-item { flex: none; }
+ .an-side-nav-item + .an-side-nav-item { border-top: none; border-left: 1px solid var(--an-border); }
+ .an-side-nav-item a { white-space: nowrap; border-left: none; }
+}
+@media print {
+ .an-side-nav { display: none; }
+ .an-cols { display: block; }
+}
+
+/* ---------------------------------------------------------------------
+ 16. 首页布局模式区块(fragments/home-blocks.html)
+ 站点配了 home_layout 时首页正文由本主题渲染:整宽区块卡 + 双栏要闻 + 藏蓝速递条。
+ --------------------------------------------------------------------- */
+/* 藏蓝配金线:标题左竖条与居中线脚改用点缀金,区别于基座 scholar-blue 的全蓝语言 */
+.an-block-head--bar h2::before { background: var(--an-accent); }
+.an-block-tick { background: var(--an-accent); }
+
+.an-section { position: relative; }
+.an-sec-bg {
+ position: absolute; inset: 0; z-index: 0;
+ background-size: cover; background-position: center;
+ opacity: .45; pointer-events: none;
+}
+/* 定位元素默认画在普通流之上:不抬 z-index,背景带会糊在卡片正面(截图实测整卡泛绿)。
+ 带图时卡片转半透明白,让底图若隐若现——高校官网新闻带的通行做法 */
+.an-sec-bg + .an-block { position: relative; z-index: 1; background: rgba(255, 255, 255, .88); }
+.an-block--flow { padding: 20px 26px 12px; }
+.an-block--flow:hover { transform: none; box-shadow: var(--an-shadow-sm); }
+/* grid 轨道用 minmax(0,1fr):否则 nowrap 省略行的 min-content 会撑破轨道(中文标题尤其明显) */
+.an-split {
+ display: grid;
+ grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
+ gap: 26px;
+ padding-top: 14px;
+}
+.an-split > * { min-width: 0; }
+/* 头条图限高 + 右列行均分:否则左图按 16/9 撑到 400px,右列 5 行挤在顶部留大片空白 */
+.an-split .an-feat-cover { max-height: 300px; }
+.an-split .an-block-list { display: flex; flex-direction: column; justify-content: space-between; }
+.an-split .an-block-item { padding: 12px 0; }
+.an-block-list--two { columns: 2; column-gap: 34px; }
+.an-block-list--two .an-block-item { break-inside: avoid; }
+.an-feat-cover--row { aspect-ratio: 16 / 7; }
+.an-item-date {
+ flex: none;
+ font-size: 12px; color: var(--an-text-light);
+ font-variant-numeric: tabular-nums;
+}
+.an-src {
+ flex: none;
+ font-size: 11px; line-height: 18px; padding: 0 6px;
+ color: var(--an-primary); border: 1px solid var(--an-primary);
+ border-radius: 2px;
+}
+.an-wall {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 14px;
+ margin: 16px 0 0;
+}
+.an-wall-item {
+ position: relative;
+ border-radius: var(--an-radius);
+ overflow: hidden;
+ box-shadow: var(--an-shadow-sm);
+}
+.an-wall-item img { width: 100%; height: 158px; object-fit: cover; transition: transform .5s ease; }
+.an-wall-item:hover img { transform: scale(1.05); }
+.an-wall-cap {
+ position: absolute; left: 0; right: 0; bottom: 0;
+ padding: 26px 10px 9px;
+ font-size: 13px; color: #fff;
+ background: linear-gradient(transparent, rgba(6, 49, 97, .85));
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+}
+.an-gallery-sub {
+ margin: -4px 0 4px;
+ text-align: center;
+ font-size: 12px; letter-spacing: .18em; text-transform: uppercase;
+ color: var(--an-text-light);
+}
+/* 速递条:flex 项自动最小尺寸 = min-content,中文可按字断行 → 不锁 nowrap/不收缩就会塌成一字一列 */
+.an-ticker {
+ position: relative;
+ background: var(--an-primary);
+ color: #fff;
+ padding: 11px 0;
+ font-size: 14px;
+}
+.an-ticker-inner { display: flex; align-items: center; gap: 16px; min-width: 0; }
+.an-ticker-label {
+ flex: none;
+ font-weight: 700; letter-spacing: .06em;
+ padding-right: 14px;
+ border-right: 1px solid rgba(255, 255, 255, .35);
+}
+.an-ticker-list {
+ display: flex; gap: 28px;
+ flex: 1; min-width: 0;
+ overflow: hidden; white-space: nowrap;
+}
+.an-ticker-list li { flex: none; min-width: 0; }
+.an-ticker-item {
+ display: block; flex: none;
+ max-width: 320px;
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+ color: #fff; opacity: .92;
+}
+.an-ticker-item:hover { opacity: 1; text-decoration: underline; }
+.an-links-group {
+ margin: 12px 0 0;
+ font-size: 13px; letter-spacing: .08em;
+ color: var(--an-text-light);
+}
+.an-links { display: flex; flex-wrap: wrap; gap: 10px; margin: 8px 0 0; }
+.an-links a {
+ font-size: 13px; color: var(--an-text-light);
+ padding: 4px 14px;
+ background: var(--an-card-bg);
+ border: 1px solid var(--an-border);
+ border-radius: 999px;
+}
+.an-links a:hover { color: var(--an-primary); border-color: var(--an-primary); }
+
+@media (max-width: 992px) {
+ .an-split { grid-template-columns: minmax(0, 1fr); }
+ .an-wall { grid-template-columns: repeat(2, minmax(0, 1fr)); }
+ .an-block-list--two { columns: 1; }
+ .an-ticker-item { max-width: 180px; }
+ .an-block--flow { padding: 16px 16px 8px; }
+}
diff --git a/src/main/resources/templates/themes/academic-navy/assets/favicon.png b/src/main/resources/templates/themes/academic-navy/assets/favicon.png
new file mode 100644
index 0000000..ac16156
Binary files /dev/null and b/src/main/resources/templates/themes/academic-navy/assets/favicon.png differ
diff --git a/src/main/resources/templates/themes/academic-navy/assets/favicon.svg b/src/main/resources/templates/themes/academic-navy/assets/favicon.svg
new file mode 100644
index 0000000..b64acaf
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/assets/favicon.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/main/resources/templates/themes/academic-navy/assets/js/main.js b/src/main/resources/templates/themes/academic-navy/assets/js/main.js
new file mode 100644
index 0000000..4d2397b
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/assets/js/main.js
@@ -0,0 +1,190 @@
+/* academic-navy 主题脚本:顶栏日期 + 轮播(圆点/箭头/触摸) + 导航吸顶反蓝 + 移动端抽屉与二级手风琴。
+ 与 default 同源逻辑,无任何外部依赖。 */
+(function () {
+ 'use strict';
+
+ /* ---------- 顶栏日期(本地时间,YYYY年M月D日 星期X) ---------- */
+ var dateEl = document.getElementById('siteDate');
+ if (dateEl) {
+ var now = new Date();
+ var week = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()];
+ dateEl.textContent = now.getFullYear() + '年' + (now.getMonth() + 1) + '月'
+ + now.getDate() + '日 星期' + week;
+ }
+
+ /* ---------- 导航吸顶反蓝(桌面端;≤768 不吸顶) ---------- */
+ var nav = document.getElementById('anNav');
+ var DESKTOP_MIN = 769;
+ var navBaseTop = 0;
+ var holder = null;
+
+ function measureNavTop() {
+ unlockNav();
+ navBaseTop = nav.getBoundingClientRect().top + window.pageYOffset;
+ }
+
+ function lockNav() {
+ if (!nav.classList.contains('an-nav--fixed')) {
+ holder = document.createElement('div');
+ holder.className = 'an-nav-holder';
+ holder.style.height = nav.offsetHeight + 'px';
+ nav.parentNode.insertBefore(holder, nav);
+ nav.classList.add('an-nav--fixed');
+ } else if (holder) {
+ holder.style.height = nav.offsetHeight + 'px';
+ }
+ }
+
+ function unlockNav() {
+ nav.classList.remove('an-nav--fixed');
+ if (holder && holder.parentNode) {
+ holder.parentNode.removeChild(holder);
+ }
+ holder = null;
+ }
+
+ function onScrollNav() {
+ if (window.innerWidth < DESKTOP_MIN) {
+ unlockNav();
+ return;
+ }
+ if (window.pageYOffset > navBaseTop) {
+ lockNav();
+ } else {
+ unlockNav();
+ }
+ }
+
+ if (nav) {
+ measureNavTop();
+ window.addEventListener('scroll', onScrollNav, { passive: true });
+ var resizeTimer = null;
+ window.addEventListener('resize', function () {
+ if (resizeTimer) { window.clearTimeout(resizeTimer); }
+ resizeTimer = window.setTimeout(function () {
+ measureNavTop();
+ onScrollNav();
+ }, 150);
+ });
+ }
+
+ /* ---------- 移动端抽屉 + 二级手风琴 ---------- */
+ var navToggle = document.querySelector('.an-nav-toggle');
+ var navList = document.querySelector('.an-nav-list');
+
+ if (navToggle && navList) {
+ navToggle.addEventListener('click', function () {
+ var open = navList.classList.toggle('an-open');
+ navToggle.setAttribute('aria-expanded', open ? 'true' : 'false');
+ });
+ }
+
+ /* 窄屏下:点击带二级的项先展开面板,再点才跳转;宽屏交还给 CSS hover */
+ if (navList) {
+ navList.addEventListener('click', function (e) {
+ if (window.innerWidth >= DESKTOP_MIN) { return; }
+ var link = e.target.closest ? e.target.closest('a') : null;
+ if (!link) { return; }
+ var li = link.parentElement;
+ if (!li || !li.classList.contains('has-sub')) { return; }
+ var sub = li.querySelector('.an-sub');
+ if (!sub) { return; }
+ if (!li.classList.contains('an-sub-open')) {
+ e.preventDefault();
+ li.classList.add('an-sub-open');
+ }
+ });
+ }
+
+ /* ---------- 首页轮播 ---------- */
+ var root = document.querySelector('.an-banner');
+ var slides = document.querySelectorAll('.an-banner-slide');
+ var dots = document.querySelectorAll('.an-banner-dots button');
+ var prevBtn = document.querySelector('.an-banner-arrow.prev');
+ var nextBtn = document.querySelector('.an-banner-arrow.next');
+ if (!slides.length || !root) {
+ return;
+ }
+ var current = 0;
+ var timer = null;
+ var INTERVAL = 5000;
+
+ function show(index) {
+ slides[current].classList.remove('active');
+ if (dots[current]) {
+ dots[current].classList.remove('active');
+ }
+ current = (index + slides.length) % slides.length;
+ slides[current].classList.add('active');
+ if (dots[current]) {
+ dots[current].classList.add('active');
+ }
+ }
+
+ function start() {
+ stop();
+ if (slides.length > 1) {
+ timer = window.setInterval(function () {
+ show(current + 1);
+ }, INTERVAL);
+ }
+ }
+
+ function stop() {
+ if (timer) {
+ window.clearInterval(timer);
+ timer = null;
+ }
+ }
+
+ dots.forEach(function (dot, index) {
+ dot.addEventListener('click', function () {
+ show(index);
+ start();
+ });
+ });
+ if (prevBtn) {
+ prevBtn.addEventListener('click', function () {
+ show(current - 1);
+ start();
+ });
+ }
+ if (nextBtn) {
+ nextBtn.addEventListener('click', function () {
+ show(current + 1);
+ start();
+ });
+ }
+ root.addEventListener('mouseenter', stop);
+ root.addEventListener('mouseleave', start);
+ root.addEventListener('focusin', stop);
+ root.addEventListener('focusout', start);
+ root.setAttribute('tabindex', '-1');
+ root.addEventListener('keydown', function (e) {
+ if (e.key === 'ArrowLeft') {
+ show(current - 1);
+ start();
+ } else if (e.key === 'ArrowRight') {
+ show(current + 1);
+ start();
+ }
+ });
+
+ /* 触摸滑动切页 */
+ var touchX = null;
+ root.addEventListener('touchstart', function (e) {
+ touchX = e.changedTouches[0].clientX;
+ stop();
+ }, { passive: true });
+ root.addEventListener('touchend', function (e) {
+ if (touchX === null) { return; }
+ var dx = e.changedTouches[0].clientX - touchX;
+ if (Math.abs(dx) > 40) {
+ show(dx < 0 ? current + 1 : current - 1);
+ }
+ touchX = null;
+ start();
+ }, { passive: true });
+
+ start();
+})();
diff --git a/src/main/resources/templates/themes/academic-navy/assets/screenshot.png b/src/main/resources/templates/themes/academic-navy/assets/screenshot.png
new file mode 100644
index 0000000..8f21f46
Binary files /dev/null and b/src/main/resources/templates/themes/academic-navy/assets/screenshot.png differ
diff --git a/src/main/resources/templates/themes/academic-navy/detail.html b/src/main/resources/templates/themes/academic-navy/detail.html
new file mode 100644
index 0000000..de38ed3
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/detail.html
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 文章标题
+
+
+ 作者
+ 来源
+ 浏览量
+
+
+ 正文
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/academic-navy/fragments/footer.html b/src/main/resources/templates/themes/academic-navy/fragments/footer.html
new file mode 100644
index 0000000..867ca6a
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/fragments/footer.html
@@ -0,0 +1,59 @@
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/cherry-bloom/fragments/head.html b/src/main/resources/templates/themes/academic-navy/fragments/head.html
similarity index 74%
rename from src/main/resources/templates/themes/cherry-bloom/fragments/head.html
rename to src/main/resources/templates/themes/academic-navy/fragments/head.html
index 1809482..a01c179 100644
--- a/src/main/resources/templates/themes/cherry-bloom/fragments/head.html
+++ b/src/main/resources/templates/themes/academic-navy/fragments/head.html
@@ -1,6 +1,6 @@
-
+
@@ -8,16 +8,13 @@
-
-
-
diff --git a/src/main/resources/templates/themes/academic-navy/fragments/header.html b/src/main/resources/templates/themes/academic-navy/fragments/header.html
new file mode 100644
index 0000000..f25584e
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/fragments/header.html
@@ -0,0 +1,86 @@
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/academic-navy/fragments/home-blocks.html b/src/main/resources/templates/themes/academic-navy/fragments/home-blocks.html
new file mode 100644
index 0000000..79f1992
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/fragments/home-blocks.html
@@ -0,0 +1,205 @@
+
+
+
+
+
+
+
+
+
+ -
+ 文章标题
+ 置顶
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+ 文章标题
+ 置顶
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ 01
+ 2026-01
+
+ 文章标题
+ 置顶
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+ 媒体来源
+ 文章标题
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
线上展厅
+
+
+
+ Online Exhibition Hall
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/academic-navy/home.html b/src/main/resources/templates/themes/academic-navy/home.html
new file mode 100644
index 0000000..9860bb0
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/home.html
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
头条推荐
+
+
+
+ -
+ 头条标题
+
+ 置顶
+
+
+
+ -
+ 置顶
+ 文章标题
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/academic-navy/list.html b/src/main/resources/templates/themes/academic-navy/list.html
new file mode 100644
index 0000000..71f8a4a
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/list.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
栏目名
+
搜索词
+
+
+
+ -
+
+
+
+
+
+
+
摘要
+
+
+ 置顶
+
+
+
+
+
+
+
+ 置顶
+
+
+
+
+
+
+
未找到相关内容
+
栏目暂无内容
+
换个关键词试试
+
内容发布后将在此展示
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/academic-navy/single.html b/src/main/resources/templates/themes/academic-navy/single.html
new file mode 100644
index 0000000..64c413f
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/single.html
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 栏目名
+
+ 单页内容
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/academic-navy/theme.json b/src/main/resources/templates/themes/academic-navy/theme.json
new file mode 100644
index 0000000..2e47990
--- /dev/null
+++ b/src/main/resources/templates/themes/academic-navy/theme.json
@@ -0,0 +1,23 @@
+{
+ "specVersion": 1,
+ "name": "academic-navy",
+ "title": "学府藏蓝(academic-navy)",
+ "version": "1.0.0",
+ "author": "yunhai",
+ "description": "学府藏蓝·高校官网门户:藏蓝顶栏+白底主导航+金线标题+日期方块列表+双栏要闻(左图右列)+深色三段页脚。基座 scholar-blue,配色与首页区块形态按综合类高校官网重做。",
+ "screenshot": "assets/screenshot.png",
+ "bannerSize": "1920x560",
+ "params": [
+ { "key": "primary", "cssVar": "--an-primary", "label": "主色", "type": "color", "default": "#0b4a8f" },
+ { "key": "primaryDark", "cssVar": "--an-primary-dark", "label": "主色加深", "type": "color", "default": "#063161" },
+ { "key": "primaryLight", "cssVar": "--an-primary-light","label": "主色提亮", "type": "color", "default": "#1a6cb5" },
+ { "key": "accent", "cssVar": "--an-accent", "label": "点缀金", "type": "color", "default": "#b8934a" },
+ { "key": "navBg", "cssVar": "--an-nav-bg", "label": "导航条底色", "type": "color", "default": "#ffffff" },
+ { "key": "footerBg", "cssVar": "--an-footer-bg", "label": "页脚底色", "type": "color", "default": "#0a2b4d" },
+ { "key": "text", "cssVar": "--an-text", "label": "正文文字色", "type": "color", "default": "#2b3644" },
+ { "key": "textLight", "cssVar": "--an-text-light", "label": "次要文字色", "type": "color", "default": "#6b7889" },
+ { "key": "bg", "cssVar": "--an-bg", "label": "页面底色", "type": "color", "default": "#f1f4f9" },
+ { "key": "cardBg", "cssVar": "--an-card-bg", "label": "卡片底色", "type": "color", "default": "#ffffff" },
+ { "key": "border", "cssVar": "--an-border", "label": "边框色", "type": "color", "default": "#dbe3ee" }
+ ]
+}
diff --git a/src/main/resources/templates/themes/campus-azure/README.md b/src/main/resources/templates/themes/campus-azure/README.md
new file mode 100644
index 0000000..e36338f
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/README.md
@@ -0,0 +1,33 @@
+# campus-azure(青蓝校园)
+
+高校官网风皮肤包:以 `scholar-blue` 为基座派生,配色与首页区块形态按师范/农林类院校官网(信阳师范学院、
+信阳农林学院一类)重做。配了 `home_layout` 的站点,首页正文区块由本主题 `fragments/home-blocks.html` 渲染,
+不落 `themes/common` 通用骨架(否则换肤只剩页头页脚)。
+
+## 风格定位
+
+- 主色青蓝 `#0d6a9e` + 加深 `#084c73` + 点缀青绿 `#2b9c8f`(列表圆点、标题线脚、速递标签走青绿)。
+- 圆角放宽到 6/12px、页面底 `#eef3f6`,比 academic-navy 更松更「校园」;区块头统一走居中双线 + 右置「更多」。
+- 全部 11 个颜色参数可在站点 theme_params 微调(`primary/primaryDark/primaryLight/accent/navBg/footerBg/text/textLight/bg/cardBg/border`)。
+
+## 首页区块形态(布局模式与回落模式同构)
+
+| homeStyle | 呈现 | 类名 |
+| -- | -- | -- |
+| `news_grid` | 图文要闻:全宽封面头条(底部渐变遮罩标题 + 元信息)+ 双列圆点密行;区块背景可取站点 `news_bg_image` | `cz-hero*` / `cz-block-list--two` |
+| `compact` | 圆点密行:青绿圆点 + 标题 + 右对齐完整日期 | `cz-item-bullet` / `cz-item-date` |
+| `media_focus` | 媒体聚焦:胶囊来源徽标 + 双列密行 | `cz-src` |
+| `image_wall` | 三列大格图墙:圆角卡 + 底部遮罩标题 | `cz-wall` |
+| (空/未知) | 整宽区块卡:左 2 份图文头条 + 右 3 份圆点行 | `cz-block--flow` / `cz-split` |
+| `ticker` | 青蓝要闻速递横条,标签为青绿胶囊(单行不换行、超长省略,中文不塌列) | `cz-ticker*` |
+| `gallery` | 线上展厅:居中双语文区头 + 四列图墙 | `cz-gallery` |
+| `links` | 友情链接分组(胶囊标签行) | `cz-links` |
+
+## 契约要点
+
+- 结构类前缀 `cz-`,CSS 变量前缀 `--cz-`;`:root` 把 `--cz-*` 别名到皮肤契约变量(`--primary`/`--text`/`--card-bg`/`--border`…),
+ 使 `themes/common` 兜底骨架也能跟随本皮肤着色。
+- 空态文案「栏目暂无内容」只在 `block.items` 为空时出现;守卫必须写在 `th:block` 外层——
+ `th:replace`(优先级 100)先于 `th:if`(300)求值,写在同一标签上等于没写。
+- 回归防线:`AcademicSkinContractTest`(自带区块 fragment + 中文不塌列 + 契约变量别名 + 主色必须学术蓝)、
+ `PortalHomeLayoutIT#campusAzure_fallbackAndAssets`(回落分支 + 资产通道)、`ThemeContractIT`(7 条路由)。
diff --git a/src/main/resources/templates/themes/campus-azure/assets/css/main.css b/src/main/resources/templates/themes/campus-azure/assets/css/main.css
new file mode 100644
index 0000000..5bea869
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/assets/css/main.css
@@ -0,0 +1,1535 @@
+/* =====================================================================
+ campus-azure · 青蓝校园(基座 scholar-blue,参考语言:师范/农林类高校官网门户)
+ 设计语言:青蓝顶栏/品牌行 + 白底主导航(吸顶反蓝) + 青绿描边双线标题
+ + 布局模式全宽封面头条 + 圆点密行 + 胶囊速递标签 + 深色圆环页脚
+ 色彩令牌全部走 CSS 变量,theme.json color 参数经 :root 覆盖真实生效。
+ ===================================================================== */
+
+/* ---------------------------------------------------------------------
+ 1. 设计令牌(与 theme.json params 一一对应,禁止出现未消费的声明)
+ --------------------------------------------------------------------- */
+:root {
+ --cz-primary: #0d6a9e; /* 主色:青蓝,顶栏/品牌行/标题/强调 */
+ --cz-primary-dark: #084c73; /* 主色加深:hover/渐变端/页脚深端 */
+ --cz-primary-light: #1d87bd; /* 主色提亮:亮线条/hover 链接/角标 */
+ --cz-accent: #2b9c8f; /* 点缀青绿:标题下划细线/日期方块描边(农林院校常见) */
+ --cz-nav-bg: #ffffff; /* 主导航条底色(白条学院风) */
+ --cz-footer-bg: #0b3348; /* 页脚主底 */
+ --cz-text: #303c46; /* 正文 */
+ --cz-text-light: #6e7d88; /* 次要文字 */
+ --cz-bg: #eef3f6; /* 页面底色 */
+ --cz-card-bg: #ffffff; /* 卡片底 */
+ --cz-border: #d9e5ec; /* 边框/分隔线 */
+
+ --cz-ink-on-dark: #ffffff; /* 深底主文字 */
+ --cz-ink-on-dark-soft: rgba(255,255,255,.75); /* 深底次要文字 */
+ --cz-ink-on-dark-faint: rgba(255,255,255,.47);
+ --cz-panel: rgba(13,106,158,.95); /* 下拉面板(主色半透明) */
+ --cz-shadow-sm: 0 1px 4px rgba(8,76,115,.08);
+ --cz-shadow-md: 0 6px 18px rgba(8,76,115,.12);
+ --cz-shadow-lg: 0 14px 34px rgba(8,76,115,.18);
+ --cz-radius: 6px;
+ --cz-radius-lg: 12px;
+ --cz-speed: .28s;
+ --cz-font: "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Helvetica Neue", Arial, sans-serif;
+
+ /* 皮肤契约别名:站点配了 home_layout 时首页走 common/fragments/home-blocks 骨架,
+ 该骨架只认契约变量(--primary/--text/…)。不别名过去,换肤就只换了页头页脚、正文区块仍是骨架内置色。 */
+ --primary: var(--cz-primary);
+ --primary-dark: var(--cz-primary-dark);
+ --primary-light: var(--cz-primary-light);
+ --text: var(--cz-text);
+ --text-light: var(--cz-text-light);
+ --bg: var(--cz-bg);
+ --card-bg: var(--cz-card-bg);
+ --border: var(--cz-border);
+ --radius: var(--cz-radius-lg);
+}
+
+/* ---------------------------------------------------------------------
+ 2. Reset 与基础
+ --------------------------------------------------------------------- */
+* { margin: 0; padding: 0; box-sizing: border-box; }
+
+html { -webkit-text-size-adjust: 100%; }
+
+body {
+ font-family: var(--cz-font);
+ font-size: 14px;
+ line-height: 1.7;
+ color: var(--cz-text);
+ background: var(--cz-bg);
+ word-break: break-word;
+}
+
+ul, ol { list-style: none; }
+
+a { color: var(--cz-primary); text-decoration: none; transition: color var(--cz-speed) ease; }
+a:hover { color: var(--cz-primary-light); }
+
+img { max-width: 100%; display: block; border: 0; }
+
+button { font-family: inherit; cursor: pointer; }
+
+input, button, select, textarea { font-size: inherit; color: inherit; }
+
+::selection { background: var(--cz-primary); color: #fff; }
+
+/* 跳转链接:仅键盘聚焦时可见 */
+.skip-link {
+ position: absolute; left: -999px; top: 0; z-index: 300;
+ background: var(--cz-primary-dark); color: #fff;
+ padding: 8px 18px; border-radius: 0 0 var(--cz-radius) 0;
+}
+.skip-link:focus { left: 0; color: #fff; }
+
+/* 通用容器 */
+.cz-container {
+ width: 1200px; max-width: calc(100% - 40px);
+ margin: 0 auto;
+}
+
+/* 屏幕阅读器专用 */
+.cz-visually-hidden {
+ position: absolute; width: 1px; height: 1px;
+ margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
+}
+
+/* 置顶徽章 */
+.cz-top-badge {
+ display: inline-block; flex: none;
+ padding: 0 7px; line-height: 18px;
+ font-size: 12px; color: #fff;
+ background: var(--cz-primary-light);
+ border-radius: 2px;
+ letter-spacing: 1px;
+}
+
+/* 空状态 */
+.cz-empty {
+ padding: 56px 20px;
+ text-align: center;
+ color: var(--cz-text-light);
+}
+.cz-empty p:first-child { font-size: 16px; margin-bottom: 8px; }
+.cz-empty-hint { font-size: 13px; color: var(--cz-text-light); opacity: .75; }
+
+/* ---------------------------------------------------------------------
+ 3. 顶栏(深蓝细条:日期 + 院系切换)
+ --------------------------------------------------------------------- */
+.cz-topbar {
+ background: linear-gradient(90deg, var(--cz-primary-dark), var(--cz-primary));
+ color: var(--cz-ink-on-dark-soft);
+ font-size: 13px;
+}
+
+.cz-topbar-inner {
+ width: 1200px; max-width: calc(100% - 40px);
+ margin: 0 auto;
+ display: flex; align-items: center; justify-content: space-between;
+ min-height: 36px;
+}
+
+.cz-topbar-date { letter-spacing: .5px; }
+
+.cz-topbar-side { position: relative; }
+
+/* 院系切换:细字 + 箭头,展开为深蓝面板 */
+.cz-colleges { position: relative; }
+
+.cz-colleges-toggle {
+ display: inline-flex; align-items: center; gap: 6px;
+ padding: 4px 2px;
+ cursor: pointer;
+}
+.cz-colleges-toggle a { color: var(--cz-ink-on-dark-soft); }
+.cz-colleges-toggle a:hover { color: #fff; }
+
+.cz-colleges-arrow {
+ font-style: normal; font-size: 10px;
+ transition: transform var(--cz-speed) ease;
+}
+.cz-colleges:hover .cz-colleges-arrow { transform: rotate(180deg); }
+
+.cz-colleges-menu {
+ position: absolute; right: 0; top: calc(100% + 6px);
+ min-width: 180px; max-height: 280px; overflow: auto;
+ background: var(--cz-panel);
+ backdrop-filter: blur(4px);
+ border-top: 2px solid var(--cz-primary-light);
+ border-radius: 0 0 var(--cz-radius) var(--cz-radius);
+ box-shadow: var(--cz-shadow-lg);
+ padding: 6px 0;
+ opacity: 0; visibility: hidden; transform: translateY(-6px);
+ transition: opacity var(--cz-speed) ease, transform var(--cz-speed) ease, visibility var(--cz-speed);
+ z-index: 120;
+}
+.cz-colleges:hover .cz-colleges-menu,
+.cz-colleges:focus-within .cz-colleges-menu {
+ opacity: 1; visibility: visible; transform: translateY(0);
+}
+
+.cz-colleges-menu li a {
+ display: block;
+ padding: 7px 16px;
+ color: var(--cz-ink-on-dark);
+ font-size: 13px;
+ border-left: 2px solid transparent;
+ transition: background var(--cz-speed) ease, border-color var(--cz-speed) ease, padding-left var(--cz-speed) ease;
+}
+.cz-colleges-menu li a:hover {
+ background: var(--cz-primary-dark);
+ border-left-color: var(--cz-primary-light);
+ padding-left: 20px;
+ color: #fff;
+}
+.cz-colleges-menu li.active a {
+ background: rgba(255,255,255,.08);
+ border-left-color: var(--cz-primary-light);
+ color: #fff;
+}
+
+/* ---------------------------------------------------------------------
+ 4. 品牌行(深蓝主区:徽标 + 站名 + 圆角搜索)
+ --------------------------------------------------------------------- */
+.cz-brandbar {
+ background: linear-gradient(100deg, var(--cz-primary-dark) 0%, var(--cz-primary) 62%, var(--cz-primary-light) 130%);
+ color: var(--cz-ink-on-dark);
+ position: relative;
+ overflow: hidden;
+}
+/* 品牌行右侧淡圆环装饰(CSS 绘制,无图片依赖) */
+.cz-brandbar::before,
+.cz-brandbar::after {
+ content: "";
+ position: absolute;
+ border-radius: 50%;
+ border: 26px solid rgba(255,255,255,.05);
+ pointer-events: none;
+}
+.cz-brandbar::before { width: 320px; height: 320px; right: -80px; top: -170px; }
+.cz-brandbar::after { width: 200px; height: 200px; right: 180px; bottom: -140px; border-width: 16px; }
+
+.cz-brandbar-inner {
+ width: 1200px; max-width: calc(100% - 40px);
+ margin: 0 auto;
+ display: flex; align-items: center; justify-content: space-between;
+ gap: 24px;
+ padding: 22px 0;
+ position: relative; z-index: 1;
+}
+
+.cz-brand {
+ display: flex; align-items: center; gap: 14px;
+ min-width: 0;
+}
+
+/* 徽标容器:白衬圆角方块,校徽任何底色都干净 */
+.cz-brand-badge {
+ flex: none;
+ width: 58px; height: 58px;
+ display: inline-flex; align-items: center; justify-content: center;
+ background: rgba(255,255,255,.94);
+ border-radius: var(--cz-radius);
+ box-shadow: 0 2px 8px rgba(8,76,115,.35);
+ overflow: hidden;
+}
+.cz-brand-badge--plain { color: var(--cz-primary); }
+.cz-logo { width: 100%; height: 100%; object-fit: contain; }
+
+.cz-site-name {
+ color: var(--cz-ink-on-dark);
+ font-size: 27px;
+ font-weight: 700;
+ letter-spacing: 2px;
+ line-height: 1.3;
+ text-shadow: 0 2px 6px rgba(8,76,115,.4);
+ white-space: nowrap;
+ overflow: hidden; text-overflow: ellipsis;
+ max-width: 560px;
+}
+.cz-site-name:hover { color: #fff; }
+
+/* 搜索:白色胶囊(学院风记忆点) */
+.cz-search {
+ flex: none;
+ display: flex; align-items: center;
+ width: 300px; max-width: 36%;
+ background: #fff;
+ border-radius: 999px;
+ padding: 3px 4px 3px 18px;
+ box-shadow: 0 3px 10px rgba(8,76,115,.28);
+}
+.cz-search input {
+ flex: 1; min-width: 0;
+ border: 0; outline: none;
+ background: transparent;
+ font-size: 13px; color: var(--cz-text);
+ line-height: 30px;
+}
+.cz-search input::placeholder { color: #a9b3c0; }
+.cz-search button {
+ flex: none;
+ width: 32px; height: 32px;
+ border: 0; border-radius: 50%;
+ background: var(--cz-primary);
+ color: #fff;
+ display: inline-flex; align-items: center; justify-content: center;
+ transition: background var(--cz-speed) ease, transform var(--cz-speed) ease;
+}
+.cz-search button:hover { background: var(--cz-primary-light); transform: scale(1.06); }
+
+/* ---------------------------------------------------------------------
+ 5. 主导航(白底条 + 主蓝半透明下拉面板 + 吸顶反蓝)
+ --------------------------------------------------------------------- */
+.cz-nav {
+ background: var(--cz-nav-bg);
+ box-shadow: var(--cz-shadow-sm);
+ position: relative;
+ z-index: 100;
+}
+/* 顶部主蓝细线:把导航条与品牌行缝在一起 */
+.cz-nav::before {
+ content: "";
+ display: block; height: 3px;
+ background: linear-gradient(90deg, var(--cz-primary), var(--cz-primary-light));
+}
+
+.cz-nav-inner {
+ width: 1200px; max-width: calc(100% - 40px);
+ margin: 0 auto;
+ position: relative;
+}
+
+.cz-nav-toggle { display: none; }
+
+.cz-nav-list {
+ display: flex;
+ justify-content: space-between;
+}
+
+.cz-nav-list > li { position: relative; flex: 1 1 auto; text-align: center; }
+
+.cz-nav-list > li > a {
+ display: flex; align-items: center; justify-content: center; gap: 5px;
+ position: relative;
+ padding: 0 10px;
+ height: 52px;
+ font-size: 16px;
+ font-weight: 600;
+ letter-spacing: 1px;
+ color: var(--cz-primary-dark);
+ white-space: nowrap;
+ transition: color var(--cz-speed) ease, background var(--cz-speed) ease;
+}
+/* 底部指示条:hover/当前项 */
+.cz-nav-list > li > a::after {
+ content: "";
+ position: absolute; left: 50%; bottom: 0;
+ width: 0; height: 3px;
+ background: var(--cz-primary);
+ transform: translateX(-50%);
+ transition: width var(--cz-speed) ease;
+}
+.cz-nav-list > li:hover > a,
+.cz-nav-list > li.active > a {
+ color: var(--cz-primary);
+ background: rgba(13,106,158,.06);
+}
+.cz-nav-list > li:hover > a::after,
+.cz-nav-list > li.active > a::after { width: 56%; }
+
+.cz-caret {
+ font-style: normal; font-size: 11px;
+ opacity: .65;
+ transition: transform var(--cz-speed) ease;
+}
+.cz-nav-list > li:hover .cz-caret { transform: rotate(180deg); }
+
+/* —— 下拉面板:主蓝半透明、顶部亮线、项 hover 加深 + 左亮条(红线第一优先级) —— */
+.cz-sub {
+ position: absolute; left: 50%; top: 100%;
+ transform: translate(-50%, 10px);
+ min-width: 176px;
+ background: var(--cz-panel);
+ backdrop-filter: blur(6px);
+ border-top: 3px solid var(--cz-primary-light);
+ border-radius: 0 0 var(--cz-radius) var(--cz-radius);
+ box-shadow: var(--cz-shadow-lg);
+ padding: 6px 0;
+ text-align: left;
+ opacity: 0; visibility: hidden;
+ transition: opacity var(--cz-speed) ease, transform var(--cz-speed) ease, visibility var(--cz-speed);
+ z-index: 110;
+}
+.cz-nav-list > li:hover .cz-sub,
+.cz-nav-list > li:focus-within .cz-sub {
+ opacity: 1; visibility: visible;
+ transform: translate(-50%, 0);
+}
+
+/* 面板小尖角 */
+.cz-sub::before {
+ content: "";
+ position: absolute; left: 50%; top: -8px;
+ width: 12px; height: 12px;
+ background: var(--cz-primary);
+ transform: translateX(-50%) rotate(45deg);
+ border-radius: 2px 0 0 0;
+}
+
+.cz-sub li a {
+ display: block;
+ position: relative;
+ margin: 2px 8px;
+ padding: 9px 14px 9px 22px;
+ font-size: 14px;
+ color: var(--cz-ink-on-dark);
+ border-radius: 4px;
+ white-space: nowrap;
+ transition: background var(--cz-speed) ease, padding-left var(--cz-speed) ease, color var(--cz-speed) ease;
+}
+/* 项前细刻度线 */
+.cz-sub li a::before {
+ content: "";
+ position: absolute; left: 10px; top: 50%;
+ width: 4px; height: 4px;
+ margin-top: -2px;
+ background: rgba(255,255,255,.5);
+ border-radius: 50%;
+ transition: background var(--cz-speed) ease, box-shadow var(--cz-speed) ease;
+}
+.cz-sub li a:hover {
+ background: var(--cz-primary-dark);
+ padding-left: 26px;
+ color: #fff;
+}
+.cz-sub li a:hover::before {
+ background: var(--cz-primary-light);
+ box-shadow: 0 0 6px var(--cz-primary-light);
+}
+
+/* —— 吸顶反蓝(.cz-nav--fixed 由 main.js 滚动加挂) —— */
+.cz-nav--fixed {
+ position: fixed; left: 0; right: 0; top: 0;
+ background: linear-gradient(90deg, var(--cz-primary-dark), var(--cz-primary));
+ box-shadow: var(--cz-shadow-md);
+ animation: cz-nav-drop var(--cz-speed) ease;
+}
+@keyframes cz-nav-drop {
+ from { transform: translateY(-100%); }
+ to { transform: translateY(0); }
+}
+.cz-nav--fixed::before { height: 0; }
+.cz-nav--fixed .cz-nav-list > li > a { color: var(--cz-ink-on-dark); }
+.cz-nav--fixed .cz-nav-list > li:hover > a,
+.cz-nav--fixed .cz-nav-list > li.active > a {
+ color: #fff;
+ background: rgba(255,255,255,.1);
+}
+.cz-nav--fixed .cz-nav-list > li > a::after { background: var(--cz-primary-light); }
+/* 吸顶态下拉:底色更沉,与蓝条衔接 */
+.cz-nav--fixed .cz-sub { background: rgba(8,76,115,.96); }
+.cz-nav--fixed .cz-sub::before { background: var(--cz-primary-dark); }
+
+/* 吸顶占位,防跳变(main.js 加挂时同步高度,解锁即移除) */
+.cz-nav-holder { display: block; }
+
+/* ---------------------------------------------------------------------
+ 6. 首页 banner(通栏轮播 + 圆形箭头 + 底部圆点)
+ --------------------------------------------------------------------- */
+.cz-banner {
+ position: relative;
+ overflow: hidden;
+ background: var(--cz-primary-dark);
+}
+.cz-banner-slides { position: relative; height: 520px; }
+
+.cz-banner-slide {
+ position: absolute; inset: 0;
+ opacity: 0; visibility: hidden;
+ transition: opacity .8s ease, visibility .8s ease;
+}
+.cz-banner-slide.active { opacity: 1; visibility: visible; z-index: 1; }
+
+.cz-banner-slide img {
+ width: 100%; height: 100%;
+ object-fit: cover;
+}
+/* 底部渐隐遮罩上承标题 */
+.cz-banner-slide::after {
+ content: "";
+ position: absolute; left: 0; right: 0; bottom: 0;
+ height: 120px;
+ background: linear-gradient(180deg, transparent, rgba(8,76,115,.66));
+ pointer-events: none;
+}
+.cz-banner-slide.active img { animation: cz-banner-zoom 6.5s ease forwards; }
+@keyframes cz-banner-zoom {
+ from { transform: scale(1); }
+ to { transform: scale(1.045); }
+}
+
+.cz-banner-title {
+ position: absolute; left: 6%; bottom: 34px;
+ z-index: 2;
+ max-width: 70%;
+ color: #fff;
+ font-size: 24px;
+ font-weight: 600;
+ letter-spacing: 1px;
+ text-shadow: 0 2px 8px rgba(8,76,115,.6);
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+}
+
+/* 圆形半透明箭头(建平语言) */
+.cz-banner-arrow {
+ position: absolute; top: 50%; z-index: 3;
+ width: 52px; height: 52px; margin-top: -26px;
+ border: 2px solid rgba(255,255,255,.75);
+ border-radius: 50%;
+ background: rgba(8,76,115,.25);
+ color: #fff;
+ font-size: 26px; line-height: 1;
+ display: inline-flex; align-items: center; justify-content: center;
+ padding-bottom: 4px;
+ opacity: 0;
+ transition: opacity var(--cz-speed) ease, background var(--cz-speed) ease, border-color var(--cz-speed) ease;
+}
+.cz-banner:hover .cz-banner-arrow { opacity: 1; }
+.cz-banner-arrow:hover { background: var(--cz-primary); border-color: #fff; }
+.cz-banner-arrow.prev { left: 26px; }
+.cz-banner-arrow.next { right: 26px; }
+
+/* 圆点指示器 */
+.cz-banner-dots {
+ position: absolute; left: 0; right: 0; bottom: 18px;
+ z-index: 3;
+ display: flex; justify-content: center; gap: 10px;
+}
+.cz-banner-dots button {
+ width: 10px; height: 10px;
+ border: 0; border-radius: 50%;
+ background: rgba(255,255,255,.55);
+ transition: background var(--cz-speed) ease, transform var(--cz-speed) ease;
+}
+.cz-banner-dots button:hover { background: #fff; }
+.cz-banner-dots button.active {
+ background: #fff;
+ transform: scale(1.25);
+ box-shadow: 0 0 0 3px rgba(255,255,255,.25);
+}
+
+/* ---------------------------------------------------------------------
+ 7. 区块标题(居中双线 + 下短横)与区块通用
+ --------------------------------------------------------------------- */
+.cz-section { margin-top: 40px; }
+
+.cz-block-head {
+ position: relative;
+ text-align: center;
+ padding: 14px 0 12px;
+ border-top: 1px solid var(--cz-border);
+ border-bottom: 1px solid var(--cz-border);
+}
+.cz-block-head h2 {
+ display: inline-block;
+ position: relative;
+ font-size: 22px;
+ font-weight: 700;
+ letter-spacing: 3px;
+ color: var(--cz-primary-dark);
+}
+/* 标题下短横:主蓝 3px */
+.cz-block-tick {
+ position: absolute; left: 50%; bottom: -2px;
+ width: 42px; height: 3px;
+ transform: translateX(-50%);
+ background: var(--cz-primary);
+ border-radius: 2px;
+}
+
+/* 栏目卡头变体:左右布局(标题居左 + 更多居右) */
+.cz-block-head--bar {
+ text-align: left;
+ padding: 0 0 10px;
+ border-top: 0;
+ border-bottom: 2px solid var(--cz-primary);
+ display: flex; align-items: baseline; justify-content: space-between;
+}
+.cz-block-head--bar h2 {
+ font-size: 19px;
+ letter-spacing: 1px;
+ padding-left: 12px;
+ position: relative;
+}
+/* 标题左侧竖条 */
+.cz-block-head--bar h2::before {
+ content: "";
+ position: absolute; left: 0; top: 6px; bottom: 6px;
+ width: 4px;
+ background: var(--cz-primary);
+ border-radius: 2px;
+}
+.cz-block-head--bar .cz-block-tick { display: none; }
+
+.cz-more {
+ font-size: 13px;
+ font-weight: 400;
+ color: var(--cz-text-light);
+ letter-spacing: 0;
+ transition: color var(--cz-speed) ease, transform var(--cz-speed) ease;
+}
+.cz-more:hover { color: var(--cz-primary); transform: translateX(3px); }
+
+/* ---------------------------------------------------------------------
+ 8. 头条区(左:头条推荐列表 / 右:图片新闻)
+ --------------------------------------------------------------------- */
+.cz-headline {
+ display: grid;
+ grid-template-columns: 7fr 5fr;
+ gap: 28px;
+}
+/* grid 项允许收缩到轨道内:否则 nowrap 省略文本会把 auto 最小宽撑破容器(移动端横向溢出) */
+.cz-headline > * { min-width: 0; }
+
+.cz-headline-card,
+.cz-focus-card {
+ background: var(--cz-card-bg);
+ border-radius: var(--cz-radius-lg);
+ box-shadow: var(--cz-shadow-sm);
+ padding: 6px 22px 18px;
+}
+
+/* 头条推荐 */
+.cz-headline-list li {
+ display: flex; align-items: center; gap: 10px;
+ padding: 10px 2px;
+ border-bottom: 1px dashed var(--cz-border);
+}
+.cz-headline-list li:last-child { border-bottom: 0; }
+.cz-headline-list li a {
+ flex: 1; min-width: 0;
+ color: var(--cz-text);
+ font-size: 15px;
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+ transition: color var(--cz-speed) ease, padding-left var(--cz-speed) ease;
+}
+.cz-headline-list li a:hover { color: var(--cz-primary); padding-left: 4px; }
+.cz-headline-list time { flex: none; color: var(--cz-text-light); font-size: 13px; }
+
+/* 头条头条:大标题 + 元信息 */
+.cz-headline-lead {
+ display: block !important;
+ padding: 14px 2px 16px !important;
+}
+.cz-lead-title {
+ display: block;
+ font-size: 19px !important;
+ font-weight: 700;
+ color: var(--cz-primary-dark) !important;
+ line-height: 1.5;
+ white-space: normal !important;
+ overflow: hidden;
+ max-height: 3em;
+}
+.cz-lead-title:hover { color: var(--cz-primary) !important; padding-left: 0 !important; }
+.cz-lead-meta {
+ display: flex; align-items: center; gap: 10px;
+ margin-top: 8px;
+ font-size: 13px; color: var(--cz-text-light);
+}
+
+/* 图片新闻 */
+.cz-focus-lead {
+ display: block;
+ margin-top: 14px;
+ border-radius: var(--cz-radius);
+ overflow: hidden;
+ position: relative;
+}
+.cz-focus-cover { display: block; aspect-ratio: 16/9; overflow: hidden; background: var(--cz-bg); }
+.cz-focus-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
+.cz-focus-lead:hover .cz-focus-cover img { transform: scale(1.05); }
+.cz-focus-title {
+ position: absolute; left: 0; right: 0; bottom: 0;
+ padding: 26px 14px 10px;
+ color: #fff; font-size: 15px; font-weight: 600;
+ background: linear-gradient(180deg, transparent, rgba(8,76,115,.82));
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+}
+
+.cz-focus-rows { margin-top: 10px; }
+.cz-focus-rows li a {
+ display: flex; align-items: center; gap: 12px;
+ padding: 8px 0;
+}
+.cz-row-cover {
+ flex: none;
+ width: 104px; height: 66px;
+ border-radius: 4px;
+ overflow: hidden;
+ background: var(--cz-bg);
+}
+.cz-row-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
+.cz-focus-rows li a:hover .cz-row-cover img { transform: scale(1.06); }
+.cz-row-title {
+ flex: 1; min-width: 0;
+ color: var(--cz-text);
+ font-size: 14px;
+ line-height: 1.55;
+ max-height: 3.1em;
+ overflow: hidden;
+ transition: color var(--cz-speed) ease;
+}
+.cz-focus-rows li a:hover .cz-row-title { color: var(--cz-primary); }
+
+/* ---------------------------------------------------------------------
+ 9. 栏目区块(白卡三列 + 日期方块行)
+ --------------------------------------------------------------------- */
+.cz-blocks {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 24px;
+ margin-top: 14px;
+}
+
+.cz-block {
+ background: var(--cz-card-bg);
+ border-radius: var(--cz-radius-lg);
+ box-shadow: var(--cz-shadow-sm);
+ padding: 18px 20px 14px;
+ display: flex; flex-direction: column;
+ min-width: 0;
+ transition: box-shadow var(--cz-speed) ease, transform var(--cz-speed) ease;
+}
+.cz-block:hover { box-shadow: var(--cz-shadow-md); transform: translateY(-2px); }
+
+.cz-block-list { flex: 1; }
+
+/* 区块头条(有封面图文 / 无封面纯文) */
+.cz-block-featured { border-bottom: 1px solid var(--cz-border); }
+.cz-block-featured > a {
+ display: block;
+ padding: 12px 0 14px;
+}
+.cz-feat-cover {
+ display: block;
+ aspect-ratio: 16/9;
+ border-radius: var(--cz-radius);
+ overflow: hidden;
+ background: var(--cz-bg);
+ margin-bottom: 10px;
+}
+.cz-feat-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
+.cz-block-featured > a:hover .cz-feat-cover img { transform: scale(1.04); }
+
+.cz-feat-title {
+ display: block;
+ font-size: 16px; font-weight: 700;
+ color: var(--cz-primary-dark);
+ line-height: 1.5;
+ max-height: 3em;
+ overflow: hidden;
+ transition: color var(--cz-speed) ease;
+}
+.cz-block-featured > a:hover .cz-feat-title { color: var(--cz-primary); }
+.cz-feat-summary {
+ display: block;
+ margin-top: 6px;
+ font-size: 13px; color: var(--cz-text-light);
+ line-height: 1.65;
+ max-height: 3.3em;
+ overflow: hidden;
+}
+.cz-feat-meta {
+ display: flex; align-items: center; gap: 10px;
+ margin-top: 8px;
+ font-size: 12px; color: var(--cz-text-light);
+}
+
+/* 列表行:日期方块 + 标题(建平通知公告语言) */
+.cz-block-item {
+ display: flex; align-items: center; gap: 12px;
+ padding: 8px 0;
+ border-bottom: 1px dashed var(--cz-border);
+}
+.cz-block-item:last-child { border-bottom: 0; }
+
+.cz-date-chip {
+ flex: none;
+ width: 46px;
+ text-align: center;
+ border-radius: 4px;
+ overflow: hidden;
+ background: var(--cz-bg);
+ border: 1px solid var(--cz-border);
+ transition: background var(--cz-speed) ease, border-color var(--cz-speed) ease;
+}
+.cz-date-chip b {
+ display: block;
+ font-size: 17px; line-height: 24px;
+ font-weight: 700;
+ color: var(--cz-primary);
+ background: rgba(13,106,158,.08);
+ transition: color var(--cz-speed) ease;
+}
+.cz-date-chip i {
+ display: block;
+ font-style: normal;
+ font-size: 10px; line-height: 16px;
+ color: var(--cz-text-light);
+ transform: scale(.92);
+}
+.cz-block-item:hover .cz-date-chip {
+ background: var(--cz-primary);
+ border-color: var(--cz-primary);
+}
+.cz-block-item:hover .cz-date-chip b { color: #fff; background: transparent; }
+.cz-block-item:hover .cz-date-chip i { color: rgba(255,255,255,.8); }
+
+.cz-block-item-title {
+ flex: 1; min-width: 0;
+ font-size: 14px;
+ color: var(--cz-text);
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+ transition: color var(--cz-speed) ease;
+}
+.cz-block-item:hover .cz-block-item-title { color: var(--cz-primary); }
+
+/* ---------------------------------------------------------------------
+ 10. 列表/详情/单页公共:页面卡 + 面包屑 + 页题
+ --------------------------------------------------------------------- */
+.cz-page { padding: 28px 0 48px; }
+
+.cz-page-card {
+ background: var(--cz-card-bg);
+ border-radius: var(--cz-radius-lg);
+ box-shadow: var(--cz-shadow-sm);
+ padding: 26px 32px 34px;
+ min-height: 420px;
+}
+
+.cz-crumb {
+ display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
+ font-size: 13px;
+ color: var(--cz-text-light);
+ padding-bottom: 14px;
+ border-bottom: 1px solid var(--cz-border);
+ margin-bottom: 20px;
+}
+.cz-crumb a { color: var(--cz-text-light); }
+.cz-crumb a:hover { color: var(--cz-primary); }
+.cz-crumb-sep { color: #c3cad4; }
+.cz-crumb-current { color: var(--cz-primary); }
+
+.cz-page-title {
+ position: relative;
+ font-size: 23px;
+ font-weight: 700;
+ letter-spacing: 1px;
+ color: var(--cz-primary-dark);
+ padding-left: 16px;
+ margin-bottom: 22px;
+}
+.cz-page-title::before {
+ content: "";
+ position: absolute; left: 0; top: 5px; bottom: 5px;
+ width: 5px;
+ border-radius: 3px;
+ background: linear-gradient(180deg, var(--cz-primary), var(--cz-primary-light));
+}
+
+/* ---------------------------------------------------------------------
+ 11. 列表页:图文行 + 行式列表 + 分页
+ --------------------------------------------------------------------- */
+.cz-article-list > li { border-bottom: 1px solid var(--cz-border); }
+.cz-article-list > li:last-child { border-bottom: 0; }
+
+/* 图文行 */
+.cz-article-row {
+ display: flex; gap: 20px;
+ padding: 18px 2px;
+}
+.cz-item-cover {
+ flex: none;
+ width: 216px; aspect-ratio: 3/2;
+ border-radius: var(--cz-radius);
+ overflow: hidden;
+ background: var(--cz-bg);
+}
+.cz-item-cover img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s ease; }
+.cz-article-row:hover .cz-item-cover img { transform: scale(1.05); }
+
+.cz-item-body { flex: 1; min-width: 0; padding-top: 4px; }
+.cz-item-title a {
+ font-size: 17px; font-weight: 600;
+ color: var(--cz-text);
+ line-height: 1.5;
+ transition: color var(--cz-speed) ease;
+}
+.cz-item-title a:hover { color: var(--cz-primary); }
+.cz-item-summary {
+ margin-top: 8px;
+ font-size: 13px; color: var(--cz-text-light);
+ line-height: 1.7;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+.cz-item-meta {
+ display: flex; align-items: center; gap: 12px;
+ margin-top: 10px;
+ font-size: 12px; color: var(--cz-text-light);
+}
+
+/* 行式(无封面):刻度符号 + 标题 + 右侧日期 */
+.cz-article-line {
+ display: flex; align-items: center; gap: 12px;
+ padding: 13px 2px;
+}
+.cz-line-tick {
+ flex: none;
+ width: 6px; height: 6px;
+ background: var(--cz-primary);
+ transform: rotate(45deg);
+ opacity: .85;
+ transition: transform var(--cz-speed) ease;
+}
+.cz-article-line:hover .cz-line-tick { transform: rotate(45deg) scale(1.35); }
+
+.cz-line-main { flex: 1; min-width: 0; }
+.cz-line-title {
+ display: block;
+ font-size: 15px;
+ color: var(--cz-text);
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+ transition: color var(--cz-speed) ease, padding-left var(--cz-speed) ease;
+}
+.cz-article-line:hover .cz-line-title { color: var(--cz-primary); padding-left: 4px; }
+.cz-article-line .cz-item-summary { margin-top: 4px; -webkit-line-clamp: 1; }
+
+.cz-line-side {
+ flex: none;
+ display: flex; align-items: center; gap: 10px;
+ font-size: 13px; color: var(--cz-text-light);
+}
+
+/* 分页 */
+.cz-pagination {
+ display: flex; justify-content: center; flex-wrap: wrap; gap: 8px;
+ margin-top: 30px;
+}
+.cz-pagination a {
+ min-width: 36px; height: 36px;
+ display: inline-flex; align-items: center; justify-content: center;
+ padding: 0 10px;
+ font-size: 14px;
+ color: var(--cz-text);
+ background: var(--cz-bg);
+ border: 1px solid var(--cz-border);
+ border-radius: 4px;
+ transition: all var(--cz-speed) ease;
+}
+.cz-pagination a:hover {
+ color: #fff;
+ background: var(--cz-primary);
+ border-color: var(--cz-primary);
+}
+.cz-pagination a.active {
+ color: #fff;
+ background: var(--cz-primary);
+ border-color: var(--cz-primary);
+ font-weight: 700;
+ box-shadow: 0 3px 8px rgba(13,106,158,.35);
+}
+.cz-pagination a.disabled {
+ opacity: .45; pointer-events: none;
+}
+
+/* ---------------------------------------------------------------------
+ 12. 详情/单页:文章排版
+ --------------------------------------------------------------------- */
+.cz-article-title {
+ text-align: center;
+ font-size: 24px;
+ font-weight: 700;
+ color: var(--cz-primary-dark);
+ line-height: 1.5;
+ padding: 6px 20px 0;
+}
+
+.cz-article-meta {
+ display: flex; justify-content: center; flex-wrap: wrap; gap: 6px 22px;
+ padding: 14px 0 18px;
+ margin-bottom: 24px;
+ font-size: 13px; color: var(--cz-text-light);
+ border-bottom: 1px solid var(--cz-border);
+ position: relative;
+}
+/* 标题下居中短横(与区块标题语言呼应) */
+.cz-article-meta::before {
+ content: "";
+ position: absolute; left: 50%; top: -12px;
+ width: 42px; height: 3px;
+ transform: translateX(-50%);
+ background: var(--cz-primary);
+ border-radius: 2px;
+}
+
+.cz-article-content {
+ font-size: 15px;
+ line-height: 1.9;
+ color: var(--cz-text);
+}
+.cz-article-content p { margin: 0 0 14px; }
+.cz-article-content h1, .cz-article-content h2,
+.cz-article-content h3, .cz-article-content h4 {
+ margin: 22px 0 12px;
+ color: var(--cz-primary-dark);
+ font-weight: 700;
+}
+.cz-article-content h2 { font-size: 19px; }
+.cz-article-content h3 { font-size: 17px; }
+.cz-article-content h4 { font-size: 15px; }
+.cz-article-content img {
+ max-width: 100%;
+ height: auto;
+ border-radius: var(--cz-radius);
+ margin: 6px auto 14px;
+ box-shadow: var(--cz-shadow-sm);
+}
+.cz-article-content ul, .cz-article-content ol {
+ margin: 0 0 14px; padding-left: 26px;
+}
+.cz-article-content ul li { list-style: disc; }
+.cz-article-content ol li { list-style: decimal; }
+.cz-article-content li { margin-bottom: 6px; }
+.cz-article-content blockquote {
+ margin: 14px 0;
+ padding: 12px 18px;
+ background: rgba(13,106,158,.05);
+ border-left: 4px solid var(--cz-primary);
+ border-radius: 0 var(--cz-radius) var(--cz-radius) 0;
+ color: var(--cz-text-light);
+}
+.cz-article-content table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 14px 0;
+ font-size: 14px;
+}
+.cz-article-content th, .cz-article-content td {
+ border: 1px solid var(--cz-border);
+ padding: 8px 12px;
+ text-align: left;
+}
+.cz-article-content th {
+ background: rgba(13,106,158,.06);
+ color: var(--cz-primary-dark);
+ font-weight: 600;
+}
+.cz-article-content a { color: var(--cz-primary-light); text-decoration: underline; }
+.cz-article-content hr {
+ border: 0; height: 1px;
+ background: var(--cz-border);
+ margin: 20px 0;
+}
+.cz-article-content video, .cz-article-content audio { max-width: 100%; }
+
+/* 上下篇 */
+.cz-sibling {
+ display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
+ margin-top: 34px;
+ padding-top: 22px;
+ border-top: 1px solid var(--cz-border);
+}
+.cz-sib, .cz-sib-none {
+ display: block;
+ padding: 12px 16px;
+ border: 1px solid var(--cz-border);
+ border-radius: var(--cz-radius);
+ background: var(--cz-bg);
+ min-width: 0;
+ transition: border-color var(--cz-speed) ease, background var(--cz-speed) ease, box-shadow var(--cz-speed) ease;
+}
+.cz-sib:hover {
+ border-color: var(--cz-primary);
+ background: var(--cz-card-bg);
+ box-shadow: var(--cz-shadow-sm);
+}
+.cz-sib.next { text-align: right; }
+.cz-sib-label {
+ display: block;
+ font-size: 12px;
+ color: var(--cz-primary);
+ letter-spacing: 2px;
+ margin-bottom: 4px;
+}
+.cz-sib-title {
+ display: block;
+ font-size: 14px;
+ color: var(--cz-text);
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+}
+.cz-sib-none { opacity: .6; }
+.cz-sib-none .cz-sib-label { color: var(--cz-text-light); }
+
+/* ---------------------------------------------------------------------
+ 13. 页脚(深蓝渐变 + 同心圆环纹理 + 三栏 + 底条)
+ --------------------------------------------------------------------- */
+.cz-footer {
+ position: relative;
+ margin-top: 56px;
+ color: var(--cz-ink-on-dark);
+ background: linear-gradient(160deg, var(--cz-footer-bg) 0%, var(--cz-primary-dark) 100%);
+ overflow: hidden;
+}
+
+/* 同心圆环纹理(CSS 绘制,呼应校徽环形语言) */
+.cz-ring {
+ position: absolute;
+ border-radius: 50%;
+ border: 2px solid rgba(255,255,255,.06);
+ pointer-events: none;
+}
+.cz-ring--1 { width: 460px; height: 460px; right: -140px; top: -160px; border-width: 30px; }
+.cz-ring--2 { width: 300px; height: 300px; right: -60px; top: -80px; border-width: 18px; }
+.cz-ring--3 { width: 520px; height: 520px; left: -200px; bottom: -300px; border-width: 34px; }
+
+.cz-footer-inner {
+ width: 1200px; max-width: calc(100% - 40px);
+ margin: 0 auto;
+ position: relative; z-index: 1;
+ display: grid;
+ grid-template-columns: 1.1fr 1.2fr 1.4fr;
+ gap: 40px;
+ padding: 44px 0 36px;
+}
+.cz-footer-inner > * { min-width: 0; }
+
+.cz-footer-brand {
+ display: flex; align-items: center; gap: 14px;
+}
+.cz-footer-badge {
+ flex: none;
+ width: 66px; height: 66px;
+ display: inline-flex; align-items: center; justify-content: center;
+ background: rgba(255,255,255,.94);
+ border-radius: var(--cz-radius);
+ overflow: hidden;
+ box-shadow: 0 2px 10px rgba(8,76,115,.4);
+}
+.cz-footer-badge--plain { color: var(--cz-primary); }
+.cz-footer-logo { width: 100%; height: 100%; object-fit: contain; }
+.cz-footer-site {
+ font-size: 21px;
+ font-weight: 700;
+ letter-spacing: 1.5px;
+ line-height: 1.45;
+ text-shadow: 0 2px 6px rgba(8,76,115,.4);
+}
+
+.cz-footer-info { padding-top: 6px; }
+.cz-footer-line {
+ display: flex; align-items: baseline; gap: 10px;
+ margin-bottom: 10px;
+ font-size: 13px;
+ color: var(--cz-ink-on-dark-soft);
+ line-height: 1.7;
+}
+.cz-dot {
+ flex: none;
+ width: 6px; height: 6px;
+ background: var(--cz-primary-light);
+ border-radius: 50%;
+ transform: translateY(-2px);
+ box-shadow: 0 0 6px rgba(17,103,187,.9);
+}
+
+.cz-footer-links {
+ padding-top: 6px;
+ display: grid; grid-template-columns: 1fr 1fr; gap: 8px 28px;
+}
+.cz-group-name {
+ display: inline-block;
+ font-size: 13px; font-weight: 600;
+ color: #fff;
+ padding-bottom: 4px;
+ margin-bottom: 6px;
+ border-bottom: 2px solid var(--cz-primary-light);
+}
+.cz-links-row {
+ display: flex; flex-wrap: wrap; gap: 4px 14px;
+ margin-bottom: 10px;
+}
+.cz-links-row a {
+ font-size: 13px;
+ color: var(--cz-ink-on-dark-soft);
+ transition: color var(--cz-speed) ease, padding-left var(--cz-speed) ease;
+}
+.cz-links-row a:hover { color: #fff; padding-left: 2px; }
+
+.cz-footer-bottom {
+ position: relative; z-index: 1;
+ border-top: 1px solid rgba(255,255,255,.14);
+ text-align: center;
+ padding: 16px 0;
+ font-size: 13px;
+ color: var(--cz-ink-on-dark-faint);
+ letter-spacing: 1px;
+}
+
+/* ---------------------------------------------------------------------
+ 14. 响应式:1200 / 992 / 768 三档
+ --------------------------------------------------------------------- */
+@media (max-width: 1240px) {
+ .cz-container, .cz-topbar-inner, .cz-brandbar-inner, .cz-nav-inner { max-width: calc(100% - 40px); }
+}
+
+@media (max-width: 992px) {
+ .cz-site-name { font-size: 22px; max-width: 380px; }
+ .cz-search { width: 240px; }
+
+ .cz-nav-list { flex-wrap: wrap; justify-content: flex-start; }
+ .cz-nav-list > li { flex: 0 0 auto; }
+ .cz-nav-list > li > a { height: 46px; font-size: 15px; padding: 0 12px; }
+
+ .cz-headline { grid-template-columns: 1fr; }
+ .cz-blocks { grid-template-columns: repeat(2, 1fr); }
+
+ .cz-banner-slides { height: 380px; }
+ .cz-banner-title { font-size: 19px; bottom: 28px; }
+
+ .cz-footer-inner { grid-template-columns: 1fr 1fr; }
+}
+
+@media (max-width: 768px) {
+ /* —— 品牌行收纳 —— */
+ .cz-brandbar-inner { flex-direction: column; align-items: stretch; gap: 14px; padding: 16px 0; }
+ .cz-site-name { font-size: 19px; max-width: none; white-space: normal; }
+ .cz-brand { justify-content: center; }
+ .cz-search { width: 100%; max-width: none; }
+
+ /* —— 移动端导航:抽屉展开 —— */
+ .cz-nav-toggle {
+ display: inline-flex; flex-direction: column; justify-content: center; gap: 5px;
+ width: 44px; height: 40px;
+ padding: 8px;
+ border: 1px solid var(--cz-border);
+ border-radius: var(--cz-radius);
+ background: var(--cz-card-bg);
+ }
+ .cz-nav-toggle span {
+ display: block; height: 2px;
+ background: var(--cz-primary);
+ border-radius: 2px;
+ transition: transform var(--cz-speed) ease, opacity var(--cz-speed) ease;
+ }
+ .cz-nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
+ .cz-nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
+ .cz-nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
+
+ .cz-nav-inner { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; }
+ /* 吸顶在移动端直接融入文档流配色 */
+ .cz-nav--fixed { position: sticky; animation: none; }
+
+ .cz-nav-list {
+ display: none;
+ position: absolute; left: -20px; right: -20px; top: 100%;
+ flex-direction: column;
+ background: var(--cz-card-bg);
+ box-shadow: var(--cz-shadow-md);
+ border-top: 1px solid var(--cz-border);
+ padding: 6px 16px 12px;
+ max-height: 68vh; overflow: auto;
+ }
+ .cz-nav-list.cz-open { display: flex; }
+ .cz-nav-list > li { text-align: left; border-bottom: 1px solid var(--cz-border); }
+ .cz-nav-list > li:last-child { border-bottom: 0; }
+ .cz-nav-list > li > a { height: 46px; justify-content: flex-start; }
+ .cz-nav-list > li > a::after { display: none; }
+
+ /* 移动端二级:手风琴内联展开(.cz-sub-open 由 main.js 控制) */
+ .cz-sub {
+ position: static;
+ display: none;
+ transform: none;
+ opacity: 1; visibility: visible;
+ background: var(--cz-bg);
+ border-top: 0;
+ box-shadow: none;
+ border-radius: 0;
+ margin: 0 -8px 8px;
+ padding: 4px 0;
+ }
+ .cz-sub::before { display: none; }
+ .cz-sub li a { color: var(--cz-text); margin: 0 8px; }
+ .cz-sub li a:hover { background: rgba(13,106,158,.08); color: var(--cz-primary); }
+ .cz-sub li a::before { background: var(--cz-primary); opacity: .5; }
+ .cz-nav-list li.cz-sub-open .cz-sub { display: block; }
+ .cz-nav-list li.has-sub > a { cursor: pointer; }
+
+ /* —— 内容收纳 —— */
+ .cz-banner-slides { height: 240px; }
+ .cz-banner-title { font-size: 15px; left: 16px; bottom: 20px; max-width: 85%; }
+ .cz-banner-arrow { display: none; }
+
+ .cz-section { margin-top: 28px; }
+ .cz-blocks { grid-template-columns: 1fr; }
+ .cz-block-head h2 { font-size: 19px; }
+
+ .cz-article-row { flex-direction: column; gap: 12px; }
+ .cz-item-cover { width: 100%; }
+ .cz-article-line { flex-wrap: wrap; }
+ .cz-line-side { width: 100%; padding-left: 18px; }
+
+ .cz-page-card { padding: 18px 16px 24px; }
+ .cz-article-title { font-size: 20px; padding: 0; }
+ .cz-article-meta { gap: 4px 14px; }
+ .cz-sibling { grid-template-columns: 1fr; }
+ .cz-sib-title { white-space: normal; }
+
+ .cz-footer-inner { grid-template-columns: 1fr; gap: 26px; padding: 32px 0 26px; }
+ .cz-footer-links { grid-template-columns: 1fr; }
+ .cz-ring--1 { width: 300px; height: 300px; border-width: 20px; }
+}
+
+/* ---------------------------------------------------------------------
+ 15. 动效偏好:尊重系统减弱动态设置
+ --------------------------------------------------------------------- */
+@media (prefers-reduced-motion: reduce) {
+ *, *::before, *::after {
+ animation-duration: .01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: .01ms !important;
+ }
+}
+
+/* B4 友链 Logo:与名称并排小图(高度 ~20px,垂直居中;过宽截断不撑破页脚) */
+.links-group a .link-logo,
+.cz-links-row a .link-logo {
+ height: 20px;
+ width: auto;
+ max-width: 64px;
+ object-fit: contain;
+ vertical-align: middle;
+ margin-right: 4px;
+ border-radius: 2px;
+}
+
+/* ===== 左侧栏目导航(docs/11):有二级节点的模块,栏目/文章页左侧展示兄弟目录 ===== */
+.cz-cols { display: flex; align-items: flex-start; gap: 28px; }
+.cz-cols .cz-page-card { flex: 1; min-width: 0; }
+.cz-side-nav {
+ flex: none;
+ width: 230px;
+ background: var(--cz-card-bg);
+ border: 1px solid var(--cz-border);
+ border-top: 3px solid var(--cz-primary);
+ box-shadow: var(--cz-shadow-md);
+}
+.cz-side-nav-head {
+ background: var(--cz-primary);
+ color: #fff;
+ font-size: 20px;
+ font-weight: 700;
+ text-align: center;
+ padding: 18px 12px;
+ letter-spacing: 3px;
+}
+.cz-side-nav-list { list-style: none; margin: 0; padding: 0; }
+.cz-side-nav-item + .cz-side-nav-item { border-top: 1px solid var(--cz-border); }
+.cz-side-nav-item a {
+ display: block;
+ padding: 13px 18px;
+ color: var(--cz-text);
+ text-decoration: none;
+ font-size: 15px;
+ border-left: 3px solid transparent;
+ transition: background .15s ease, color .15s ease, border-color .15s ease;
+}
+.cz-side-nav-item a:hover { color: var(--cz-primary); background: var(--cz-panel); }
+.cz-side-nav-item.active a {
+ background: var(--cz-primary);
+ color: #fff;
+ font-weight: 600;
+ text-decoration: none;
+ border-left-color: var(--cz-primary-light);
+}
+/* 顶导航二级下拉当前项高亮(docs/11 顺带) */
+.cz-nav-list ul.cz-sub li.active a { color: var(--cz-primary-light); }
+@media (max-width: 768px) {
+ .cz-cols { flex-direction: column; gap: 16px; }
+ .cz-side-nav { width: 100%; }
+ .cz-side-nav-list { display: flex; overflow-x: auto; -webkit-overflow-scrolling: touch; }
+ .cz-side-nav-item { flex: none; }
+ .cz-side-nav-item + .cz-side-nav-item { border-top: none; border-left: 1px solid var(--cz-border); }
+ .cz-side-nav-item a { white-space: nowrap; border-left: none; }
+}
+@media print {
+ .cz-side-nav { display: none; }
+ .cz-cols { display: block; }
+}
+
+/* ---------------------------------------------------------------------
+ 16. 首页布局模式区块(fragments/home-blocks.html)
+ 站点配了 home_layout 时首页正文由本主题渲染:整宽区块卡 + 全宽封面头条 + 圆点密行。
+ --------------------------------------------------------------------- */
+/* 青蓝配青绿:标题竖条/线脚与列表圆点走 accent,圆角比基座更大(卡片更柔和) */
+.cz-block-head--bar h2::before { background: var(--cz-accent); }
+.cz-block-tick { background: var(--cz-accent); }
+/* 居中双线标题下的「更多」钉在标题行右端(师范/农林官网惯例:标题居中、更多右置) */
+.cz-block-head .cz-more {
+ position: absolute; right: 0; bottom: 13px;
+ font-size: 13px;
+}
+
+.cz-section { position: relative; }
+.cz-sec-bg {
+ position: absolute; inset: 0; z-index: 0;
+ background-size: cover; background-position: center;
+ opacity: .45; pointer-events: none;
+}
+/* 定位元素默认画在普通流之上:不抬 z-index,背景带会糊在卡片正面(截图实测整卡泛色)。
+ 带图时卡片转半透明白,让底图若隐若现——高校官网新闻带的通行做法 */
+.cz-sec-bg + .cz-block { position: relative; z-index: 1; background: rgba(255, 255, 255, .88); }
+.cz-block--flow { padding: 20px 26px 14px; }
+.cz-block--flow:hover { transform: none; box-shadow: var(--cz-shadow-sm); }
+/* grid 轨道用 minmax(0,1fr):否则 nowrap 省略行的 min-content 会撑破轨道(中文标题尤其明显) */
+.cz-split {
+ display: grid;
+ grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
+ gap: 26px;
+ padding-top: 14px;
+}
+.cz-split > * { min-width: 0; }
+.cz-hero {
+ position: relative;
+ display: block;
+ margin-top: 14px;
+ border-radius: var(--cz-radius-lg);
+ overflow: hidden;
+ background: var(--cz-bg);
+}
+.cz-hero img { width: 100%; height: 300px; object-fit: cover; transition: transform .5s ease; }
+.cz-hero:hover img { transform: scale(1.03); }
+.cz-hero-plain { display: block; height: 8px; background: var(--cz-accent); }
+.cz-hero-mask {
+ position: absolute; left: 0; right: 0; bottom: 0;
+ padding: 40px 22px 16px;
+ background: linear-gradient(transparent, rgba(8, 76, 115, .88));
+ color: #fff;
+}
+.cz-hero-plain + .cz-hero-mask {
+ position: static;
+ padding: 16px 22px;
+ background: var(--cz-card-bg);
+ color: var(--cz-text);
+}
+.cz-hero-title {
+ display: block;
+ font-size: 20px; font-weight: 700; line-height: 1.5;
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+}
+.cz-hero-meta { display: flex; align-items: center; gap: 10px; margin-top: 6px; font-size: 12px; opacity: .9; }
+.cz-block-list--two { columns: 2; column-gap: 34px; }
+.cz-block-list--two .cz-block-item { break-inside: avoid; }
+.cz-item-bullet {
+ flex: none;
+ width: 5px; height: 5px;
+ border-radius: 50%;
+ background: var(--cz-accent);
+}
+.cz-item-date {
+ flex: none;
+ font-size: 12px; color: var(--cz-text-light);
+ font-variant-numeric: tabular-nums;
+}
+.cz-src {
+ flex: none;
+ font-size: 11px; line-height: 18px; padding: 0 6px;
+ color: var(--cz-primary); border: 1px solid var(--cz-primary);
+ border-radius: 999px;
+}
+.cz-wall {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 16px;
+ margin: 16px 0 0;
+}
+.cz-wall--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
+.cz-wall-item {
+ position: relative;
+ border-radius: var(--cz-radius-lg);
+ overflow: hidden;
+ box-shadow: var(--cz-shadow-sm);
+}
+.cz-wall-item img { width: 100%; height: 168px; object-fit: cover; transition: transform .5s ease; }
+.cz-wall-item:hover img { transform: scale(1.05); }
+.cz-wall-cap {
+ position: absolute; left: 0; right: 0; bottom: 0;
+ padding: 28px 12px 10px;
+ font-size: 13px; color: #fff;
+ background: linear-gradient(transparent, rgba(11, 51, 72, .85));
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+}
+.cz-gallery-sub {
+ margin: -4px 0 4px;
+ text-align: center;
+ font-size: 12px; letter-spacing: .18em; text-transform: uppercase;
+ color: var(--cz-text-light);
+}
+/* 速递条:flex 项自动最小尺寸 = min-content,中文可按字断行 → 不锁 nowrap/不收缩就会塌成一字一列 */
+.cz-ticker {
+ position: relative;
+ background: var(--cz-primary);
+ color: #fff;
+ padding: 11px 0;
+ font-size: 14px;
+}
+.cz-ticker-inner { display: flex; align-items: center; gap: 16px; min-width: 0; }
+.cz-ticker-label {
+ flex: none;
+ font-weight: 700; letter-spacing: .06em;
+ padding: 2px 14px;
+ border-radius: 999px;
+ background: var(--cz-accent);
+}
+.cz-ticker-list {
+ display: flex; gap: 28px;
+ flex: 1; min-width: 0;
+ overflow: hidden; white-space: nowrap;
+}
+.cz-ticker-list li { flex: none; min-width: 0; }
+.cz-ticker-item {
+ display: block; flex: none;
+ max-width: 320px;
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
+ color: #fff; opacity: .92;
+}
+.cz-ticker-item:hover { opacity: 1; text-decoration: underline; }
+.cz-links-group {
+ margin: 12px 0 0;
+ font-size: 13px; letter-spacing: .08em;
+ color: var(--cz-text-light);
+}
+.cz-links { display: flex; flex-wrap: wrap; gap: 10px; margin: 8px 0 0; }
+.cz-links a {
+ font-size: 13px; color: var(--cz-text-light);
+ padding: 4px 14px;
+ background: var(--cz-card-bg);
+ border: 1px solid var(--cz-border);
+ border-radius: 999px;
+}
+.cz-links a:hover { color: var(--cz-primary); border-color: var(--cz-primary); }
+
+@media (max-width: 992px) {
+ .cz-split { grid-template-columns: minmax(0, 1fr); }
+ .cz-wall, .cz-wall--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
+ .cz-block-list--two { columns: 1; }
+ .cz-hero img { height: 190px; }
+ .cz-ticker-item { max-width: 180px; }
+ .cz-block--flow { padding: 16px 16px 8px; }
+}
diff --git a/src/main/resources/templates/themes/campus-azure/assets/favicon.png b/src/main/resources/templates/themes/campus-azure/assets/favicon.png
new file mode 100644
index 0000000..ac16156
Binary files /dev/null and b/src/main/resources/templates/themes/campus-azure/assets/favicon.png differ
diff --git a/src/main/resources/templates/themes/campus-azure/assets/favicon.svg b/src/main/resources/templates/themes/campus-azure/assets/favicon.svg
new file mode 100644
index 0000000..b64acaf
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/assets/favicon.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/main/resources/templates/themes/campus-azure/assets/js/main.js b/src/main/resources/templates/themes/campus-azure/assets/js/main.js
new file mode 100644
index 0000000..3ef9a19
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/assets/js/main.js
@@ -0,0 +1,190 @@
+/* campus-azure 主题脚本:顶栏日期 + 轮播(圆点/箭头/触摸) + 导航吸顶反蓝 + 移动端抽屉与二级手风琴。
+ 与 default 同源逻辑,无任何外部依赖。 */
+(function () {
+ 'use strict';
+
+ /* ---------- 顶栏日期(本地时间,YYYY年M月D日 星期X) ---------- */
+ var dateEl = document.getElementById('siteDate');
+ if (dateEl) {
+ var now = new Date();
+ var week = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()];
+ dateEl.textContent = now.getFullYear() + '年' + (now.getMonth() + 1) + '月'
+ + now.getDate() + '日 星期' + week;
+ }
+
+ /* ---------- 导航吸顶反蓝(桌面端;≤768 不吸顶) ---------- */
+ var nav = document.getElementById('czNav');
+ var DESKTOP_MIN = 769;
+ var navBaseTop = 0;
+ var holder = null;
+
+ function measureNavTop() {
+ unlockNav();
+ navBaseTop = nav.getBoundingClientRect().top + window.pageYOffset;
+ }
+
+ function lockNav() {
+ if (!nav.classList.contains('cz-nav--fixed')) {
+ holder = document.createElement('div');
+ holder.className = 'cz-nav-holder';
+ holder.style.height = nav.offsetHeight + 'px';
+ nav.parentNode.insertBefore(holder, nav);
+ nav.classList.add('cz-nav--fixed');
+ } else if (holder) {
+ holder.style.height = nav.offsetHeight + 'px';
+ }
+ }
+
+ function unlockNav() {
+ nav.classList.remove('cz-nav--fixed');
+ if (holder && holder.parentNode) {
+ holder.parentNode.removeChild(holder);
+ }
+ holder = null;
+ }
+
+ function onScrollNav() {
+ if (window.innerWidth < DESKTOP_MIN) {
+ unlockNav();
+ return;
+ }
+ if (window.pageYOffset > navBaseTop) {
+ lockNav();
+ } else {
+ unlockNav();
+ }
+ }
+
+ if (nav) {
+ measureNavTop();
+ window.addEventListener('scroll', onScrollNav, { passive: true });
+ var resizeTimer = null;
+ window.addEventListener('resize', function () {
+ if (resizeTimer) { window.clearTimeout(resizeTimer); }
+ resizeTimer = window.setTimeout(function () {
+ measureNavTop();
+ onScrollNav();
+ }, 150);
+ });
+ }
+
+ /* ---------- 移动端抽屉 + 二级手风琴 ---------- */
+ var navToggle = document.querySelector('.cz-nav-toggle');
+ var navList = document.querySelector('.cz-nav-list');
+
+ if (navToggle && navList) {
+ navToggle.addEventListener('click', function () {
+ var open = navList.classList.toggle('cz-open');
+ navToggle.setAttribute('aria-expanded', open ? 'true' : 'false');
+ });
+ }
+
+ /* 窄屏下:点击带二级的项先展开面板,再点才跳转;宽屏交还给 CSS hover */
+ if (navList) {
+ navList.addEventListener('click', function (e) {
+ if (window.innerWidth >= DESKTOP_MIN) { return; }
+ var link = e.target.closest ? e.target.closest('a') : null;
+ if (!link) { return; }
+ var li = link.parentElement;
+ if (!li || !li.classList.contains('has-sub')) { return; }
+ var sub = li.querySelector('.cz-sub');
+ if (!sub) { return; }
+ if (!li.classList.contains('cz-sub-open')) {
+ e.preventDefault();
+ li.classList.add('cz-sub-open');
+ }
+ });
+ }
+
+ /* ---------- 首页轮播 ---------- */
+ var root = document.querySelector('.cz-banner');
+ var slides = document.querySelectorAll('.cz-banner-slide');
+ var dots = document.querySelectorAll('.cz-banner-dots button');
+ var prevBtn = document.querySelector('.cz-banner-arrow.prev');
+ var nextBtn = document.querySelector('.cz-banner-arrow.next');
+ if (!slides.length || !root) {
+ return;
+ }
+ var current = 0;
+ var timer = null;
+ var INTERVAL = 5000;
+
+ function show(index) {
+ slides[current].classList.remove('active');
+ if (dots[current]) {
+ dots[current].classList.remove('active');
+ }
+ current = (index + slides.length) % slides.length;
+ slides[current].classList.add('active');
+ if (dots[current]) {
+ dots[current].classList.add('active');
+ }
+ }
+
+ function start() {
+ stop();
+ if (slides.length > 1) {
+ timer = window.setInterval(function () {
+ show(current + 1);
+ }, INTERVAL);
+ }
+ }
+
+ function stop() {
+ if (timer) {
+ window.clearInterval(timer);
+ timer = null;
+ }
+ }
+
+ dots.forEach(function (dot, index) {
+ dot.addEventListener('click', function () {
+ show(index);
+ start();
+ });
+ });
+ if (prevBtn) {
+ prevBtn.addEventListener('click', function () {
+ show(current - 1);
+ start();
+ });
+ }
+ if (nextBtn) {
+ nextBtn.addEventListener('click', function () {
+ show(current + 1);
+ start();
+ });
+ }
+ root.addEventListener('mouseenter', stop);
+ root.addEventListener('mouseleave', start);
+ root.addEventListener('focusin', stop);
+ root.addEventListener('focusout', start);
+ root.setAttribute('tabindex', '-1');
+ root.addEventListener('keydown', function (e) {
+ if (e.key === 'ArrowLeft') {
+ show(current - 1);
+ start();
+ } else if (e.key === 'ArrowRight') {
+ show(current + 1);
+ start();
+ }
+ });
+
+ /* 触摸滑动切页 */
+ var touchX = null;
+ root.addEventListener('touchstart', function (e) {
+ touchX = e.changedTouches[0].clientX;
+ stop();
+ }, { passive: true });
+ root.addEventListener('touchend', function (e) {
+ if (touchX === null) { return; }
+ var dx = e.changedTouches[0].clientX - touchX;
+ if (Math.abs(dx) > 40) {
+ show(dx < 0 ? current + 1 : current - 1);
+ }
+ touchX = null;
+ start();
+ }, { passive: true });
+
+ start();
+})();
diff --git a/src/main/resources/templates/themes/campus-azure/assets/screenshot.png b/src/main/resources/templates/themes/campus-azure/assets/screenshot.png
new file mode 100644
index 0000000..e278e48
Binary files /dev/null and b/src/main/resources/templates/themes/campus-azure/assets/screenshot.png differ
diff --git a/src/main/resources/templates/themes/campus-azure/detail.html b/src/main/resources/templates/themes/campus-azure/detail.html
new file mode 100644
index 0000000..6cd44f7
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/detail.html
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 文章标题
+
+
+ 作者
+ 来源
+ 浏览量
+
+
+ 正文
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/campus-azure/fragments/footer.html b/src/main/resources/templates/themes/campus-azure/fragments/footer.html
new file mode 100644
index 0000000..2a9e163
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/fragments/footer.html
@@ -0,0 +1,59 @@
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/violet-iris/fragments/head.html b/src/main/resources/templates/themes/campus-azure/fragments/head.html
similarity index 74%
rename from src/main/resources/templates/themes/violet-iris/fragments/head.html
rename to src/main/resources/templates/themes/campus-azure/fragments/head.html
index 1809482..f9395a0 100644
--- a/src/main/resources/templates/themes/violet-iris/fragments/head.html
+++ b/src/main/resources/templates/themes/campus-azure/fragments/head.html
@@ -1,6 +1,6 @@
-
+
@@ -8,16 +8,13 @@
-
-
-
diff --git a/src/main/resources/templates/themes/campus-azure/fragments/header.html b/src/main/resources/templates/themes/campus-azure/fragments/header.html
new file mode 100644
index 0000000..b2a9883
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/fragments/header.html
@@ -0,0 +1,86 @@
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/campus-azure/fragments/home-blocks.html b/src/main/resources/templates/themes/campus-azure/fragments/home-blocks.html
new file mode 100644
index 0000000..a252e1a
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/fragments/home-blocks.html
@@ -0,0 +1,209 @@
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ 文章标题
+ 置顶
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ 文章标题
+ 置顶
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+ 媒体来源
+ 文章标题
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
线上展厅
+
+
+
+ Online Exhibition Hall
+
+
+
+
+
+
+
+
+
友情链接
+
+
+
+ 分组
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/campus-azure/home.html b/src/main/resources/templates/themes/campus-azure/home.html
new file mode 100644
index 0000000..037a873
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/home.html
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
头条推荐
+
+
+
+ -
+ 头条标题
+
+ 置顶
+
+
+
+ -
+ 置顶
+ 文章标题
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/campus-azure/list.html b/src/main/resources/templates/themes/campus-azure/list.html
new file mode 100644
index 0000000..1a58292
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/list.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
栏目名
+
搜索词
+
+
+
+ -
+
+
+
+
+
+
+
摘要
+
+
+ 置顶
+
+
+
+
+
+
+
+ 置顶
+
+
+
+
+
+
+
未找到相关内容
+
栏目暂无内容
+
换个关键词试试
+
内容发布后将在此展示
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/campus-azure/single.html b/src/main/resources/templates/themes/campus-azure/single.html
new file mode 100644
index 0000000..86422bf
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/single.html
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 栏目名
+
+ 单页内容
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/templates/themes/campus-azure/theme.json b/src/main/resources/templates/themes/campus-azure/theme.json
new file mode 100644
index 0000000..e72758d
--- /dev/null
+++ b/src/main/resources/templates/themes/campus-azure/theme.json
@@ -0,0 +1,23 @@
+{
+ "specVersion": 1,
+ "name": "campus-azure",
+ "title": "青蓝校园(campus-azure)",
+ "version": "1.0.0",
+ "author": "yunhai",
+ "description": "青蓝校园·师范/农林类官网门户:青蓝顶栏+白底主导航+青绿描边标题+大日期数字列表+图文左列右栏+圆角卡片区块+深色页脚带二维码位。基座 scholar-blue,配色与首页区块形态按师范/农林类高校官网重做。",
+ "screenshot": "assets/screenshot.png",
+ "bannerSize": "1920x560",
+ "params": [
+ { "key": "primary", "cssVar": "--cz-primary", "label": "主色", "type": "color", "default": "#0d6a9e" },
+ { "key": "primaryDark", "cssVar": "--cz-primary-dark", "label": "主色加深", "type": "color", "default": "#084c73" },
+ { "key": "primaryLight", "cssVar": "--cz-primary-light","label": "主色提亮", "type": "color", "default": "#1d87bd" },
+ { "key": "accent", "cssVar": "--cz-accent", "label": "点缀青绿", "type": "color", "default": "#2b9c8f" },
+ { "key": "navBg", "cssVar": "--cz-nav-bg", "label": "导航条底色", "type": "color", "default": "#ffffff" },
+ { "key": "footerBg", "cssVar": "--cz-footer-bg", "label": "页脚底色", "type": "color", "default": "#0b3348" },
+ { "key": "text", "cssVar": "--cz-text", "label": "正文文字色", "type": "color", "default": "#303c46" },
+ { "key": "textLight", "cssVar": "--cz-text-light", "label": "次要文字色", "type": "color", "default": "#6e7d88" },
+ { "key": "bg", "cssVar": "--cz-bg", "label": "页面底色", "type": "color", "default": "#eef3f6" },
+ { "key": "cardBg", "cssVar": "--cz-card-bg", "label": "卡片底色", "type": "color", "default": "#ffffff" },
+ { "key": "border", "cssVar": "--cz-border", "label": "边框色", "type": "color", "default": "#d9e5ec" }
+ ]
+}
diff --git a/src/main/resources/templates/themes/cherry-bloom/README.md b/src/main/resources/templates/themes/cherry-bloom/README.md
deleted file mode 100644
index ebf6e2e..0000000
--- a/src/main/resources/templates/themes/cherry-bloom/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# cherry-bloom 皮肤包
-
-由 mint-breeze 派生的温柔樱粉风皮肤(docs/10 契约 §5 工作流)。**升级随版本发布,不在站点间复制目录**。
-
-
-## 风格定位
-
-温柔、甜美,适合幼儿园与小学门户:樱花粉品牌色、大圆角 16px、卡片纯白+暖粉柔和阴影、细线顶栏+居中 logo(桌面吸顶,移动端取消)、列表卡片网格(一行 3 张)、花瓣式圆点装饰与暖白留白;无纹理、无通栏大图、无复杂动效。
-
-## 数据契约(模板可取用的 model 属性全集,契约 §3)
-
-| 页面 | 属性 |
-| --- | --- |
-| 全部 | `site`(快照:config/分类树/轮播/友链组/院系子站)、`url`(PortalUrlHelper:home/category/article/asset/search/siteHome)、`themeBase`(=`themes/cherry-bloom`)、`navCategories`、`pageTitle`、`seoDescription`、`canonical`、`themeParams`(微调参数,仅 theme.json 声明过的 key)、`themeVarsCss`(服务端预构建 `:root{}` 覆盖串,无参数为空) |
-| home | `banners`(时间窗内 home 位)、`topArticles`(置顶+最新 6)、`categoryBlocks`(LIST 型根栏目块,各 top 8) |
-| list / search | `listData`(分页)、`category`(list)、`q` + `searchMode`(search) |
-| detail | `article`、`prevArticle`、`nextArticle`、`currentCategoryId` |
-| single | `category`(含 `content`)、`currentCategoryId` |
-
-原则:皮肤不得假设"首页一定有轮播",对空集合优雅降级。
-
-## 轮播图尺寸约定(bannerSize)
-
-1920x560(管理端上传端按此引导裁剪,D2 决策点)。
-
-## 可调参数
-
-见 `theme.json` 的 `params`:
-
-- **color**(进 CSS 变量):`primary` 主色 / `primaryDark` 主色加深(即强调色,用于品牌文字与悬停加深)/ `primaryLight` 主色提亮 / `bg` 页面底色 / `cardBg` 卡片底色 / `border` 边框色 / `text` 正文文字 / `textLight` 次要文字。
-- **select**:`listLayout` = `grid`(默认,卡片网格一行 3 张)或 `row`(传统行列表)。
-
-换色建议:主色系三值同步调整(primary / primaryDark / primaryLight),bg 与 border、primaryLight 保持同族浅色调,避免底色与卡片对比失衡。
-
-优先级:`custom_css` > `themeVarsCss` > `main.css`。
diff --git a/src/main/resources/templates/themes/cherry-bloom/assets/css/main.css b/src/main/resources/templates/themes/cherry-bloom/assets/css/main.css
deleted file mode 100644
index 3362d07..0000000
--- a/src/main/resources/templates/themes/cherry-bloom/assets/css/main.css
+++ /dev/null
@@ -1,616 +0,0 @@
-/* ============================================================
- * cherry-bloom 皮肤包样式(mint-breeze 派生,docs/10 皮肤包契约 §5)
- * 温柔樱粉风:樱花粉品牌色 + 大圆角 16px + 柔和暖粉阴影 + 卡片网格列表
- * + 花瓣式圆点装饰与暖白留白;无纹理、无通栏大图、无复杂动效。
- * 轮播图设计尺寸约定:1920×560(管理端上传端按此引导裁剪)。
- * ============================================================ */
-:root {
- --primary: #DB5A8B;
- --primary-dark: #B23A68;
- --primary-light: #FDECF3;
- --text: #43333B;
- --text-light: #9C828C;
- --bg: #FFFAFB;
- --card-bg: #FFFFFF;
- --border: #F7DDE7;
- --radius: 16px;
- --radius-sm: 10px;
- --radius-pill: 999px;
- --shadow-soft: 0 6px 18px rgba(178, 58, 104, .08);
- --shadow-hover: 0 12px 28px rgba(178, 58, 104, .14);
- --max-width: 1200px;
-}
-
-* { box-sizing: border-box; }
-body {
- margin: 0;
- font-family: "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
- color: var(--text);
- background: var(--bg);
-}
-a { color: inherit; text-decoration: none; transition: color .15s ease; }
-a:hover { color: var(--primary); }
-img { max-width: 100%; }
-time, .item-meta { color: var(--text-light); font-size: 13px; }
-.empty { color: var(--text-light); text-align: center; padding: 32px 0; }
-
-/* ===== 头部:细线顶栏 + 居中品牌行 + 白底导航(桌面吸顶) ===== */
-.site-header {
- position: sticky;
- top: 0;
- z-index: 90;
- background: var(--card-bg);
- box-shadow: var(--shadow-soft);
-}
-/* 细线顶栏:院系切换在左、站内搜索在右;院系未配置时搜索仍靠右 */
-.top-bar {
- display: flex;
- align-items: center;
- justify-content: flex-end;
- gap: 16px;
- padding: 7px max(16px, calc((100% - var(--max-width)) / 2 + 16px));
- border-bottom: 1px solid var(--border);
- font-size: 13px;
-}
-.top-bar .site-colleges { margin-right: auto; }
-/* 居中品牌行:两侧几何圆点装饰(纯 CSS,无纹理) */
-.brand-row {
- position: relative;
- display: flex;
- justify-content: center;
- padding: 18px 16px 14px;
-}
-.brand-row::before, .brand-row::after {
- content: "";
- position: absolute;
- top: 50%;
- transform: translateY(-50%);
- width: 46px;
- height: 10px;
- opacity: .45;
- background-image:
- radial-gradient(circle, var(--primary) 2.2px, transparent 2.8px),
- radial-gradient(circle, var(--primary) 1.6px, transparent 2.2px),
- radial-gradient(circle, var(--primary) 1.1px, transparent 1.7px);
- background-repeat: no-repeat;
- background-position: left center, center center, right center;
-}
-.brand-row::before { left: 6%; }
-.brand-row::after { right: 6%; }
-.site-brand { display: flex; align-items: center; gap: 14px; }
-.site-logo { height: 52px; }
-.site-name {
- font-size: 28px;
- font-weight: 600;
- letter-spacing: .02em;
- color: var(--primary-dark);
-}
-.site-name:hover { color: var(--primary); }
-.site-search { display: flex; align-items: center; }
-.site-search input {
- border: 1px solid var(--border);
- border-right: none;
- border-radius: var(--radius-pill) 0 0 var(--radius-pill);
- padding: 7px 16px;
- width: 220px;
- outline: none;
- background: var(--card-bg);
- color: var(--text);
- transition: border-color .15s ease, box-shadow .15s ease;
-}
-.site-search input:focus {
- border-color: var(--primary);
- box-shadow: 0 0 0 3px var(--primary-light);
-}
-.site-search button {
- border: none;
- background: var(--primary);
- color: #fff;
- padding: 7px 20px;
- border-radius: 0 var(--radius-pill) var(--radius-pill) 0;
- cursor: pointer;
- transition: background .15s ease;
-}
-.site-search button:hover { background: var(--primary-dark); }
-
-/* ===== 专业院系下拉(院系子站切换):胶囊开关 + 圆角白卡面板 ===== */
-.site-colleges { position: relative; }
-.site-colleges .colleges-toggle {
- display: inline-flex;
- align-items: center;
- gap: 6px;
- border: 1px solid var(--border);
- border-radius: var(--radius-pill);
- padding: 5px 14px;
- cursor: pointer;
- color: var(--primary-dark);
- font-weight: 600;
- white-space: nowrap;
- transition: border-color .15s ease, background .15s ease;
-}
-.site-colleges:hover .colleges-toggle {
- border-color: var(--primary);
- background: var(--primary-light);
-}
-.site-colleges .colleges-arrow { font-style: normal; font-size: 12px; color: var(--primary); }
-.site-colleges .colleges-menu {
- display: none;
- position: absolute;
- top: 100%;
- left: 0;
- min-width: 200px;
- max-height: 420px;
- overflow-y: auto;
- margin: 0;
- padding: 8px 0;
- list-style: none;
- background: var(--card-bg);
- border: 1px solid var(--border);
- border-radius: var(--radius);
- box-shadow: var(--shadow-hover);
- z-index: 110;
-}
-.site-colleges:hover .colleges-menu { display: block; }
-.site-colleges .colleges-menu li a {
- display: block;
- margin: 0 8px;
- padding: 9px 12px;
- border-radius: var(--radius-sm);
- color: var(--text);
- white-space: nowrap;
-}
-.site-colleges .colleges-menu li a:hover { background: var(--primary-light); color: var(--primary-dark); }
-.site-colleges .colleges-menu li.active a { color: var(--primary); font-weight: 600; }
-
-/* ===== 主导航:白底 + 柔和文字层级,当前项圆点标记 ===== */
-.site-nav { background: var(--card-bg); border-top: 1px solid var(--border); }
-.site-nav ul {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 0 16px;
- list-style: none;
- display: flex;
- justify-content: center;
- flex-wrap: wrap;
-}
-.site-nav li a {
- position: relative;
- display: block;
- padding: 13px 20px;
- color: var(--text);
- font-weight: 500;
-}
-.site-nav li a:hover { color: var(--primary); }
-.site-nav li.active a { color: var(--primary); font-weight: 600; }
-/* 几何圆点:当前栏目下方的小圆点 */
-.site-nav li.active > a::before {
- content: "";
- position: absolute;
- left: 50%;
- bottom: 5px;
- width: 5px;
- height: 5px;
- transform: translateX(-50%);
- border-radius: 50%;
- background: var(--primary);
-}
-
-/* ===== 二级下拉导航:圆角白卡面板 ===== */
-.site-nav > ul > li { position: relative; }
-.site-nav li.has-sub > a::after { content: " ▾"; font-size: 12px; opacity: .7; }
-.site-nav ul.sub-nav {
- display: none;
- position: absolute;
- top: 100%;
- left: 0;
- min-width: 168px;
- max-width: none;
- margin: 0;
- padding: 8px 0;
- list-style: none;
- background: var(--card-bg);
- border: 1px solid var(--border);
- border-radius: var(--radius);
- box-shadow: var(--shadow-hover);
- z-index: 100;
-}
-.site-nav li:hover > .sub-nav { display: block; }
-.site-nav .sub-nav li a {
- margin: 0 8px;
- padding: 9px 12px;
- border-radius: var(--radius-sm);
- color: var(--text);
- font-weight: 400;
- white-space: nowrap;
- background: none;
-}
-.site-nav .sub-nav li a:hover { background: var(--primary-light); color: var(--primary-dark); }
-.site-nav .sub-nav li.active a { color: var(--primary); font-weight: 600; }
-
-/* ===== 首页轮播:容器内圆角卡片(非通栏),几何圆点指示器 ===== */
-.banner {
- position: relative;
- width: min(var(--max-width), calc(100% - 32px));
- margin: 24px auto 0;
- border-radius: var(--radius);
- overflow: hidden;
- box-shadow: var(--shadow-soft);
-}
-.banner-slides { position: relative; height: 400px; }
-.banner-slide { display: none; position: absolute; inset: 0; }
-.banner-slide.active { display: block; }
-.banner-slide img { width: 100%; height: 100%; object-fit: cover; }
-.banner-title {
- position: absolute;
- left: 0; right: 0; bottom: 0;
- padding: 14px 20px;
- color: #fff;
- font-weight: 500;
- background: linear-gradient(transparent, rgba(20, 63, 61, .62));
-}
-.banner-dots {
- position: absolute;
- bottom: 14px; right: 20px;
- display: flex; gap: 8px;
-}
-.banner-dots button {
- width: 9px; height: 9px;
- border-radius: 50%;
- border: none;
- background: rgba(255, 255, 255, .55);
- cursor: pointer;
- transition: background .15s ease, transform .15s ease;
-}
-.banner-dots button.active { background: #fff; transform: scale(1.25); }
-
-/* ===== 首页区块:卡片网格(头条通栏 + 栏目块一行 3 张) ===== */
-.home-main {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 28px 16px 56px;
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 24px;
-}
-.top-strip, .category-block {
- background: var(--card-bg);
- border-radius: var(--radius);
- box-shadow: var(--shadow-soft);
- padding: 24px;
-}
-.top-strip { grid-column: 1 / -1; }
-/* 栏目标题:几何圆点标记(环形点),标题中等粗细、层级柔和 */
-.section-title, .block-head h2 {
- margin: 0 0 14px;
- font-size: 19px;
- font-weight: 600;
- letter-spacing: .02em;
- display: flex;
- align-items: center;
- gap: 10px;
-}
-.section-title::before, .block-head h2::before {
- content: "";
- flex: none;
- width: 9px;
- height: 9px;
- border-radius: 50%;
- background: var(--primary);
- box-shadow: 0 0 0 3.5px var(--primary-light);
-}
-.block-head { display: flex; align-items: center; justify-content: space-between; }
-.more {
- flex: none;
- font-size: 13px;
- color: var(--text-light);
- padding: 4px 12px;
- border: 1px solid var(--border);
- border-radius: var(--radius-pill);
- transition: color .15s ease, border-color .15s ease, background .15s ease;
-}
-.more:hover {
- color: var(--primary-dark);
- border-color: var(--primary);
- background: var(--primary-light);
-}
-.top-strip ul, .block-list { list-style: none; margin: 0; padding: 0; }
-.top-strip li, .block-list li {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 12px;
- padding: 10px 0;
- border-bottom: 1px dashed var(--border);
-}
-.top-strip li:last-child, .block-list li:last-child { border-bottom: none; }
-.top-strip li a, .block-list li a {
- flex: 1;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.top-badge {
- flex: none;
- color: var(--primary-dark);
- background: var(--primary-light);
- font-size: 12px;
- font-weight: 500;
- padding: 2px 10px;
- border-radius: var(--radius-pill);
-}
-
-/* ===== 列表页:卡片网格(默认一行 3 张;listLayout=row 切换行列表) ===== */
-.list-main {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 28px 16px 56px;
-}
-.breadcrumb { color: var(--text-light); font-size: 13px; margin-bottom: 14px; }
-.breadcrumb a { margin-right: 8px; }
-.breadcrumb span { margin-left: 8px; }
-.page-title {
- font-size: 24px;
- font-weight: 600;
- letter-spacing: .02em;
- margin: 0 0 22px;
- display: flex;
- align-items: center;
- gap: 10px;
-}
-.page-title::before {
- content: "";
- flex: none;
- width: 9px;
- height: 9px;
- border-radius: 50%;
- background: var(--primary);
- box-shadow: 0 0 0 3.5px var(--primary-light);
-}
-.article-list {
- list-style: none;
- margin: 0;
- padding: 0;
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 20px;
-}
-.article-list li {
- background: var(--card-bg);
- border-radius: var(--radius);
- box-shadow: var(--shadow-soft);
- padding: 22px 20px;
- display: flex;
- flex-direction: column;
- gap: 10px;
- transition: transform .18s ease, box-shadow .18s ease;
-}
-.article-list li:hover { transform: translateY(-3px); box-shadow: var(--shadow-hover); }
-.item-title {
- font-size: 16px;
- font-weight: 600;
- line-height: 1.55;
- overflow: hidden;
- display: -webkit-box;
- -webkit-line-clamp: 2;
- -webkit-box-orient: vertical;
-}
-.article-list li:hover .item-title { color: var(--primary); }
-.item-summary {
- color: var(--text-light);
- font-size: 13.5px;
- line-height: 1.7;
- margin: 0;
- flex: 1;
- overflow: hidden;
- display: -webkit-box;
- -webkit-line-clamp: 3;
- -webkit-box-orient: vertical;
-}
-.item-meta {
- display: flex;
- gap: 10px;
- align-items: center;
- margin-top: auto;
- padding-top: 10px;
- border-top: 1px dashed var(--border);
-}
-/* 布局变体:传统行列表(themeParams listLayout=row,见 list.html classappend) */
-.list-rows .article-list { display: block; }
-.list-rows .article-list li { display: block; margin-bottom: 16px; }
-.list-rows .item-summary { -webkit-line-clamp: 2; flex: none; }
-.list-rows .item-meta { border-top: none; padding-top: 0; margin-top: 6px; }
-
-/* ===== 分页:胶囊页码 ===== */
-.pagination {
- display: flex;
- gap: 8px;
- justify-content: center;
- flex-wrap: wrap;
- padding: 28px 0 4px;
-}
-.pagination a {
- min-width: 36px;
- text-align: center;
- padding: 6px 12px;
- border: 1px solid var(--border);
- border-radius: var(--radius-pill);
- background: var(--card-bg);
- font-size: 14px;
- transition: color .15s ease, border-color .15s ease, background .15s ease;
-}
-.pagination a:hover { color: var(--primary-dark); border-color: var(--primary); }
-.pagination a.active { background: var(--primary); color: #fff; border-color: var(--primary); }
-
-/* ===== 详情/单页:整卡承载,正文舒适行距 ===== */
-.detail-main {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 28px 16px 56px;
-}
-.detail-main .article {
- background: var(--card-bg);
- border-radius: var(--radius);
- box-shadow: var(--shadow-soft);
- padding: 36px 40px;
-}
-.article-title {
- margin: 4px 0 14px;
- font-size: 26px;
- font-weight: 600;
- letter-spacing: .02em;
- text-align: center;
-}
-.article-meta {
- display: flex;
- gap: 18px;
- justify-content: center;
- flex-wrap: wrap;
- color: var(--text-light);
- font-size: 13px;
- padding-bottom: 18px;
- border-bottom: 1px solid var(--border);
-}
-.article-content { line-height: 1.9; font-size: 16px; padding-top: 22px; word-break: break-word; }
-.article-content img { height: auto; border-radius: var(--radius-sm); }
-.article-content table { border-collapse: collapse; width: 100%; }
-.article-content table td, .article-content table th { border: 1px solid var(--border); padding: 6px 10px; }
-.article-sibling { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 20px; font-size: 14px; }
-.article-sibling a {
- flex: 1 1 320px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- background: var(--card-bg);
- border-radius: var(--radius);
- box-shadow: var(--shadow-soft);
- padding: 14px 18px;
- transition: transform .18s ease, box-shadow .18s ease, color .15s ease;
-}
-.article-sibling a:hover {
- color: var(--primary-dark);
- transform: translateY(-2px);
- box-shadow: var(--shadow-hover);
-}
-
-/* ===== 页脚:浅樱粉底 + 圆点分隔条(三态渲染逻辑不动) ===== */
-.site-footer {
- margin-top: 40px;
- background: var(--primary-light);
- color: var(--text);
- border-top: 1px solid var(--border);
-}
-.site-footer::before {
- content: "";
- display: block;
- height: 8px;
- width: min(var(--max-width), calc(100% - 32px));
- margin: 18px auto 0;
- background-image: radial-gradient(circle, var(--primary) 1.6px, transparent 2.2px);
- background-size: 16px 8px;
- background-repeat: repeat-x;
- opacity: .4;
-}
-.footer-links {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 18px 16px 0;
- display: flex;
- flex-direction: column;
- gap: 10px;
-}
-.links-group { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center; font-size: 13px; }
-.group-name { font-weight: 600; margin-right: 4px; color: var(--primary-dark); }
-.links-group a {
- padding: 3px 10px;
- border-radius: var(--radius-pill);
- transition: background .15s ease, color .15s ease;
-}
-.links-group a:hover { background: rgba(255, 255, 255, .75); color: var(--primary-dark); }
-.footer-info {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 14px 16px 24px;
- text-align: center;
- font-size: 13px;
- color: var(--text-light);
-}
-.footer-info p { margin: 4px 0; }
-
-/* B4 友链 Logo:与名称并排小图(高度 ~20px,垂直居中;过宽截断不撑破页脚) */
-.links-group a .link-logo {
- height: 20px;
- width: auto;
- max-width: 64px;
- object-fit: contain;
- vertical-align: middle;
- margin-right: 4px;
- border-radius: 4px;
-}
-
-/* ===== 平板(≤992px):网格降为两列,隐藏品牌行圆点装饰 ===== */
-@media (max-width: 992px) {
- .home-main { grid-template-columns: repeat(2, minmax(0, 1fr)); }
- .article-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
- .brand-row::before, .brand-row::after { display: none; }
-}
-
-/* ===== 移动端(≤768px):取消吸顶,网格单列,导航横向滑动 ===== */
-@media (max-width: 768px) {
- .site-header { position: static; }
- .top-bar { padding: 8px 14px; justify-content: flex-start; flex-wrap: wrap; }
- .top-bar .site-colleges { margin-right: 0; }
- .site-search { flex: 1; }
- .site-search input { flex: 1; width: auto; min-width: 0; }
- .brand-row { padding: 14px 16px 10px; }
- .site-logo { height: 40px; }
- .site-name { font-size: 22px; }
- .site-nav ul {
- justify-content: flex-start;
- flex-wrap: nowrap;
- overflow-x: auto;
- -webkit-overflow-scrolling: touch;
- }
- .banner-slides { height: 200px; }
- .home-main { grid-template-columns: minmax(0, 1fr); padding: 18px 14px 40px; }
- .article-list { grid-template-columns: minmax(0, 1fr); }
- .detail-main .article { padding: 22px 16px; }
- .article-title { font-size: 21px; }
- /* 触屏无 hover:子菜单静态平铺(缩进列表),不做浮层 */
- .site-nav ul.sub-nav {
- display: block;
- position: static;
- border: none;
- box-shadow: none;
- background: transparent;
- min-width: 0;
- padding: 0 0 6px;
- }
- .site-nav .sub-nav li a { margin: 0; padding: 8px 16px 8px 34px; border-radius: 0; color: var(--text-light); }
- .site-nav .sub-nav li a:hover { background: var(--primary-light); color: var(--primary-dark); }
-}
-
-
-/* ===== 左侧栏目导航(docs/11):有二级节点的模块,栏目/文章页左侧展示兄弟目录 ===== */
-.list-main.has-sidenav, .detail-main.has-sidenav { display: flex; align-items: flex-start; gap: 24px; }
-.has-sidenav .list-body { flex: 1; min-width: 0; }
-.side-nav { flex: none; width: 220px; background: var(--card-bg, #fff); border: 1px solid var(--border); overflow: hidden; }
-.side-nav-head { background: var(--primary); color: #fff; font-size: 20px; font-weight: 700; text-align: center; padding: 18px 12px; letter-spacing: 2px; }
-.side-nav-list { list-style: none; margin: 0; padding: 0; }
-.side-nav-item + .side-nav-item { border-top: 1px dashed var(--border); }
-.side-nav-item a { display: block; padding: 12px 16px; color: var(--text); text-decoration: none; font-size: 15px; transition: background .15s ease, color .15s ease; }
-.side-nav-item a:hover { color: var(--primary); background: var(--bg); }
-.side-nav-item.active a { background: var(--primary); color: #fff; font-weight: 600; text-decoration: none; }
-/* 顶导航二级下拉当前项高亮(docs/11 顺带) */
-.site-nav ul.sub-nav li.active a { color: var(--primary); }
-@media (max-width: 768px) {
- .list-main.has-sidenav, .detail-main.has-sidenav { flex-direction: column; gap: 12px; }
- .side-nav { width: 100%; }
- .side-nav-list { display: flex; overflow-x: auto; -webkit-overflow-scrolling: touch; }
- .side-nav-item { flex: none; }
- .side-nav-item + .side-nav-item { border-top: none; border-left: 1px dashed var(--border); }
- .side-nav-item a { white-space: nowrap; }
-}
-@media print {
- .side-nav { display: none; }
- .list-main.has-sidenav, .detail-main.has-sidenav { display: block; }
-}
diff --git a/src/main/resources/templates/themes/cherry-bloom/assets/favicon.png b/src/main/resources/templates/themes/cherry-bloom/assets/favicon.png
deleted file mode 100644
index e451454..0000000
Binary files a/src/main/resources/templates/themes/cherry-bloom/assets/favicon.png and /dev/null differ
diff --git a/src/main/resources/templates/themes/cherry-bloom/assets/favicon.svg b/src/main/resources/templates/themes/cherry-bloom/assets/favicon.svg
deleted file mode 100644
index 56ed83c..0000000
--- a/src/main/resources/templates/themes/cherry-bloom/assets/favicon.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
diff --git a/src/main/resources/templates/themes/cherry-bloom/assets/js/main.js b/src/main/resources/templates/themes/cherry-bloom/assets/js/main.js
deleted file mode 100644
index a077c85..0000000
--- a/src/main/resources/templates/themes/cherry-bloom/assets/js/main.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* cherry-bloom 皮肤包脚本:仅首页轮播自动播放与圆点切换,无任何外部依赖 */
-(function () {
- var slides = document.querySelectorAll('.banner-slide');
- var dots = document.querySelectorAll('.banner-dots button');
- if (!slides.length) {
- return;
- }
- var current = 0;
- var timer = null;
-
- function show(index) {
- slides[current].classList.remove('active');
- if (dots[current]) {
- dots[current].classList.remove('active');
- }
- current = (index + slides.length) % slides.length;
- slides[current].classList.add('active');
- if (dots[current]) {
- dots[current].classList.add('active');
- }
- }
-
- function start() {
- if (slides.length > 1) {
- timer = window.setInterval(function () {
- show(current + 1);
- }, 5000);
- }
- }
-
- dots.forEach(function (dot, index) {
- dot.addEventListener('click', function () {
- window.clearInterval(timer);
- show(index);
- start();
- });
- });
-
- start();
-})();
diff --git a/src/main/resources/templates/themes/cherry-bloom/assets/screenshot.png b/src/main/resources/templates/themes/cherry-bloom/assets/screenshot.png
deleted file mode 100644
index 8f58dfb..0000000
Binary files a/src/main/resources/templates/themes/cherry-bloom/assets/screenshot.png and /dev/null differ
diff --git a/src/main/resources/templates/themes/cherry-bloom/detail.html b/src/main/resources/templates/themes/cherry-bloom/detail.html
deleted file mode 100644
index 8eab71f..0000000
--- a/src/main/resources/templates/themes/cherry-bloom/detail.html
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- 文章标题
-
-
- 作者
- 来源
- 浏览量
-
-
- 正文
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/cherry-bloom/fragments/footer.html b/src/main/resources/templates/themes/cherry-bloom/fragments/footer.html
deleted file mode 100644
index 1f3f83d..0000000
--- a/src/main/resources/templates/themes/cherry-bloom/fragments/footer.html
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/cherry-bloom/fragments/header.html b/src/main/resources/templates/themes/cherry-bloom/fragments/header.html
deleted file mode 100644
index 903691c..0000000
--- a/src/main/resources/templates/themes/cherry-bloom/fragments/header.html
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/cherry-bloom/home.html b/src/main/resources/templates/themes/cherry-bloom/home.html
deleted file mode 100644
index 8d4f072..0000000
--- a/src/main/resources/templates/themes/cherry-bloom/home.html
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 头条推荐
-
- -
- 置顶
- 文章标题
-
-
-
-
-
-
-
-
-
- -
- 文章标题
-
-
-
- 暂无内容
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/cherry-bloom/list.html b/src/main/resources/templates/themes/cherry-bloom/list.html
deleted file mode 100644
index 14c47c4..0000000
--- a/src/main/resources/templates/themes/cherry-bloom/list.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
栏目名
-
搜索词
-
-
- -
- 文章标题
-
摘要
-
-
- 置顶
-
-
-
-
暂无内容
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/cherry-bloom/single.html b/src/main/resources/templates/themes/cherry-bloom/single.html
deleted file mode 100644
index 65292dc..0000000
--- a/src/main/resources/templates/themes/cherry-bloom/single.html
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- 栏目名
-
- 单页内容
- 暂无内容
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/cherry-bloom/theme.json b/src/main/resources/templates/themes/cherry-bloom/theme.json
deleted file mode 100644
index 5d24a11..0000000
--- a/src/main/resources/templates/themes/cherry-bloom/theme.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "specVersion": 1,
- "name": "cherry-bloom",
- "title": "樱语粉韵",
- "version": "1.0.0",
- "author": "yunhai",
- "description": "温柔樱粉风门户:细线顶栏+居中 logo 吸顶、樱花粉品牌色、大圆角 16px 卡片网格列表、花瓣式圆点装饰与暖白留白,甜美亲和,适合幼儿园与小学门户。",
- "screenshot": "assets/screenshot.png",
- "bannerSize": "1920x560",
- "params": [
- { "key": "primary", "cssVar": "--primary", "label": "主色", "type": "color", "default": "#DB5A8B" },
- { "key": "primaryDark", "cssVar": "--primary-dark", "label": "主色加深(强调色)", "type": "color", "default": "#B23A68" },
- { "key": "primaryLight", "cssVar": "--primary-light", "label": "主色提亮", "type": "color", "default": "#FDECF3" },
- { "key": "bg", "cssVar": "--bg", "label": "页面底色", "type": "color", "default": "#FFFAFB" },
- { "key": "cardBg", "cssVar": "--card-bg", "label": "卡片底色", "type": "color", "default": "#FFFFFF" },
- { "key": "border", "cssVar": "--border", "label": "边框色", "type": "color", "default": "#F7DDE7" },
- { "key": "text", "cssVar": "--text", "label": "正文文字色", "type": "color", "default": "#43333B" },
- { "key": "textLight", "cssVar": "--text-light", "label": "次要文字色", "type": "color", "default": "#9C828C" },
- { "key": "listLayout", "label": "列表布局", "type": "select", "default": "grid",
- "options": [ { "value": "grid", "label": "卡片网格(一行 3 张)" }, { "value": "row", "label": "传统行列表" } ] }
- ]
-}
diff --git a/src/main/resources/templates/themes/common/fragments/home-blocks.html b/src/main/resources/templates/themes/common/fragments/home-blocks.html
index 952b001..54dd804 100644
--- a/src/main/resources/templates/themes/common/fragments/home-blocks.html
+++ b/src/main/resources/templates/themes/common/fragments/home-blocks.html
@@ -8,56 +8,76 @@
-->
@@ -92,7 +112,7 @@
更多 >
-
+
@@ -121,7 +141,9 @@
-
+
+
+
@@ -138,7 +160,9 @@
-
+
+
+
@@ -158,7 +182,9 @@
置顶
-
+
+
+
@@ -176,7 +202,10 @@
-
+
+
+
+
@@ -193,7 +222,9 @@
-
+
+
+
diff --git a/src/main/resources/templates/themes/mint-breeze/assets/css/main.css b/src/main/resources/templates/themes/mint-breeze/assets/css/main.css
index e65d638..73fc718 100644
--- a/src/main/resources/templates/themes/mint-breeze/assets/css/main.css
+++ b/src/main/resources/templates/themes/mint-breeze/assets/css/main.css
@@ -230,6 +230,7 @@ time, .item-meta { color: var(--text-light); font-size: 13px; }
/* ===== 首页轮播:容器内圆角卡片(非通栏),几何圆点指示器 ===== */
.banner {
position: relative;
+ grid-column: 1 / -1; /* .home-main 是三列网格,轮播必须跨满整行,否则被塞进首列变窄条 */
width: min(var(--max-width), calc(100% - 32px));
margin: 24px auto 0;
border-radius: var(--radius);
diff --git a/src/main/resources/templates/themes/scholar-blue/assets/css/main.css b/src/main/resources/templates/themes/scholar-blue/assets/css/main.css
index 7822fa6..cc02a36 100644
--- a/src/main/resources/templates/themes/scholar-blue/assets/css/main.css
+++ b/src/main/resources/templates/themes/scholar-blue/assets/css/main.css
@@ -31,6 +31,18 @@
--sp-radius-lg: 10px;
--sp-speed: .28s;
--sp-font: "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Helvetica Neue", Arial, sans-serif;
+
+ /* 皮肤契约别名:站点配了 home_layout 时首页走 common/fragments/home-blocks 骨架,
+ 该骨架只认契约变量(--primary/--text/…)。不别名过去,换肤就只换了页头页脚、正文区块仍是骨架内置色。 */
+ --primary: var(--sp-primary);
+ --primary-dark: var(--sp-primary-dark);
+ --primary-light: var(--sp-primary-light);
+ --text: var(--sp-text);
+ --text-light: var(--sp-text-light);
+ --bg: var(--sp-bg);
+ --card-bg: var(--sp-card-bg);
+ --border: var(--sp-border);
+ --radius: var(--sp-radius-lg);
}
/* ---------------------------------------------------------------------
diff --git a/src/main/resources/templates/themes/violet-iris/README.md b/src/main/resources/templates/themes/violet-iris/README.md
deleted file mode 100644
index 747398a..0000000
--- a/src/main/resources/templates/themes/violet-iris/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# violet-iris 皮肤包
-
-由 mint-breeze 派生的雅致鸢尾紫皮肤(docs/10 契约 §5 工作流)。**升级随版本发布,不在站点间复制目录**。
-
-
-## 风格定位
-
-沉静、书卷气,适合高校与教科研机构门户:鸢尾紫品牌色、圆角 12px、卡片纯白+淡紫柔和阴影、细线顶栏+居中 logo(桌面吸顶,移动端取消)、列表卡片网格(一行 3 张)、几何圆点装饰与大留白;无纹理、无通栏大图、无复杂动效。
-
-## 数据契约(模板可取用的 model 属性全集,契约 §3)
-
-| 页面 | 属性 |
-| --- | --- |
-| 全部 | `site`(快照:config/分类树/轮播/友链组/院系子站)、`url`(PortalUrlHelper:home/category/article/asset/search/siteHome)、`themeBase`(=`themes/violet-iris`)、`navCategories`、`pageTitle`、`seoDescription`、`canonical`、`themeParams`(微调参数,仅 theme.json 声明过的 key)、`themeVarsCss`(服务端预构建 `:root{}` 覆盖串,无参数为空) |
-| home | `banners`(时间窗内 home 位)、`topArticles`(置顶+最新 6)、`categoryBlocks`(LIST 型根栏目块,各 top 8) |
-| list / search | `listData`(分页)、`category`(list)、`q` + `searchMode`(search) |
-| detail | `article`、`prevArticle`、`nextArticle`、`currentCategoryId` |
-| single | `category`(含 `content`)、`currentCategoryId` |
-
-原则:皮肤不得假设"首页一定有轮播",对空集合优雅降级。
-
-## 轮播图尺寸约定(bannerSize)
-
-1920x560(管理端上传端按此引导裁剪,D2 决策点)。
-
-## 可调参数
-
-见 `theme.json` 的 `params`:
-
-- **color**(进 CSS 变量):`primary` 主色 / `primaryDark` 主色加深(即强调色,用于品牌文字与悬停加深)/ `primaryLight` 主色提亮 / `bg` 页面底色 / `cardBg` 卡片底色 / `border` 边框色 / `text` 正文文字 / `textLight` 次要文字。
-- **select**:`listLayout` = `grid`(默认,卡片网格一行 3 张)或 `row`(传统行列表)。
-
-换色建议:主色系三值同步调整(primary / primaryDark / primaryLight),bg 与 border、primaryLight 保持同族浅色调,避免底色与卡片对比失衡。
-
-优先级:`custom_css` > `themeVarsCss` > `main.css`。
diff --git a/src/main/resources/templates/themes/violet-iris/assets/css/main.css b/src/main/resources/templates/themes/violet-iris/assets/css/main.css
deleted file mode 100644
index 8fffbe5..0000000
--- a/src/main/resources/templates/themes/violet-iris/assets/css/main.css
+++ /dev/null
@@ -1,616 +0,0 @@
-/* ============================================================
- * violet-iris 皮肤包样式(mint-breeze 派生,docs/10 皮肤包契约 §5)
- * 雅致鸢尾紫风:鸢尾紫品牌色 + 圆角 12px + 柔和紫阴影 + 卡片网格列表
- * + 几何圆点装饰与淡薰衣草留白;无纹理、无通栏大图、无复杂动效。
- * 轮播图设计尺寸约定:1920×560(管理端上传端按此引导裁剪)。
- * ============================================================ */
-:root {
- --primary: #6552D9;
- --primary-dark: #4A39B0;
- --primary-light: #EFECFC;
- --text: #332F45;
- --text-light: #847E9C;
- --bg: #F8F7FD;
- --card-bg: #FFFFFF;
- --border: #E4DFF6;
- --radius: 12px;
- --radius-sm: 8px;
- --radius-pill: 999px;
- --shadow-soft: 0 6px 18px rgba(74, 57, 176, .08);
- --shadow-hover: 0 12px 28px rgba(74, 57, 176, .14);
- --max-width: 1200px;
-}
-
-* { box-sizing: border-box; }
-body {
- margin: 0;
- font-family: "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
- color: var(--text);
- background: var(--bg);
-}
-a { color: inherit; text-decoration: none; transition: color .15s ease; }
-a:hover { color: var(--primary); }
-img { max-width: 100%; }
-time, .item-meta { color: var(--text-light); font-size: 13px; }
-.empty { color: var(--text-light); text-align: center; padding: 32px 0; }
-
-/* ===== 头部:细线顶栏 + 居中品牌行 + 白底导航(桌面吸顶) ===== */
-.site-header {
- position: sticky;
- top: 0;
- z-index: 90;
- background: var(--card-bg);
- box-shadow: var(--shadow-soft);
-}
-/* 细线顶栏:院系切换在左、站内搜索在右;院系未配置时搜索仍靠右 */
-.top-bar {
- display: flex;
- align-items: center;
- justify-content: flex-end;
- gap: 16px;
- padding: 7px max(16px, calc((100% - var(--max-width)) / 2 + 16px));
- border-bottom: 1px solid var(--border);
- font-size: 13px;
-}
-.top-bar .site-colleges { margin-right: auto; }
-/* 居中品牌行:两侧几何圆点装饰(纯 CSS,无纹理) */
-.brand-row {
- position: relative;
- display: flex;
- justify-content: center;
- padding: 18px 16px 14px;
-}
-.brand-row::before, .brand-row::after {
- content: "";
- position: absolute;
- top: 50%;
- transform: translateY(-50%);
- width: 46px;
- height: 10px;
- opacity: .45;
- background-image:
- radial-gradient(circle, var(--primary) 2.2px, transparent 2.8px),
- radial-gradient(circle, var(--primary) 1.6px, transparent 2.2px),
- radial-gradient(circle, var(--primary) 1.1px, transparent 1.7px);
- background-repeat: no-repeat;
- background-position: left center, center center, right center;
-}
-.brand-row::before { left: 6%; }
-.brand-row::after { right: 6%; }
-.site-brand { display: flex; align-items: center; gap: 14px; }
-.site-logo { height: 52px; }
-.site-name {
- font-size: 28px;
- font-weight: 600;
- letter-spacing: .02em;
- color: var(--primary-dark);
-}
-.site-name:hover { color: var(--primary); }
-.site-search { display: flex; align-items: center; }
-.site-search input {
- border: 1px solid var(--border);
- border-right: none;
- border-radius: var(--radius-pill) 0 0 var(--radius-pill);
- padding: 7px 16px;
- width: 220px;
- outline: none;
- background: var(--card-bg);
- color: var(--text);
- transition: border-color .15s ease, box-shadow .15s ease;
-}
-.site-search input:focus {
- border-color: var(--primary);
- box-shadow: 0 0 0 3px var(--primary-light);
-}
-.site-search button {
- border: none;
- background: var(--primary);
- color: #fff;
- padding: 7px 20px;
- border-radius: 0 var(--radius-pill) var(--radius-pill) 0;
- cursor: pointer;
- transition: background .15s ease;
-}
-.site-search button:hover { background: var(--primary-dark); }
-
-/* ===== 专业院系下拉(院系子站切换):胶囊开关 + 圆角白卡面板 ===== */
-.site-colleges { position: relative; }
-.site-colleges .colleges-toggle {
- display: inline-flex;
- align-items: center;
- gap: 6px;
- border: 1px solid var(--border);
- border-radius: var(--radius-pill);
- padding: 5px 14px;
- cursor: pointer;
- color: var(--primary-dark);
- font-weight: 600;
- white-space: nowrap;
- transition: border-color .15s ease, background .15s ease;
-}
-.site-colleges:hover .colleges-toggle {
- border-color: var(--primary);
- background: var(--primary-light);
-}
-.site-colleges .colleges-arrow { font-style: normal; font-size: 12px; color: var(--primary); }
-.site-colleges .colleges-menu {
- display: none;
- position: absolute;
- top: 100%;
- left: 0;
- min-width: 200px;
- max-height: 420px;
- overflow-y: auto;
- margin: 0;
- padding: 8px 0;
- list-style: none;
- background: var(--card-bg);
- border: 1px solid var(--border);
- border-radius: var(--radius);
- box-shadow: var(--shadow-hover);
- z-index: 110;
-}
-.site-colleges:hover .colleges-menu { display: block; }
-.site-colleges .colleges-menu li a {
- display: block;
- margin: 0 8px;
- padding: 9px 12px;
- border-radius: var(--radius-sm);
- color: var(--text);
- white-space: nowrap;
-}
-.site-colleges .colleges-menu li a:hover { background: var(--primary-light); color: var(--primary-dark); }
-.site-colleges .colleges-menu li.active a { color: var(--primary); font-weight: 600; }
-
-/* ===== 主导航:白底 + 柔和文字层级,当前项圆点标记 ===== */
-.site-nav { background: var(--card-bg); border-top: 1px solid var(--border); }
-.site-nav ul {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 0 16px;
- list-style: none;
- display: flex;
- justify-content: center;
- flex-wrap: wrap;
-}
-.site-nav li a {
- position: relative;
- display: block;
- padding: 13px 20px;
- color: var(--text);
- font-weight: 500;
-}
-.site-nav li a:hover { color: var(--primary); }
-.site-nav li.active a { color: var(--primary); font-weight: 600; }
-/* 几何圆点:当前栏目下方的小圆点 */
-.site-nav li.active > a::before {
- content: "";
- position: absolute;
- left: 50%;
- bottom: 5px;
- width: 5px;
- height: 5px;
- transform: translateX(-50%);
- border-radius: 50%;
- background: var(--primary);
-}
-
-/* ===== 二级下拉导航:圆角白卡面板 ===== */
-.site-nav > ul > li { position: relative; }
-.site-nav li.has-sub > a::after { content: " ▾"; font-size: 12px; opacity: .7; }
-.site-nav ul.sub-nav {
- display: none;
- position: absolute;
- top: 100%;
- left: 0;
- min-width: 168px;
- max-width: none;
- margin: 0;
- padding: 8px 0;
- list-style: none;
- background: var(--card-bg);
- border: 1px solid var(--border);
- border-radius: var(--radius);
- box-shadow: var(--shadow-hover);
- z-index: 100;
-}
-.site-nav li:hover > .sub-nav { display: block; }
-.site-nav .sub-nav li a {
- margin: 0 8px;
- padding: 9px 12px;
- border-radius: var(--radius-sm);
- color: var(--text);
- font-weight: 400;
- white-space: nowrap;
- background: none;
-}
-.site-nav .sub-nav li a:hover { background: var(--primary-light); color: var(--primary-dark); }
-.site-nav .sub-nav li.active a { color: var(--primary); font-weight: 600; }
-
-/* ===== 首页轮播:容器内圆角卡片(非通栏),几何圆点指示器 ===== */
-.banner {
- position: relative;
- width: min(var(--max-width), calc(100% - 32px));
- margin: 24px auto 0;
- border-radius: var(--radius);
- overflow: hidden;
- box-shadow: var(--shadow-soft);
-}
-.banner-slides { position: relative; height: 400px; }
-.banner-slide { display: none; position: absolute; inset: 0; }
-.banner-slide.active { display: block; }
-.banner-slide img { width: 100%; height: 100%; object-fit: cover; }
-.banner-title {
- position: absolute;
- left: 0; right: 0; bottom: 0;
- padding: 14px 20px;
- color: #fff;
- font-weight: 500;
- background: linear-gradient(transparent, rgba(20, 63, 61, .62));
-}
-.banner-dots {
- position: absolute;
- bottom: 14px; right: 20px;
- display: flex; gap: 8px;
-}
-.banner-dots button {
- width: 9px; height: 9px;
- border-radius: 50%;
- border: none;
- background: rgba(255, 255, 255, .55);
- cursor: pointer;
- transition: background .15s ease, transform .15s ease;
-}
-.banner-dots button.active { background: #fff; transform: scale(1.25); }
-
-/* ===== 首页区块:卡片网格(头条通栏 + 栏目块一行 3 张) ===== */
-.home-main {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 28px 16px 56px;
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 24px;
-}
-.top-strip, .category-block {
- background: var(--card-bg);
- border-radius: var(--radius);
- box-shadow: var(--shadow-soft);
- padding: 24px;
-}
-.top-strip { grid-column: 1 / -1; }
-/* 栏目标题:几何圆点标记(环形点),标题中等粗细、层级柔和 */
-.section-title, .block-head h2 {
- margin: 0 0 14px;
- font-size: 19px;
- font-weight: 600;
- letter-spacing: .02em;
- display: flex;
- align-items: center;
- gap: 10px;
-}
-.section-title::before, .block-head h2::before {
- content: "";
- flex: none;
- width: 9px;
- height: 9px;
- border-radius: 50%;
- background: var(--primary);
- box-shadow: 0 0 0 3.5px var(--primary-light);
-}
-.block-head { display: flex; align-items: center; justify-content: space-between; }
-.more {
- flex: none;
- font-size: 13px;
- color: var(--text-light);
- padding: 4px 12px;
- border: 1px solid var(--border);
- border-radius: var(--radius-pill);
- transition: color .15s ease, border-color .15s ease, background .15s ease;
-}
-.more:hover {
- color: var(--primary-dark);
- border-color: var(--primary);
- background: var(--primary-light);
-}
-.top-strip ul, .block-list { list-style: none; margin: 0; padding: 0; }
-.top-strip li, .block-list li {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 12px;
- padding: 10px 0;
- border-bottom: 1px dashed var(--border);
-}
-.top-strip li:last-child, .block-list li:last-child { border-bottom: none; }
-.top-strip li a, .block-list li a {
- flex: 1;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.top-badge {
- flex: none;
- color: var(--primary-dark);
- background: var(--primary-light);
- font-size: 12px;
- font-weight: 500;
- padding: 2px 10px;
- border-radius: var(--radius-pill);
-}
-
-/* ===== 列表页:卡片网格(默认一行 3 张;listLayout=row 切换行列表) ===== */
-.list-main {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 28px 16px 56px;
-}
-.breadcrumb { color: var(--text-light); font-size: 13px; margin-bottom: 14px; }
-.breadcrumb a { margin-right: 8px; }
-.breadcrumb span { margin-left: 8px; }
-.page-title {
- font-size: 24px;
- font-weight: 600;
- letter-spacing: .02em;
- margin: 0 0 22px;
- display: flex;
- align-items: center;
- gap: 10px;
-}
-.page-title::before {
- content: "";
- flex: none;
- width: 9px;
- height: 9px;
- border-radius: 50%;
- background: var(--primary);
- box-shadow: 0 0 0 3.5px var(--primary-light);
-}
-.article-list {
- list-style: none;
- margin: 0;
- padding: 0;
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 20px;
-}
-.article-list li {
- background: var(--card-bg);
- border-radius: var(--radius);
- box-shadow: var(--shadow-soft);
- padding: 22px 20px;
- display: flex;
- flex-direction: column;
- gap: 10px;
- transition: transform .18s ease, box-shadow .18s ease;
-}
-.article-list li:hover { transform: translateY(-3px); box-shadow: var(--shadow-hover); }
-.item-title {
- font-size: 16px;
- font-weight: 600;
- line-height: 1.55;
- overflow: hidden;
- display: -webkit-box;
- -webkit-line-clamp: 2;
- -webkit-box-orient: vertical;
-}
-.article-list li:hover .item-title { color: var(--primary); }
-.item-summary {
- color: var(--text-light);
- font-size: 13.5px;
- line-height: 1.7;
- margin: 0;
- flex: 1;
- overflow: hidden;
- display: -webkit-box;
- -webkit-line-clamp: 3;
- -webkit-box-orient: vertical;
-}
-.item-meta {
- display: flex;
- gap: 10px;
- align-items: center;
- margin-top: auto;
- padding-top: 10px;
- border-top: 1px dashed var(--border);
-}
-/* 布局变体:传统行列表(themeParams listLayout=row,见 list.html classappend) */
-.list-rows .article-list { display: block; }
-.list-rows .article-list li { display: block; margin-bottom: 16px; }
-.list-rows .item-summary { -webkit-line-clamp: 2; flex: none; }
-.list-rows .item-meta { border-top: none; padding-top: 0; margin-top: 6px; }
-
-/* ===== 分页:胶囊页码 ===== */
-.pagination {
- display: flex;
- gap: 8px;
- justify-content: center;
- flex-wrap: wrap;
- padding: 28px 0 4px;
-}
-.pagination a {
- min-width: 36px;
- text-align: center;
- padding: 6px 12px;
- border: 1px solid var(--border);
- border-radius: var(--radius-pill);
- background: var(--card-bg);
- font-size: 14px;
- transition: color .15s ease, border-color .15s ease, background .15s ease;
-}
-.pagination a:hover { color: var(--primary-dark); border-color: var(--primary); }
-.pagination a.active { background: var(--primary); color: #fff; border-color: var(--primary); }
-
-/* ===== 详情/单页:整卡承载,正文舒适行距 ===== */
-.detail-main {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 28px 16px 56px;
-}
-.detail-main .article {
- background: var(--card-bg);
- border-radius: var(--radius);
- box-shadow: var(--shadow-soft);
- padding: 36px 40px;
-}
-.article-title {
- margin: 4px 0 14px;
- font-size: 26px;
- font-weight: 600;
- letter-spacing: .02em;
- text-align: center;
-}
-.article-meta {
- display: flex;
- gap: 18px;
- justify-content: center;
- flex-wrap: wrap;
- color: var(--text-light);
- font-size: 13px;
- padding-bottom: 18px;
- border-bottom: 1px solid var(--border);
-}
-.article-content { line-height: 1.9; font-size: 16px; padding-top: 22px; word-break: break-word; }
-.article-content img { height: auto; border-radius: var(--radius-sm); }
-.article-content table { border-collapse: collapse; width: 100%; }
-.article-content table td, .article-content table th { border: 1px solid var(--border); padding: 6px 10px; }
-.article-sibling { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 20px; font-size: 14px; }
-.article-sibling a {
- flex: 1 1 320px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- background: var(--card-bg);
- border-radius: var(--radius);
- box-shadow: var(--shadow-soft);
- padding: 14px 18px;
- transition: transform .18s ease, box-shadow .18s ease, color .15s ease;
-}
-.article-sibling a:hover {
- color: var(--primary-dark);
- transform: translateY(-2px);
- box-shadow: var(--shadow-hover);
-}
-
-/* ===== 页脚:浅鸢尾底 + 圆点分隔条(三态渲染逻辑不动) ===== */
-.site-footer {
- margin-top: 40px;
- background: var(--primary-light);
- color: var(--text);
- border-top: 1px solid var(--border);
-}
-.site-footer::before {
- content: "";
- display: block;
- height: 8px;
- width: min(var(--max-width), calc(100% - 32px));
- margin: 18px auto 0;
- background-image: radial-gradient(circle, var(--primary) 1.6px, transparent 2.2px);
- background-size: 16px 8px;
- background-repeat: repeat-x;
- opacity: .4;
-}
-.footer-links {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 18px 16px 0;
- display: flex;
- flex-direction: column;
- gap: 10px;
-}
-.links-group { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center; font-size: 13px; }
-.group-name { font-weight: 600; margin-right: 4px; color: var(--primary-dark); }
-.links-group a {
- padding: 3px 10px;
- border-radius: var(--radius-pill);
- transition: background .15s ease, color .15s ease;
-}
-.links-group a:hover { background: rgba(255, 255, 255, .75); color: var(--primary-dark); }
-.footer-info {
- max-width: var(--max-width);
- margin: 0 auto;
- padding: 14px 16px 24px;
- text-align: center;
- font-size: 13px;
- color: var(--text-light);
-}
-.footer-info p { margin: 4px 0; }
-
-/* B4 友链 Logo:与名称并排小图(高度 ~20px,垂直居中;过宽截断不撑破页脚) */
-.links-group a .link-logo {
- height: 20px;
- width: auto;
- max-width: 64px;
- object-fit: contain;
- vertical-align: middle;
- margin-right: 4px;
- border-radius: 4px;
-}
-
-/* ===== 平板(≤992px):网格降为两列,隐藏品牌行圆点装饰 ===== */
-@media (max-width: 992px) {
- .home-main { grid-template-columns: repeat(2, minmax(0, 1fr)); }
- .article-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
- .brand-row::before, .brand-row::after { display: none; }
-}
-
-/* ===== 移动端(≤768px):取消吸顶,网格单列,导航横向滑动 ===== */
-@media (max-width: 768px) {
- .site-header { position: static; }
- .top-bar { padding: 8px 14px; justify-content: flex-start; flex-wrap: wrap; }
- .top-bar .site-colleges { margin-right: 0; }
- .site-search { flex: 1; }
- .site-search input { flex: 1; width: auto; min-width: 0; }
- .brand-row { padding: 14px 16px 10px; }
- .site-logo { height: 40px; }
- .site-name { font-size: 22px; }
- .site-nav ul {
- justify-content: flex-start;
- flex-wrap: nowrap;
- overflow-x: auto;
- -webkit-overflow-scrolling: touch;
- }
- .banner-slides { height: 200px; }
- .home-main { grid-template-columns: minmax(0, 1fr); padding: 18px 14px 40px; }
- .article-list { grid-template-columns: minmax(0, 1fr); }
- .detail-main .article { padding: 22px 16px; }
- .article-title { font-size: 21px; }
- /* 触屏无 hover:子菜单静态平铺(缩进列表),不做浮层 */
- .site-nav ul.sub-nav {
- display: block;
- position: static;
- border: none;
- box-shadow: none;
- background: transparent;
- min-width: 0;
- padding: 0 0 6px;
- }
- .site-nav .sub-nav li a { margin: 0; padding: 8px 16px 8px 34px; border-radius: 0; color: var(--text-light); }
- .site-nav .sub-nav li a:hover { background: var(--primary-light); color: var(--primary-dark); }
-}
-
-
-/* ===== 左侧栏目导航(docs/11):有二级节点的模块,栏目/文章页左侧展示兄弟目录 ===== */
-.list-main.has-sidenav, .detail-main.has-sidenav { display: flex; align-items: flex-start; gap: 24px; }
-.has-sidenav .list-body { flex: 1; min-width: 0; }
-.side-nav { flex: none; width: 220px; background: var(--card-bg, #fff); border: 1px solid var(--border); overflow: hidden; }
-.side-nav-head { background: var(--primary); color: #fff; font-size: 20px; font-weight: 700; text-align: center; padding: 18px 12px; letter-spacing: 2px; }
-.side-nav-list { list-style: none; margin: 0; padding: 0; }
-.side-nav-item + .side-nav-item { border-top: 1px dashed var(--border); }
-.side-nav-item a { display: block; padding: 12px 16px; color: var(--text); text-decoration: none; font-size: 15px; transition: background .15s ease, color .15s ease; }
-.side-nav-item a:hover { color: var(--primary); background: var(--bg); }
-.side-nav-item.active a { background: var(--primary); color: #fff; font-weight: 600; text-decoration: none; }
-/* 顶导航二级下拉当前项高亮(docs/11 顺带) */
-.site-nav ul.sub-nav li.active a { color: var(--primary); }
-@media (max-width: 768px) {
- .list-main.has-sidenav, .detail-main.has-sidenav { flex-direction: column; gap: 12px; }
- .side-nav { width: 100%; }
- .side-nav-list { display: flex; overflow-x: auto; -webkit-overflow-scrolling: touch; }
- .side-nav-item { flex: none; }
- .side-nav-item + .side-nav-item { border-top: none; border-left: 1px dashed var(--border); }
- .side-nav-item a { white-space: nowrap; }
-}
-@media print {
- .side-nav { display: none; }
- .list-main.has-sidenav, .detail-main.has-sidenav { display: block; }
-}
diff --git a/src/main/resources/templates/themes/violet-iris/assets/favicon.png b/src/main/resources/templates/themes/violet-iris/assets/favicon.png
deleted file mode 100644
index 5fa2755..0000000
Binary files a/src/main/resources/templates/themes/violet-iris/assets/favicon.png and /dev/null differ
diff --git a/src/main/resources/templates/themes/violet-iris/assets/favicon.svg b/src/main/resources/templates/themes/violet-iris/assets/favicon.svg
deleted file mode 100644
index eed749f..0000000
--- a/src/main/resources/templates/themes/violet-iris/assets/favicon.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-
diff --git a/src/main/resources/templates/themes/violet-iris/assets/js/main.js b/src/main/resources/templates/themes/violet-iris/assets/js/main.js
deleted file mode 100644
index 8261c6b..0000000
--- a/src/main/resources/templates/themes/violet-iris/assets/js/main.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* violet-iris 皮肤包脚本:仅首页轮播自动播放与圆点切换,无任何外部依赖 */
-(function () {
- var slides = document.querySelectorAll('.banner-slide');
- var dots = document.querySelectorAll('.banner-dots button');
- if (!slides.length) {
- return;
- }
- var current = 0;
- var timer = null;
-
- function show(index) {
- slides[current].classList.remove('active');
- if (dots[current]) {
- dots[current].classList.remove('active');
- }
- current = (index + slides.length) % slides.length;
- slides[current].classList.add('active');
- if (dots[current]) {
- dots[current].classList.add('active');
- }
- }
-
- function start() {
- if (slides.length > 1) {
- timer = window.setInterval(function () {
- show(current + 1);
- }, 5000);
- }
- }
-
- dots.forEach(function (dot, index) {
- dot.addEventListener('click', function () {
- window.clearInterval(timer);
- show(index);
- start();
- });
- });
-
- start();
-})();
diff --git a/src/main/resources/templates/themes/violet-iris/assets/screenshot.png b/src/main/resources/templates/themes/violet-iris/assets/screenshot.png
deleted file mode 100644
index 908a26e..0000000
Binary files a/src/main/resources/templates/themes/violet-iris/assets/screenshot.png and /dev/null differ
diff --git a/src/main/resources/templates/themes/violet-iris/detail.html b/src/main/resources/templates/themes/violet-iris/detail.html
deleted file mode 100644
index 8eab71f..0000000
--- a/src/main/resources/templates/themes/violet-iris/detail.html
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- 文章标题
-
-
- 作者
- 来源
- 浏览量
-
-
- 正文
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/violet-iris/fragments/footer.html b/src/main/resources/templates/themes/violet-iris/fragments/footer.html
deleted file mode 100644
index 1f3f83d..0000000
--- a/src/main/resources/templates/themes/violet-iris/fragments/footer.html
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/violet-iris/fragments/header.html b/src/main/resources/templates/themes/violet-iris/fragments/header.html
deleted file mode 100644
index 462364e..0000000
--- a/src/main/resources/templates/themes/violet-iris/fragments/header.html
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/violet-iris/home.html b/src/main/resources/templates/themes/violet-iris/home.html
deleted file mode 100644
index 8d4f072..0000000
--- a/src/main/resources/templates/themes/violet-iris/home.html
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 头条推荐
-
- -
- 置顶
- 文章标题
-
-
-
-
-
-
-
-
-
- -
- 文章标题
-
-
-
- 暂无内容
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/violet-iris/list.html b/src/main/resources/templates/themes/violet-iris/list.html
deleted file mode 100644
index 14c47c4..0000000
--- a/src/main/resources/templates/themes/violet-iris/list.html
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
栏目名
-
搜索词
-
-
- -
- 文章标题
-
摘要
-
-
- 置顶
-
-
-
-
暂无内容
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/violet-iris/single.html b/src/main/resources/templates/themes/violet-iris/single.html
deleted file mode 100644
index 65292dc..0000000
--- a/src/main/resources/templates/themes/violet-iris/single.html
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- 栏目名
-
- 单页内容
- 暂无内容
-
-
-
-
-
-
-
diff --git a/src/main/resources/templates/themes/violet-iris/theme.json b/src/main/resources/templates/themes/violet-iris/theme.json
deleted file mode 100644
index 607917f..0000000
--- a/src/main/resources/templates/themes/violet-iris/theme.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "specVersion": 1,
- "name": "violet-iris",
- "title": "鸢尾紫韵",
- "version": "1.0.0",
- "author": "yunhai",
- "description": "雅致鸢尾紫门户:细线顶栏+居中 logo 吸顶、鸢尾紫品牌色、圆角 12px 卡片网格列表、几何圆点装饰与淡薰衣草留白,沉静书卷气,适合高校与教科研机构。",
- "screenshot": "assets/screenshot.png",
- "bannerSize": "1920x560",
- "params": [
- { "key": "primary", "cssVar": "--primary", "label": "主色", "type": "color", "default": "#6552D9" },
- { "key": "primaryDark", "cssVar": "--primary-dark", "label": "主色加深(强调色)", "type": "color", "default": "#4A39B0" },
- { "key": "primaryLight", "cssVar": "--primary-light", "label": "主色提亮", "type": "color", "default": "#EFECFC" },
- { "key": "bg", "cssVar": "--bg", "label": "页面底色", "type": "color", "default": "#F8F7FD" },
- { "key": "cardBg", "cssVar": "--card-bg", "label": "卡片底色", "type": "color", "default": "#FFFFFF" },
- { "key": "border", "cssVar": "--border", "label": "边框色", "type": "color", "default": "#E4DFF6" },
- { "key": "text", "cssVar": "--text", "label": "正文文字色", "type": "color", "default": "#332F45" },
- { "key": "textLight", "cssVar": "--text-light", "label": "次要文字色", "type": "color", "default": "#847E9C" },
- { "key": "listLayout", "label": "列表布局", "type": "select", "default": "grid",
- "options": [ { "value": "grid", "label": "卡片网格(一行 3 张)" }, { "value": "row", "label": "传统行列表" } ] }
- ]
-}
diff --git a/src/test/java/com/yunhai/cms/portal/PortalHomeLayoutIT.java b/src/test/java/com/yunhai/cms/portal/PortalHomeLayoutIT.java
index b55deec..fe46edf 100644
--- a/src/test/java/com/yunhai/cms/portal/PortalHomeLayoutIT.java
+++ b/src/test/java/com/yunhai/cms/portal/PortalHomeLayoutIT.java
@@ -35,12 +35,13 @@ class PortalHomeLayoutIT extends CmsIntegrationTestBase {
private Integer catNews;
private Integer catNotice;
+ private Integer siteId;
@BeforeEach
void seed() {
purgeTables();
CmsSite site = persistSite("layhome", 1, "布局测试门户");
- Integer siteId = site.getId();
+ siteId = site.getId();
catNews = persistCategory(siteId, 0, "校园时讯", CategoryTypeEnum.LIST).getId();
catNotice = persistCategory(siteId, 0, "通知公告", CategoryTypeEnum.LIST).getId();
persistCategory(siteId, 0, "学校概况", CategoryTypeEnum.SINGLE);
@@ -118,7 +119,7 @@ class PortalHomeLayoutIT extends CmsIntegrationTestBase {
assertThat(html).doesNotContain("headline-list").doesNotContain("category-block");
// ticker:置顶优先+发布时间倒序取 size=2 条(无置顶 → 最新两篇)
assertThat(html).contains("plb-ticker").contains("要闻速递");
- assertThat(count(html, "plb-ticker-item")).as("ticker 取 size=2 条").isEqualTo(2);
+ assertThat(count(html, " {
+ s.setTheme("academic-navy");
+ siteRepository.saveAndFlush(s);
+ });
+ clearCaches();
+
+ String html = body(mockMvc.perform(get("/portal/layhome/")).andExpect(status().isOk()).andReturn());
+
+ // 皮肤自有区块:an-* 结构类;news_grid/compact 不再落 plb 骨架
+ assertThat(html).contains("an-ticker").contains("an-split").contains("an-date-chip");
+ assertThat(html).as("已实现形态不得回落通用骨架").doesNotContain("plb-");
+ assertThat(html).contains("校园要闻").contains("通知公告").contains("要闻速递");
+ assertThat(count(html, " {
+ s.setTheme("campus-azure");
+ siteRepository.saveAndFlush(s);
+ });
+ clearCaches();
+
+ String html = body(mockMvc.perform(get("/portal/layhome/")).andExpect(status().isOk()).andReturn());
+ assertThat(html).contains("cz-header").contains("cz-footer").contains("校园时讯");
+ assertThat(html).as("无 home_layout 时不得出现布局骨架").doesNotContain("plb-section");
+
+ String css = body(mockMvc.perform(get("/portal/layhome/assets/campus-azure/css/main.css"))
+ .andExpect(status().isOk()).andReturn());
+ // CSS 里是 "--primary: var(--cz-primary);",声明带空格,断言前先去空白
+ assertThat(css.replaceAll("\\s+", ""))
+ .as("资产通道按主题名服务 CSS,且私有变量已别名到契约变量")
+ .contains("--cz-primary").contains("--primary:var(--cz-primary)");
+ }
+
+ @Test
+ @DisplayName("空态守卫:有内容的区块不得渲染「该区块暂无内容」,空区块恰渲染一次")
+ void emptyState_onlyForEmptyBlocks() throws Exception {
+ Integer emptyCat = persistCategory(siteId, 0, "空置栏目", CategoryTypeEnum.LIST).getId();
+ clearCaches();
+ setConfig("layhome", "{\"home_layout\":{\"version\":1,\"blocks\":["
+ + "{\"id\":\"b1\",\"type\":\"article_list\",\"title\":\"校园时讯\",\"categoryIds\":[" + catNews + "],\"style\":\"compact\",\"size\":3},"
+ + "{\"id\":\"b2\",\"type\":\"article_list\",\"title\":\"校园要闻\",\"categoryIds\":[" + catNews + "],\"style\":\"news_grid\",\"size\":3},"
+ + "{\"id\":\"b3\",\"type\":\"article_list\",\"title\":\"空置栏目\",\"categoryIds\":[" + emptyCat + "],\"style\":\"compact\",\"size\":3}"
+ + "]}}");
+
+ String html = body(mockMvc.perform(get("/portal/layhome/")).andExpect(status().isOk()).andReturn());
+
+ // th:replace(优先级 100)先于 th:if(300)求值:守卫写在同一标签上等于没写,
+ // 空态块会被无条件插入——线上表现为每个有内容的栏目卡下面都挂一句「该区块暂无内容」。
+ assertThat(count(html, "该区块暂无内容"))
+ .as("三块中仅空置栏目该显示空态")
+ .isEqualTo(1);
+ assertThat(html).contains("校园时讯").contains("校园要闻");
+ }
}
diff --git a/src/test/java/com/yunhai/cms/theme/AcademicSkinContractTest.java b/src/test/java/com/yunhai/cms/theme/AcademicSkinContractTest.java
new file mode 100644
index 0000000..c80e882
--- /dev/null
+++ b/src/test/java/com/yunhai/cms/theme/AcademicSkinContractTest.java
@@ -0,0 +1,194 @@
+package com.yunhai.cms.theme;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * 高校官网风皮肤契约(academic-navy / campus-azure,以 scholar-blue 为基座派生)。
+ *
+ * 线上事故复盘:站点配了 home_layout 时首页走 common 骨架,派生包若只改色不改区块形态,
+ * 首页正文就是骨架内置的蓝灰卡片——用户看到的"皮肤"只剩页头页脚,且中文标题被 flex 压塌。
+ * 故这里要求派生包必须自带 home-blocks fragment,并钉住三条渲染不变量。
+ */
+@DisplayName("高校官网风皮肤契约 - 自带首页区块 + 学术蓝配色")
+class AcademicSkinContractTest {
+
+ /** 皮肤名:结构类名前缀,两处必须一致(拷贝忘改前缀会让两套皮肤互相串样式)。 */
+ private static final String[] SKINS = {"academic-navy:an", "campus-azure:cz"};
+
+ private static String skin(String spec) {
+ return spec.substring(0, spec.indexOf(':'));
+ }
+
+ private static String prefix(String spec) {
+ return spec.substring(spec.indexOf(':') + 1);
+ }
+
+ private static String text(String classpath) {
+ try (InputStream in = AcademicSkinContractTest.class.getResourceAsStream(classpath)) {
+ assertThat(in).as("classpath 资源必须存在:%s", classpath).isNotNull();
+ return new String(readAll(in), StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private static byte[] readAll(InputStream in) throws IOException {
+ java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
+ byte[] buf = new byte[8192];
+ int n;
+ while ((n = in.read(buf)) > 0) {
+ out.write(buf, 0, n);
+ }
+ return out.toByteArray();
+ }
+
+ private static String ruleOf(String css, String selector) {
+ Matcher m = Pattern.compile(Pattern.quote(selector) + "\\s*\\{([^}]*)\\}").matcher(css);
+ assertThat(m.find()).as("main.css 应含选择器 %s 的规则", selector).isTrue();
+ return m.group(1).replaceAll("\\s+", "");
+ }
+
+ /** 抽出所有含 marker 的开始标签,用于检查同一标签上的属性组合。 */
+ private static java.util.List tagsContaining(String html, String marker) {
+ java.util.List tags = new java.util.ArrayList<>();
+ Matcher m = Pattern.compile("<[a-zA-Z][^>]*>").matcher(html);
+ while (m.find()) {
+ if (m.group().contains(marker)) {
+ tags.add(m.group());
+ }
+ }
+ return tags;
+ }
+
+ @Test
+ @DisplayName("派生包自带首页区块 fragment:布局模式下区块由皮肤渲染,不落通用骨架")
+ void skinOwnsHomeBlockFragments() {
+ for (String spec : SKINS) {
+ String html = text("/templates/themes/" + skin(spec) + "/fragments/home-blocks.html");
+ for (String fragment : new String[] {"news_grid", "media_focus", "compact", "image_wall",
+ "card", "ticker", "gallery", "links", "empty"}) {
+ assertThat(html).as("%s 区块 fragment 必须自带", fragment)
+ .contains("th:fragment=\"" + fragment + "(block)\"");
+ }
+ // 空态:th:replace(优先级 100)先于 th:if(300),守卫写在同一标签上等于没写
+ for (String tag : tagsContaining(html, ":: empty(")) {
+ assertThat(tag).as("%s 的空态守卫必须在外层 th:block 上", skin(spec)).doesNotContain("th:if");
+ }
+ assertThat(html).contains("th:block th:if=\"${#lists.isEmpty(block.items)}\"");
+ }
+ }
+
+ @Test
+ @DisplayName("home.html 把布局区块分发到本皮肤 fragment,区块头带右置「更多」")
+ void homeDispatchesToOwnFragments() {
+ for (String spec : SKINS) {
+ String html = text("/templates/themes/" + skin(spec) + "/home.html");
+ assertThat(html).as("须按 layoutBlocks 分支渲染").contains("layoutBlocks != null");
+ for (String style : new String[] {"news_grid", "media_focus", "compact", "image_wall"}) {
+ assertThat(html).as("%s 形态 %s 应走本皮肤 fragment", skin(spec), style)
+ .contains("'/fragments/home-blocks' :: " + style + "(${block})");
+ }
+ assertThat(html).as("区块标题行须有右侧「更多」样式钩子").contains(prefix(spec) + "-more");
+ }
+ }
+
+ @Test
+ @DisplayName("中文行不被压塌:速递条单行可收缩、列表标题超长省略")
+ void rowsMustNotCollapseCjkText() {
+ for (String spec : SKINS) {
+ String css = text("/templates/themes/" + skin(spec) + "/assets/css/main.css");
+ String p = prefix(spec);
+ String list = ruleOf(css, "." + p + "-ticker-list");
+ assertThat(list).as("flex 列表须让出收缩权并锁单行").contains("min-width:0").contains("white-space:nowrap");
+ String item = ruleOf(css, "." + p + "-ticker-item");
+ assertThat(item).as("条目不被压缩且超长省略").contains("flex:none").contains("text-overflow:ellipsis");
+ String title = ruleOf(css, "." + p + "-block-item-title");
+ assertThat(title).contains("min-width:0").contains("overflow:hidden").contains("text-overflow:ellipsis");
+ }
+ }
+
+ @Test
+ @DisplayName("皮肤变量别名到主题契约变量,供 common 兜底骨架继承")
+ void skinAliasesContractVars() {
+ for (String spec : SKINS) {
+ String css = text("/templates/themes/" + skin(spec) + "/assets/css/main.css");
+ String p = prefix(spec);
+ String root = ruleOf(css, ":root");
+ assertThat(root).contains("--primary:var(--" + p + "-primary)")
+ .contains("--text:var(--" + p + "-text)")
+ .contains("--card-bg:var(--" + p + "-card-bg)")
+ .contains("--border:var(--" + p + "-border)");
+ }
+ }
+
+ @Test
+ @DisplayName("新闻背景带画在卡片之下:绝对定位层必须压 z-index,卡片抬起来")
+ void newsBandMustPaintBehindCard() {
+ for (String spec : SKINS) {
+ String css = text("/templates/themes/" + skin(spec) + "/assets/css/main.css");
+ String p = prefix(spec);
+ // 定位元素默认绘制在普通流之上:不带 z-index 的背景带会糊在卡片正面(实测整卡泛绿)
+ assertThat(ruleOf(css, "." + p + "-sec-bg")).as("%s 背景带须压到卡片之下", p).contains("z-index:0");
+ assertThat(ruleOf(css, "." + p + "-sec-bg + ." + p + "-block"))
+ .as("%s 卡片须抬到背景带之上,否则新闻带图片盖住正文", p).contains("z-index:1");
+ }
+ }
+
+ @Test
+ @DisplayName("皮肤预览图必须是实拍图,不得沿用基座 scholar-blue 的截图")
+ void screenshotMustBeOwnCapture() {
+ byte[] base = bytes("/templates/themes/scholar-blue/assets/screenshot.png");
+ for (String spec : SKINS) {
+ String path = "/templates/themes/" + skin(spec) + "/assets/screenshot.png";
+ byte[] shot = bytes(path);
+ assertThat(shot).as("%s 的预览图与基座雷同,等于没换肤", skin(spec)).isNotEqualTo(base);
+ assertThat(shot.length).as("%s 预览图不能是空文件", skin(spec)).isGreaterThan(20 * 1024);
+ }
+ }
+
+ private static byte[] bytes(String classpath) {
+ try (InputStream in = AcademicSkinContractTest.class.getResourceAsStream(classpath)) {
+ assertThat(in).as("classpath 资源必须存在:%s", classpath).isNotNull();
+ return readAll(in);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Test
+ @DisplayName("配色必须是学术蓝:主色蓝通道主导、明度落在深蓝区间,不得回落粉紫")
+ void primaryMustBeAcademicBlue() throws IOException {
+ for (String spec : SKINS) {
+ JsonNode root = new ObjectMapper()
+ .readTree(text("/templates/themes/" + skin(spec) + "/theme.json"));
+ assertThat(root.path("name").asText()).as("name 必须等于目录名").isEqualTo(skin(spec));
+ String primary = null;
+ for (JsonNode p : root.path("params")) {
+ if ("primary".equals(p.path("key").asText())) {
+ primary = p.path("default").asText();
+ }
+ }
+ assertThat(primary).as("%s theme.json 须声明 primary 颜色参数", skin(spec)).isNotNull();
+ Matcher m = Pattern.compile("#([0-9a-fA-F]{6})").matcher(primary);
+ assertThat(m.matches()).as("primary 需为 6 位 hex,实际 %s", primary).isTrue();
+ int rgb = Integer.parseInt(m.group(1), 16);
+ int r = (rgb >> 16) & 0xFF, g = (rgb >> 8) & 0xFF, b = rgb & 0xFF;
+ assertThat(b).as("主色须蓝通道主导(粉/紫已被否决),实际 %s", primary).isGreaterThan(r);
+ assertThat(b).as("主色须蓝通道主导,实际 %s", primary).isGreaterThan(g);
+ double lightness = (Math.max(r, Math.max(g, b)) + Math.min(r, Math.min(g, b))) / 255d / 2d;
+ assertThat(lightness).as("官网主色应为深蓝/藏蓝而非浅粉彩,实际 %s", primary)
+ .isBetween(0.18d, 0.52d);
+ }
+ }
+}
diff --git a/src/test/java/com/yunhai/cms/theme/HomeBlocksCssContractTest.java b/src/test/java/com/yunhai/cms/theme/HomeBlocksCssContractTest.java
new file mode 100644
index 0000000..911be80
--- /dev/null
+++ b/src/test/java/com/yunhai/cms/theme/HomeBlocksCssContractTest.java
@@ -0,0 +1,115 @@
+package com.yunhai.cms.theme;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * 通用兜底区块骨架(themes/common/fragments/home-blocks.html)的 CSS 契约。
+ *
+ * 该片段带内联 style,任何配了 home_layout 的站点都用它渲染区块,是门户首页的实际门面;
+ * 它出问题时十套皮肤一起坏,且只在"站点配了首页布局"时才暴露——回落分支看不到。
+ * 故把三条易被改坏的不变量钉在这里:不被中文压塌、颜色穿透皮肤、全宽区块不被网格切列。
+ */
+@DisplayName("home-blocks 共享骨架 CSS 契约")
+class HomeBlocksCssContractTest {
+
+ private static final String FRAGMENT = "/templates/themes/common/fragments/home-blocks.html";
+
+ /** 取 ::style 片段里的 CSS 正文(第一个 ", Pattern.DOTALL).matcher(html);
+ assertThat(m.find()).as("片段应携带内联