Files
novalon-website/src/app/globals.css
T
zhangxiang 40c6cd612d feat(theme): 暗黑模式 Phase 1 基础设施 + 首页试点
为 html[data-theme='dark'] 添加完整 CSS 变量覆盖块,建立暗黑模式基石。
--color-ink 收窄为'文字/描边跟随主题'语义,深色 UI 元素(卡片/按钮/遮罩/
代码块/页脚)迁到 --color-dark-bg / --color-overlay 独立 token,避免 ink
反色为浅色文字时连带把深色区块变浅(双语义冲突)。

【基础设施】
- globals.css:
  * html/body 顶部硬编码 #FFFFFF !important 改 var() 化(保留 !important)
  * :root 新增 --color-overlay / --color-overlay-rgb(遮罩/深色叠加层,
    永不反色)
  * 新增 html[data-theme='dark'] 覆盖块:墨色反色为浅色文字,bg/text/
    border 层级反色,link 反色;保留 --color-dark-* / --color-brand-section
  * pre 背景 var(--color-ink) → var(--color-dark-bg)
- tailwind.config.js:注册 overlay 色(rgb() 形式,支持 /50 /60 修饰符)
- layout.tsx:head 内联防 FOUC 同步脚本,读 localStorage['novalon-theme']
  设置 data-theme(当前无切换 UI,仅作未来挂载点)

【首页试点 + 布局组件】(浅色值完全等价 → 浅色零视觉差异)
- home-content-v15.tsx:7 处 bg-white → bg-bg-primary(narrative/insights/
  cases sections 与卡片),2 处 bg-ink → bg-dark-bg(案例卡 bg-dark-bg 不
  随反色,保留深色画布)
- header.tsx / mega-dropdown.tsx:bg-white → bg-bg-primary(导航栏/移动
  端菜单/下拉面板)
- footer.tsx:bg-[#0A0E14] → bg-dark-bg(语义统一,视觉零差异)

【全局 UI 组件】(深色区块语义统一 + 遮罩固定深色)
- button.tsx:secondary 'bg-ink hover:bg-ink-light' → bg-dark-bg / hover:bg-dark-bg-secondary;
  outline 'hover:bg-ink hover:border-ink' → hover:bg-dark-bg / border-dark-bg
- stats-showcase / milestone-timeline:isDark 分支 bg-ink → bg-dark-bg
- metric-card:isDark 分支 bg-ink/50 → bg-overlay/50,hover:bg-ink → hover:bg-overlay
- dialog / alert-dialog:遮罩 bg-ink/60 → bg-overlay/60(永不反色)
- button.test.tsx:断言 bg-ink → bg-dark-bg,注释同步

【验证】
- type-check 0 errors
- lint 0 errors(127 warnings 既有,非本次引入)
- jest 128 suites / 1623 passed(button 断言同步通过)
- 视觉回归先非 update:21 passed(浅色安全门零 diff)+ 1 failed
  (仅 theme-dark-main,dark 快照从浅色名义变真正深色 = 语义修复预期)
- update-snapshots:22 passed,仅 theme-dark-main 基线重写
- computed-style 权威验证(一次性脚本,已删除):
  dark 7 项断言全过(html/body/hero/导航栏/案例卡→深色 #0A0E14;
  body 文字→浅色 #F8FAFC;footer/overlay→保持深色);light 4 项零回归

【未在 Phase 1 范围】(已识别,留待 Phase 2/3 决策)
- service-detail-content-v4.tsx 等营销页 bg-white:Phase 2 批量 token 化
- admin 页面 bg-white + RichTextEditor:admin 边界决策 + Phase 3
- 品牌红 #C41E3A 在深色底对比度复检:Phase 3
2026-08-31 18:15:58 +08:00

1436 lines
38 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@tailwind base;
@tailwind components;
@tailwind utilities;
html {
background-color: var(--color-bg-primary) !important;
}
body {
background-color: var(--color-bg-primary) !important;
color: var(--color-text-primary) !important;
}
:root {
/* === 咨询专业 · 色彩体系(浅色模式) === */
/* 墨色核心 */
--color-ink: #0A0E14;
--color-ink-light: #0F1419;
--color-ink-lighter: #151B23;
--color-ink-rgb: 10 14 20;
/* 品牌信号色:朱砂红 — Committed 色彩策略(Bain 式自信表达) */
--color-brand: #C41E3A;
--color-brand-hover: #A01830;
--color-brand-light: #E04A68;
--color-brand-soft: rgba(196, 30, 58, 0.12);
--color-brand-bg: #FEF2F4;
--color-brand-rgb: 196 30 58;
/* 品牌色深色区块(Bain 式深红背景) */
--color-brand-section: #8B1530;
--color-brand-section-text: #F8FAFC;
--color-brand-section-muted: rgba(248, 250, 252, 0.7);
/* 辅助色:服务/行业编码 */
--color-accent-blue: #3B82F6;
--color-accent-blue-soft: rgba(59, 130, 246, 0.12);
--color-accent-blue-rgb: 59 130 246;
--color-accent-teal: #14B8A6;
--color-accent-teal-soft: rgba(20, 184, 166, 0.12);
--color-accent-teal-rgb: 20 184 166;
--color-accent-amber: #F59E0B;
--color-accent-amber-soft: rgba(245, 158, 11, 0.12);
--color-accent-amber-rgb: 245 158 11;
--color-accent-purple: #8B5CF6;
--color-accent-purple-soft: rgba(139, 92, 246, 0.12);
--color-accent-purple-rgb: 139 92 246;
--color-accent-cyan: #06B6D4;
--color-accent-cyan-soft: rgba(6, 182, 212, 0.12);
--color-accent-cyan-rgb: 6 182 212;
/* 背景色层级 */
--color-bg-primary: #FFFFFF;
--color-bg-secondary: #F8FAFC;
--color-bg-secondary-rgb: 248 250 252;
--color-bg-tertiary: #F1F5F9;
--color-bg-section: #F8FAFC;
--color-bg-hover: #F1F5F9;
--color-bg-elevated: #FFFFFF;
--color-bg-primary-rgb: 255 255 255;
/* 文字色层级 */
--color-text-primary: #0A0E14;
--color-text-secondary: #334155;
--color-text-secondary-rgb: 51 65 85;
--color-text-tertiary: #475569;
--color-text-muted: #64748B;
--color-text-muted-rgb: 100 116 139;
--color-text-subtle: #64748B;
--color-text-placeholder: #64748B;
/* 仅用于 ≥24px 大号装饰性文本(如章节序号),对白底 3.41:1,满足 AA 大字 3:1。
正文、占位符、提示文案请改用 --color-text-placeholder(4.76:1)或更深的令牌。 */
--color-text-hint: #7C8CA5;
--color-text-inverse: #FFFFFF;
/* 边框色层级 —— 中度软化:--color-border-primary 从 #E2E8F0 调整为 #EEF2F7(更淡),
让 20 处 gap-px bg-border-primary 网格线与所有卡片边框都自动弱化(约 50%),
与增强的卡片阴影呼应,视觉从"靠硬边分界"转为"靠阴影分层"。 */
--color-border-primary: #EEF2F7;
--color-border-primary-rgb: 238 242 247;
--color-border-secondary: #CBD5E1;
--color-border-secondary-rgb: 203 213 225;
--color-border-accent: #0A0E14;
--color-border-accent-rgb: 10 14 20;
--color-border-light: #F1F5F9;
--color-border-light-rgb: 241 245 249;
--color-border-dark: #334155;
--color-border-dark-rgb: 51 65 85;
--color-border-brand: #C41E3A;
--color-border-brand-rgb: 196 30 58;
/* 链接色 */
--color-link: #0A0E14;
--color-link-hover: #C41E3A;
/* 功能色 */
--color-success: #16A34A;
--color-success-hover: #15803D;
--color-success-bg: #F0FDF4;
--color-success-rgb: 22 163 74;
/* 文字专用:--color-success 仅 3.30:1,作正文色不达 AA;本值 5.02:1(于 success-bg 上 4.79:1) */
--color-success-text: #15803D;
--color-warning: #D97706;
--color-warning-hover: #B45309;
--color-warning-bg: #FFFBEB;
--color-warning-rgb: 217 119 6;
/* 文字专用:--color-warning 仅 3.19:1,作正文色不达 AA;本值 5.02:1(于 warning-bg 上 4.84:1) */
--color-warning-text: #B45309;
--color-error: #C41E3A;
--color-error-hover: #A01830;
--color-error-bg: #FEF2F4;
--color-error-rgb: 196 30 58;
--color-info: #3B82F6;
--color-info-rgb: 59 130 246;
--color-info-bg: #EFF6FF;
/* 文字专用:--color-info 仅 3.68:1,作正文色不达 AA;本值 6.70:1(于 info-bg 上 6.16:1) */
--color-info-text: #1D4ED8;
/* 深色调性区域 */
--color-dark-bg: #0A0E14;
--color-dark-bg-secondary: #0F1419;
--color-dark-bg-tertiary: #151B23;
--color-dark-text-primary: #F8FAFC;
--color-dark-text-secondary: #CBD5E1;
--color-dark-text-muted: #94A3B8;
--color-dark-border: #1E293B;
/* 遮罩 / 深色叠加层(dialog 背板、metric-card 深色半透明底):
语义上"永远是深色覆盖",不随暗黑模式反色 —— 故用独立 token。 */
--color-overlay: #0A0E14;
--color-overlay-rgb: 10 14 20;
/* 阴影系统(按层级 + 用途分类) */
/* 基础层级:几乎看不见,用于微妙的边界定义 */
--shadow-xs: 0 1px 1px rgba(10, 14, 20, 0.03);
/* 轻量:卡片默认状态、输入框 */
--shadow-sm: 0 1px 3px rgba(10, 14, 20, 0.04), 0 1px 2px rgba(10, 14, 20, 0.02);
/* 中等:悬浮状态、下拉菜单 */
--shadow-md: 0 4px 12px rgba(10, 14, 20, 0.06), 0 2px 4px rgba(10, 14, 20, 0.03);
/* 大型:模态框、悬浮卡片 */
--shadow-lg: 0 12px 28px rgba(10, 14, 20, 0.08), 0 4px 8px rgba(10, 14, 20, 0.04);
/* 超大:全屏弹窗、重要浮层 */
--shadow-xl: 0 24px 56px rgba(10, 14, 20, 0.1), 0 8px 16px rgba(10, 14, 20, 0.06);
/* 品牌阴影:CTA 按钮、品牌强调元素 */
--shadow-brand: 0 6px 24px rgba(196, 30, 58, 0.22);
--shadow-brand-hover: 0 8px 32px rgba(196, 30, 58, 0.32);
/* 内阴影:凹陷效果、输入框聚焦 */
--shadow-inset: inset 0 2px 4px rgba(10, 14, 20, 0.04);
/* 光晕阴影:发光效果(慎用) */
--shadow-glow: 0 0 40px rgba(196, 30, 58, 0.15);
/* 字体系统
字族按「逐字符」回退:拉丁字母命中 Geist(无 CJK 字形),
中文自动落到后面的 PingFang SC / 微软雅黑。
var() 必须给回退值,否则 next/font 变量缺失时整条声明会失效。 */
--font-sans: var(--font-geist-sans, ui-sans-serif), "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--font-display: var(--font-geist-sans, ui-sans-serif), "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--font-mono: var(--font-geist-mono, ui-monospace), SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
--font-brand: "STKaiti", "KaiTi", "楷体", "SimKai", serif;
--font-calligraphy-system: "STKaiti", "KaiTi", "楷体", "SimKai", serif;
--font-serif: "Songti SC", "STSongti-SC", "Noto Serif CJK SC", "SimSun", "STSong", serif;
/* 字号系统(12级排版尺度)—— Mobile First,默认移动端 */
--font-size-caption: 0.6875rem;
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.0625rem;
--font-size-xl: 1.1875rem;
--font-size-2xl: 1.25rem;
--font-size-3xl: 1.5rem;
--font-size-4xl: 1.875rem;
--font-size-5xl: 2.25rem;
--font-size-6xl: 3rem;
--font-size-7xl: 3.5rem;
--font-size-display: 4.5rem;
/* 行高系统(与字号对应) */
--line-height-caption: 1.4;
--line-height-tight: 1.15;
--line-height-snug: 1.35;
--line-height-normal: 1.65;
--line-height-relaxed: 1.85;
/* 字间距系统(按使用场景分层) */
--letter-spacing-tighter: -0.03em; /* 展示标题,不低于 -0.04em 地板 */
--letter-spacing-tight: -0.02em;
--letter-spacing-normal: 0;
--letter-spacing-wide: 0.03em;
--letter-spacing-wider: 0.06em;
--letter-spacing-widest: 0.12em;
--letter-spacing-eyebrow: 0.12em; /* 减小,避免过宽追踪 */
/* 段落间距 */
--paragraph-spacing: 1.25em;
--paragraph-spacing-loose: 1.75em;
/* 间距系统 */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
--spacing-2xl: 3rem;
--spacing-3xl: 4rem;
--spacing-4xl: 6rem;
--spacing-5xl: 8rem;
--spacing-6xl: 12rem;
/* 圆角系统(按用途分类)—— 中度软化:4→6/6→8/10→12/14→18,
让"硬边"卡片语言变为"柔边",与增强的卡片阴影呼应。
注意:SM/MD/LG 同步联动大量 Tailwind 圆角类,全局生效。 */
--radius-xs: 3px; /* 极小:标签、徽章 */
--radius-sm: 6px; /* 小:按钮、输入框 */
--radius-md: 8px; /* 中:卡片、弹窗 */
--radius-lg: 12px; /* 大:大型卡片、容器 */
--radius-xl: 18px; /* 特大:英雄卡片、特色模块 */
--radius-2xl: 24px; /* 超大:全屏弹窗、大型容器 */
--radius-3xl: 32px; /* 巨大:展示卡片 */
--radius-full: 9999px; /* 圆形:头像、圆形按钮 */
/* 过渡系统(按时长分级) */
--transition-instant: 100ms;
--transition-fast: 180ms;
--transition-normal: 280ms;
--transition-slow: 450ms;
--transition-slower: 700ms;
--transition-gentle: 1000ms;
/* 缓动曲线(按性格分类) */
/* 标准:通用入场、状态变化(最常用) */
--ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
/* 减速:元素入场(快速开始,轻柔结束) */
--ease-decelerate: cubic-bezier(0, 0, 0.2, 1);
/* 加速:元素退场(轻柔开始,快速结束) */
--ease-accelerate: cubic-bezier(0.4, 0, 1, 1);
/* 弹性:有生命感的交互(按钮按压、卡片回弹) */
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
--ease-spring-soft: cubic-bezier(0.34, 1.2, 0.64, 1);
/* 锐利:精确、专业的感觉(数据变化、指标跳动) */
--ease-sharp: cubic-bezier(0.65, 0, 0.35, 1);
/* 水墨:柔和、有呼吸感(背景过渡、光晕变化) */
--ease-ink: cubic-bezier(0.22, 1, 0.36, 1);
/* ease-out 别名:默认使用水墨曲线(Porsche 风格:快速开始,缓慢结束) */
--ease-out: cubic-bezier(0.22, 1, 0.36, 1);
/* 动效延迟序列(错落动效用) */
--stagger-xs: 30ms;
--stagger-sm: 60ms;
--stagger-md: 100ms;
--stagger-lg: 150ms;
--stagger-xl: 200ms;
/* 容器宽度 */
--container-max: 1360px;
--container-padding: 1rem;
/* === 组件令牌层(Component Tokens)=== */
/* 按钮 */
--btn-height-sm: 2.25rem;
--btn-height-md: 2.75rem;
--btn-height-lg: 3.25rem;
--btn-padding-x: 1.5rem;
--btn-font-size: 0.875rem;
/* 卡片 —— 中度软化:阴影加深(透明度 0.06→0.08),新增 y 偏移的 hover 抬升过渡。
让卡片从"靠 1px 硬边分界"变为"靠柔和阴影分层",与增大圆角呼应。 */
--card-padding: 1.5rem;
--card-padding-lg: 2.5rem;
--card-gap: 1.5rem;
--card-border-radius: var(--radius-lg);
--card-shadow: 0 1px 2px rgba(10, 14, 20, 0.04), 0 2px 8px rgba(10, 14, 20, 0.08);
--card-shadow-hover: 0 4px 12px rgba(10, 14, 20, 0.06), 0 12px 32px rgba(10, 14, 20, 0.12);
--card-border: 1px solid var(--color-border-light);
--card-transition: transform var(--transition-normal) var(--ease-out),
box-shadow var(--transition-normal) var(--ease-out),
border-color var(--transition-normal) var(--ease-out);
/* 输入框 */
--input-height: 2.75rem;
--input-padding-x: 1rem;
--input-border-radius: var(--radius-sm);
/* Section 间距 —— Mobile First,默认移动端 —— 中度软化:节奏更舒展 */
--section-gap: var(--spacing-4xl);
--section-gap-sm: var(--spacing-3xl);
--section-padding-y: var(--spacing-4xl);
/* === 组件令牌层(Component Tokens)=== */
/* Badge 标签 */
--badge-height-sm: 1.25rem;
--badge-height-md: 1.5rem;
--badge-padding-x: 0.625rem;
--badge-font-size: 0.6875rem;
--badge-radius: var(--radius-full);
/* Tabs 标签页 */
--tab-height: 2.5rem;
--tab-padding-x: 1rem;
--tab-font-size: 0.875rem;
--tab-indicator-height: 2px;
/* Modal / Dialog 弹窗 */
--modal-padding: 2rem;
--modal-radius: var(--radius-xl);
--modal-max-width-sm: 420px;
--modal-max-width-md: 560px;
--modal-max-width-lg: 720px;
/* Tooltip 提示 */
--tooltip-padding: 0.5rem 0.75rem;
--tooltip-radius: var(--radius-sm);
--tooltip-font-size: 0.75rem;
/* Form 表单 */
--label-font-size: 0.875rem;
--label-margin-bottom: 0.5rem;
--form-group-gap: 1.25rem;
/* Avatar 头像 */
--avatar-size-sm: 2rem;
--avatar-size-md: 2.5rem;
--avatar-size-lg: 3rem;
--avatar-radius: var(--radius-full);
/* Table 表格 */
--table-header-bg: var(--color-bg-secondary);
--table-header-font-size: 0.75rem;
--table-cell-padding-y: 0.75rem;
--table-cell-padding-x: 1rem;
--table-border-color: var(--color-border-primary);
/* Breadcrumb 面包屑 */
--breadcrumb-font-size: 0.875rem;
--breadcrumb-separator-margin: 0.5rem;
/* Menu / Dropdown 菜单 */
--menu-item-height: 2.5rem;
--menu-padding-y: 0.5rem;
--menu-min-width: 180px;
/* Accordion 手风琴 */
--accordion-item-gap: 0.5rem;
--accordion-trigger-height: 3rem;
--accordion-trigger-padding-x: 1rem;
/* Skeleton 骨架屏 */
--skeleton-radius: var(--radius-sm);
--skeleton-bg: var(--color-bg-tertiary);
/* Stats Bar 数据条 */
--stats-bar-gap: var(--spacing-2xl);
--stats-number-size: var(--font-size-4xl);
--stats-label-size: var(--font-size-xs);
/* === 12 列网格系统(Grid System)=== */
--grid-columns: 12;
--grid-gap-xs: 0.5rem;
--grid-gap-sm: 1rem;
--grid-gap-md: 1.5rem;
--grid-gap-lg: 2rem;
--grid-gap-xl: 2.5rem;
--grid-gap-2xl: 3rem;
}
/* === 暗黑模式(html[data-theme='dark'])===
策略:仅覆盖 CSS 变量,组件无需逐元素反色。
- 文字墨色 --color-ink 反色为浅色(其语义收窄为"文字/描边跟随主题")
- 页面底色 --color-bg-* 反色为深色
- 深色区块(--color-dark-* / --color-brand-section / --color-overlay / footer)
使用独立 token,不随反色 —— 由组件显式引用(如 bg-dark-bg) */
html[data-theme='dark'] {
/* 墨色反色 → 文字浅色 */
--color-ink: #F8FAFC;
--color-ink-light: #E2E8F0;
--color-ink-lighter: #CBD5E1;
--color-ink-rgb: 248 250 252;
/* 页面底色反色 */
--color-bg-primary: #0A0E14;
--color-bg-primary-rgb: 10 14 20;
--color-bg-secondary: #0F1419;
--color-bg-secondary-rgb: 15 20 25;
--color-bg-tertiary: #151B23;
--color-bg-section: #0F1419;
--color-bg-hover: #151B23;
--color-bg-elevated: #151B23;
/* 文字层级反色 */
--color-text-primary: #F8FAFC;
--color-text-secondary: #CBD5E1;
--color-text-secondary-rgb: 203 213 225;
--color-text-tertiary: #94A3B8;
--color-text-muted: #94A3B8;
--color-text-muted-rgb: 148 163 184;
--color-text-subtle: #94A3B8;
--color-text-placeholder: #94A3B8;
--color-text-hint: #94A3B8;
--color-text-inverse: #0A0E14;
/* 边框层级反色 */
--color-border-primary: #1E293B;
--color-border-primary-rgb: 30 41 59;
--color-border-secondary: #334155;
--color-border-secondary-rgb: 51 65 85;
--color-border-accent: #F8FAFC;
--color-border-accent-rgb: 248 250 252;
--color-border-light: #1E293B;
--color-border-light-rgb: 30 41 59;
--color-border-dark: #CBD5E1;
--color-border-dark-rgb: 203 213 225;
/* 链接反色 */
--color-link: #F8FAFC;
--color-link-hover: #E04A68;
}
/* html/body 背景跟随主题 token(覆盖顶部 !important 硬编码) */
html[data-theme='dark'],
html[data-theme='dark'] body {
background-color: var(--color-bg-primary) !important;
color: var(--color-text-primary) !important;
}
@layer base {
* {
@apply antialiased;
border-color: var(--color-border-primary);
}
html {
scroll-behavior: smooth;
/* 桌面端字号分级(mobile-first 16 → tablet 17 → desktop 18):
桌面端 18px 根字号使所有 rem 单位放大 12.5%,标题与留白更舒展,
与增强的圆角+阴影形成"软化"语言。
权衡:会覆盖用户浏览器字号缩放设置 —— 经 design review 决定保留视觉一致性。 */
font-size: 16px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
overflow-x: hidden;
}
@media (min-width: 640px) {
html {
font-size: 17px;
}
}
@media (min-width: 1024px) {
html {
font-size: 18px;
}
}
body {
background-color: var(--color-bg-primary);
color: var(--color-text-primary);
font-family: var(--font-sans);
line-height: var(--line-height-normal);
letter-spacing: var(--letter-spacing-normal);
position: relative;
overflow-x: hidden;
width: 100%;
transition: background-color var(--transition-normal) var(--ease-out),
color var(--transition-normal) var(--ease-out);
}
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
z-index: -1;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 700;
line-height: var(--line-height-tight);
letter-spacing: var(--letter-spacing-tight);
color: var(--color-text-primary);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1 {
font-size: var(--font-size-5xl);
letter-spacing: var(--letter-spacing-tighter);
font-weight: 800;
}
h2 {
font-size: var(--font-size-4xl);
letter-spacing: var(--letter-spacing-tight);
font-weight: 700;
}
h3 {
font-size: var(--font-size-2xl);
letter-spacing: var(--letter-spacing-tight);
font-weight: 700;
}
h4 {
font-size: var(--font-size-xl);
letter-spacing: var(--letter-spacing-normal);
font-weight: 600;
}
h5 {
font-size: var(--font-size-lg);
letter-spacing: var(--letter-spacing-normal);
font-weight: 600;
}
h6 {
font-size: var(--font-size-base);
letter-spacing: var(--letter-spacing-wide);
font-weight: 600;
text-transform: uppercase;
}
p {
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
margin-bottom: var(--paragraph-spacing);
}
p:last-child {
margin-bottom: 0;
}
/* 列表样式优化 */
ul, ol {
color: var(--color-text-secondary);
line-height: var(--line-height-relaxed);
margin-bottom: var(--paragraph-spacing);
padding-left: 1.5em;
}
li {
margin-bottom: 0.5em;
}
li:last-child {
margin-bottom: 0;
}
ul {
list-style-type: none;
}
ul li::before {
content: '';
position: absolute;
left: 0;
top: 0.75em;
width: 6px;
height: 6px;
border-radius: 1px;
background: var(--color-brand);
transform: rotate(45deg);
}
ul li {
position: relative;
padding-left: 0.5em;
}
/* 引用样式 */
blockquote {
border-left: 3px solid var(--color-brand);
padding-left: 1.5em;
margin: 2em 0;
font-size: var(--font-size-lg);
color: var(--color-text-primary);
font-style: normal;
line-height: var(--line-height-relaxed);
background: var(--color-bg-secondary);
padding: 1.5em 2em;
border-radius: 0 var(--radius-md) var(--radius-md) 0;
}
/* 强调文本 */
strong {
font-weight: 600;
color: var(--color-text-primary);
}
/* 代码样式 */
code {
font-family: var(--font-mono);
font-size: 0.9em;
background: var(--color-bg-tertiary);
padding: 0.15em 0.4em;
border-radius: var(--radius-sm);
color: var(--color-brand);
}
pre {
font-family: var(--font-mono);
font-size: var(--font-size-sm);
line-height: var(--line-height-snug);
background: var(--color-dark-bg);
color: var(--color-dark-text-primary);
padding: 1.5em;
border-radius: var(--radius-lg);
overflow-x: auto;
margin: 2em 0;
}
pre code {
background: transparent;
padding: 0;
color: inherit;
font-size: inherit;
}
/* 水平分隔线 */
hr {
border: none;
height: 1px;
background: var(--color-border-primary);
margin: 3em 0;
}
/* 数字和符号的字体优化 */
.tabular-nums {
font-variant-numeric: tabular-nums;
}
.oldstyle-nums {
font-variant-numeric: oldstyle-nums;
}
/* 小字说明文字 */
.caption {
font-size: var(--font-size-caption);
line-height: var(--line-height-caption);
color: var(--color-text-muted);
letter-spacing: var(--letter-spacing-wide);
}
/* 眉毛标签(Eyebrow Label) */
.eyebrow {
font-size: var(--font-size-xs);
font-weight: 600;
letter-spacing: var(--letter-spacing-eyebrow);
text-transform: uppercase;
color: var(--color-brand);
}
a {
color: var(--color-link);
text-decoration: none;
transition: color var(--transition-fast) var(--ease-out);
}
a:hover {
color: var(--color-link-hover);
}
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
outline: 2px solid var(--color-brand);
outline-offset: 2px;
border-radius: 4px;
}
button:focus:not(:focus-visible),
a:focus:not(:focus-visible),
input:focus:not(:focus-visible),
textarea:focus:not(:focus-visible) {
outline: none;
}
button {
font-family: inherit;
cursor: pointer;
}
input, textarea {
font-family: inherit;
outline: none;
}
input:focus, textarea:focus {
outline: none;
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
@media (prefers-contrast: more) {
:root {
--color-text-primary: #000000;
--color-text-secondary: #1a1a1a;
--color-border-primary: #000000;
/* Tailwind border-* 工具类消费 rgb 通道,需同步覆写,否则高对比度模式下边框静默失效 */
--color-border-primary-rgb: 0 0 0;
}
}
.font-brand {
font-family: var(--font-brand), "STKaiti", "KaiTi", serif !important;
font-weight: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
::selection {
background-color: var(--color-brand);
color: white;
}
}
@layer utilities {
.container-x {
width: 100%;
max-width: var(--container-max);
margin-left: auto;
margin-right: auto;
padding-left: var(--container-padding);
padding-right: var(--container-padding);
}
@media (min-width: 768px) {
.container-x {
--container-padding: 2.5rem;
}
}
@media (min-width: 1024px) {
.container-x {
--container-padding: 3rem;
}
}
.section-padding {
padding-top: var(--section-padding-y);
padding-bottom: var(--section-padding-y);
}
.text-balance {
text-wrap: balance;
}
.bg-dots {
background-image: radial-gradient(circle, var(--color-border-primary) 1px, transparent 1px);
background-size: 24px 24px;
}
.bg-grain {
position: relative;
}
.bg-grain::before {
content: '';
position: absolute;
inset: 0;
opacity: 0.04;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
background-repeat: repeat;
background-size: 128px 128px;
pointer-events: none;
z-index: 0;
}
.bg-glow-brand {
background: radial-gradient(ellipse at 50% 0%, rgba(var(--color-brand-rgb), 0.08) 0%, transparent 60%);
}
/* Bain 式干净卡片(替代旧墨韵光晕卡片) */
.bain-card {
background: var(--color-bg-primary);
border: var(--card-border);
border-radius: var(--card-border-radius);
box-shadow: var(--card-shadow);
transition: transform var(--transition-fast) var(--ease-out),
box-shadow var(--transition-fast) var(--ease-out);
}
.bain-card:hover {
transform: translateY(-4px);
box-shadow: var(--card-shadow-hover);
}
/* === Bain 式不对称布局系统 === */
/* 宽窄列:左宽右窄(65/35) */
.asymmetric-wide-narrow {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-2xl);
}
@media (min-width: 1024px) {
.asymmetric-wide-narrow {
grid-template-columns: 5fr 3fr;
gap: var(--spacing-4xl);
}
}
/* 宽窄列:左窄右宽(35/65) */
.asymmetric-narrow-wide {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-2xl);
}
@media (min-width: 1024px) {
.asymmetric-narrow-wide {
grid-template-columns: 3fr 5fr;
gap: var(--spacing-4xl);
}
}
/* 不对称三列:左宽 + 中窄 + 右窄(50/25/25) */
.asymmetric-three {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-2xl);
}
@media (min-width: 1024px) {
.asymmetric-three {
grid-template-columns: 2fr 1fr 1fr;
gap: var(--spacing-3xl);
}
}
/* 大留白区块:用于 Hero 下方过渡 */
.section-breathing {
padding-top: var(--spacing-5xl);
padding-bottom: var(--spacing-5xl);
}
@media (min-width: 768px) {
.section-breathing {
padding-top: var(--spacing-6xl);
padding-bottom: var(--spacing-6xl);
}
}
/* 紧致区块:用于数据密集区 */
.section-compact {
padding-top: var(--spacing-2xl);
padding-bottom: var(--spacing-2xl);
}
@media (min-width: 768px) {
.section-compact {
padding-top: var(--spacing-3xl);
padding-bottom: var(--spacing-3xl);
}
}
/* 品牌色深色区块(Bain 式 Hero/CTA 深红背景) */
.bg-brand-section {
background-color: var(--color-brand-section);
color: var(--color-brand-section-text);
}
.bg-glow-hero {
background:
radial-gradient(ellipse at 20% 30%, rgba(var(--color-brand-rgb), 0.1) 0%, transparent 50%),
radial-gradient(ellipse at 80% 70%, rgba(var(--color-accent-blue-rgb), 0.06) 0%, transparent 50%);
}
/* 斜切装饰(Accenture 风格) */
.clip-slant-right {
clip-path: polygon(0 0, 100% 0, 92% 100%, 0 100%);
}
.clip-slant-left {
clip-path: polygon(8% 0, 100% 0, 100% 100%, 0 100%);
}
/* 渐变分隔线 */
.divider-gradient {
height: 1px;
background: linear-gradient(90deg, transparent, var(--color-border-secondary), transparent);
}
/* L 形角框 */
.corner-frame {
position: relative;
}
.corner-frame::before,
.corner-frame::after {
content: '';
position: absolute;
width: 16px;
height: 16px;
border-color: var(--color-brand);
border-style: solid;
transition: all var(--transition-normal) var(--ease-out);
}
.corner-frame::before {
top: 0;
left: 0;
border-width: 2px 0 0 2px;
}
.corner-frame::after {
bottom: 0;
right: 0;
border-width: 0 2px 2px 0;
}
/* 编号样式(超大背景编号) */
.bg-number {
font-size: clamp(6rem, 20vw, 16rem);
font-weight: 900;
line-height: 0.8;
color: transparent;
-webkit-text-stroke: 1px var(--color-border-primary);
user-select: none;
pointer-events: none;
}
/* === 12 列网格系统 === */
.grid-12 {
display: grid;
grid-template-columns: repeat(12, 1fr);
}
.grid-gap-xs { gap: var(--grid-gap-xs); }
.grid-gap-sm { gap: var(--grid-gap-sm); }
.grid-gap-md { gap: var(--grid-gap-md); }
.grid-gap-lg { gap: var(--grid-gap-lg); }
.grid-gap-xl { gap: var(--grid-gap-xl); }
.grid-gap-2xl { gap: var(--grid-gap-2xl); }
/* 列跨越(1-12) */
.col-span-1 { grid-column: span 1 / span 1; }
.col-span-2 { grid-column: span 2 / span 2; }
.col-span-3 { grid-column: span 3 / span 3; }
.col-span-4 { grid-column: span 4 / span 4; }
.col-span-5 { grid-column: span 5 / span 5; }
.col-span-6 { grid-column: span 6 / span 6; }
.col-span-7 { grid-column: span 7 / span 7; }
.col-span-8 { grid-column: span 8 / span 8; }
.col-span-9 { grid-column: span 9 / span 9; }
.col-span-10 { grid-column: span 10 / span 10; }
.col-span-11 { grid-column: span 11 / span 11; }
.col-span-12 { grid-column: span 12 / span 12; }
/* 响应式列跨越 */
@media (min-width: 640px) {
.sm\:col-span-1 { grid-column: span 1 / span 1; }
.sm\:col-span-2 { grid-column: span 2 / span 2; }
.sm\:col-span-3 { grid-column: span 3 / span 3; }
.sm\:col-span-4 { grid-column: span 4 / span 4; }
.sm\:col-span-5 { grid-column: span 5 / span 5; }
.sm\:col-span-6 { grid-column: span 6 / span 6; }
.sm\:col-span-7 { grid-column: span 7 / span 7; }
.sm\:col-span-8 { grid-column: span 8 / span 8; }
.sm\:col-span-9 { grid-column: span 9 / span 9; }
.sm\:col-span-10 { grid-column: span 10 / span 10; }
.sm\:col-span-11 { grid-column: span 11 / span 11; }
.sm\:col-span-12 { grid-column: span 12 / span 12; }
}
@media (min-width: 768px) {
.md\:col-span-1 { grid-column: span 1 / span 1; }
.md\:col-span-2 { grid-column: span 2 / span 2; }
.md\:col-span-3 { grid-column: span 3 / span 3; }
.md\:col-span-4 { grid-column: span 4 / span 4; }
.md\:col-span-5 { grid-column: span 5 / span 5; }
.md\:col-span-6 { grid-column: span 6 / span 6; }
.md\:col-span-7 { grid-column: span 7 / span 7; }
.md\:col-span-8 { grid-column: span 8 / span 8; }
.md\:col-span-9 { grid-column: span 9 / span 9; }
.md\:col-span-10 { grid-column: span 10 / span 10; }
.md\:col-span-11 { grid-column: span 11 / span 11; }
.md\:col-span-12 { grid-column: span 12 / span 12; }
}
@media (min-width: 1024px) {
.lg\:col-span-1 { grid-column: span 1 / span 1; }
.lg\:col-span-2 { grid-column: span 2 / span 2; }
.lg\:col-span-3 { grid-column: span 3 / span 3; }
.lg\:col-span-4 { grid-column: span 4 / span 4; }
.lg\:col-span-5 { grid-column: span 5 / span 5; }
.lg\:col-span-6 { grid-column: span 6 / span 6; }
.lg\:col-span-7 { grid-column: span 7 / span 7; }
.lg\:col-span-8 { grid-column: span 8 / span 8; }
.lg\:col-span-9 { grid-column: span 9 / span 9; }
.lg\:col-span-10 { grid-column: span 10 / span 10; }
.lg\:col-span-11 { grid-column: span 11 / span 11; }
.lg\:col-span-12 { grid-column: span 12 / span 12; }
}
/* 网格行跨越 */
.row-span-1 { grid-row: span 1 / span 1; }
.row-span-2 { grid-row: span 2 / span 2; }
.row-span-3 { grid-row: span 3 / span 3; }
}
/* ===== 动画关键帧 ===== */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(24px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-24px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideInLeft {
from {
opacity: 0;
transform: translateX(-32px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideInRight {
from {
opacity: 0;
transform: translateX(32px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes pulse-soft {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
@keyframes shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
@keyframes float {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-8px);
}
}
@keyframes ripple {
0% {
transform: scale(0);
opacity: 0.5;
}
100% {
transform: scale(4);
opacity: 0;
}
}
@keyframes skeletonPulse {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0.7;
}
}
@keyframes growWidth {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
@keyframes spinSlow {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.animate-fade-in-up {
animation: fadeInUp var(--transition-slower) var(--ease-out) forwards;
}
.animate-fade-in-down {
animation: fadeInDown var(--transition-slower) var(--ease-out) forwards;
}
.animate-fade-in {
animation: fadeIn var(--transition-normal) var(--ease-out) forwards;
}
.animate-slide-in-left {
animation: slideInLeft var(--transition-slow) var(--ease-out) forwards;
}
.animate-slide-in-right {
animation: slideInRight var(--transition-slow) var(--ease-out) forwards;
}
.animate-scale-in {
animation: scaleIn var(--transition-normal) var(--ease-out) forwards;
}
.animate-pulse-soft {
animation: pulse-soft 2s ease-in-out infinite;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
.animate-ripple {
animation: ripple var(--transition-normal) var(--ease-out) forwards;
}
.animate-grow-width {
animation: growWidth var(--transition-slow) var(--ease-out) forwards;
transform-origin: left center;
}
.animate-spin-slow {
animation: spinSlow 8s linear infinite;
}
.skeleton-pulse {
animation: skeletonPulse 2s ease-in-out infinite;
}
.skeleton-shimmer {
background: linear-gradient(
90deg,
var(--color-bg-tertiary) 25%,
var(--color-bg-secondary) 50%,
var(--color-bg-tertiary) 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s ease-in-out infinite;
}
.animation-delay-100 { animation-delay: 100ms; }
.animation-delay-200 { animation-delay: 200ms; }
.animation-delay-300 { animation-delay: 300ms; }
.animation-delay-400 { animation-delay: 400ms; }
.animation-delay-500 { animation-delay: 500ms; }
.animation-delay-600 { animation-delay: 600ms; }
.animation-delay-700 { animation-delay: 700ms; }
.animation-delay-800 { animation-delay: 800ms; }
/* ===== 滚动条样式 ===== */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--color-border-secondary);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--color-text-muted);
}
/* ===== 响应式调整(Mobile First) ===== */
body {
padding-bottom: 64px;
}
p, li, span {
overflow-wrap: break-word;
word-wrap: break-word;
}
/* WCAG 2.5.5 (AAA): 44×44px 触控目标仅作用于移动端导航/页眉/页脚交互元素。
原全局选择器会撑大正文行内链接,破坏排版节奏与组件自有的尺寸控制。 */
@media (max-width: 768px) {
nav a,
nav button,
header a,
header button,
footer a,
footer button,
[role="menu"] a,
[role="menu"] button,
[data-mobile-menu] a,
[data-mobile-menu] button {
min-height: 44px;
min-width: 44px;
}
}
@media (min-width: 640px) {
:root {
--container-padding: 1.5rem;
}
}
@media (min-width: 768px) {
:root {
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-size-3xl: 1.875rem;
--font-size-4xl: 2.25rem;
--font-size-5xl: 3rem;
--font-size-6xl: 3.75rem;
--font-size-7xl: 4.5rem;
--font-size-display: 6rem;
--section-gap: var(--spacing-4xl);
--section-gap-sm: var(--spacing-3xl);
--section-padding-y: var(--spacing-4xl);
}
body {
padding-bottom: 0;
}
}
@media (min-width: 1024px) {
:root {
--font-size-2xl: 1.5rem;
--font-size-3xl: 2rem;
--font-size-4xl: 2.5rem;
--font-size-5xl: 3.5rem;
--font-size-6xl: 4.5rem;
--font-size-7xl: 6rem;
--font-size-display: 8rem;
--container-padding: 3rem;
--section-gap: var(--spacing-5xl);
--section-padding-y: var(--spacing-5xl);
}
}
/* ===== 安全区域 ===== */
.safe-area-inset-bottom {
padding-bottom: env(safe-area-inset-bottom, 0px);
}
/* ===== 页面过渡加载条 ===== */
.page-transition-loader {
width: 120px;
height: 3px;
background: var(--color-bg-tertiary);
border-radius: 2px;
overflow: hidden;
}
.page-transition-loader__bar {
width: 40%;
height: 100%;
background: var(--color-brand);
border-radius: 2px;
animation: page-loader-slide 1.2s ease-in-out infinite;
}
@keyframes page-loader-slide {
0% { transform: translateX(-100%); }
50% { transform: translateX(200%); }
100% { transform: translateX(-100%); }
}
@media (prefers-reduced-motion: reduce) {
.page-transition-loader__bar {
animation: none;
width: 100%;
}
}
/* ===== 渐变边框动画 ===== */
@property --border-angle {
syntax: '<angle>';
initial-value: 0deg;
inherits: false;
}
@keyframes rotateBorder {
from { --border-angle: 0deg; }
to { --border-angle: 360deg; }
}
.glow-border {
position: relative;
animation: rotateBorder 6s linear infinite paused;
}
.glow-border::before {
content: '';
position: absolute;
inset: -1px;
border-radius: inherit;
padding: 1px;
background: conic-gradient(from var(--border-angle),
var(--color-text-muted),
var(--color-border-primary),
var(--color-text-muted));
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
opacity: 0;
transition: opacity 0.6s var(--ease-out);
pointer-events: none;
}
.glow-border:hover::before {
opacity: 0.8;
}
.glow-border:hover {
animation-play-state: running;
}
/* === CMS RichTextEditor (TipTap) 样式 === */
/* 仅用于 CMS Studio 暗色主题,选择器限定在 .rich-text-editor-content */
.rich-text-editor-content {
min-height: 120px;
padding: 0.75rem;
color: white;
font-size: 0.875rem;
line-height: 1.6;
outline: none;
}
.rich-text-editor-content:empty::before {
content: attr(data-placeholder);
color: rgba(255, 255, 255, 0.3);
pointer-events: none;
}
.rich-text-editor-content h2 {
font-size: 1.125rem;
font-weight: 600;
margin: 0.75rem 0 0.5rem;
color: white;
}
.rich-text-editor-content h3 {
font-size: 1rem;
font-weight: 600;
margin: 0.5rem 0 0.375rem;
color: white;
}
.rich-text-editor-content p {
margin: 0.375rem 0;
}
.rich-text-editor-content ul,
.rich-text-editor-content ol {
padding-left: 1.25rem;
margin: 0.5rem 0;
}
.rich-text-editor-content ul {
list-style: disc;
}
.rich-text-editor-content ol {
list-style: decimal;
}
.rich-text-editor-content li {
margin: 0.25rem 0;
}
.rich-text-editor-content blockquote {
border-left: 3px solid var(--color-brand);
padding-left: 0.75rem;
margin: 0.5rem 0;
color: rgba(255, 255, 255, 0.7);
font-style: italic;
}
.rich-text-editor-content a {
color: var(--color-brand);
text-decoration: underline;
}
.rich-text-editor-content strong {
font-weight: 600;
color: white;
}
.rich-text-editor-content em {
font-style: italic;
}