fix(theme): 品牌色令牌语义拆分与暗黑模式全站治理

- 拆分品牌色「文字/底色」双通道:新增 --color-brand-ink(-rgb)(深色 #F87171)
  与 tailwind brand.ink;text-brand → text-brand-ink 迁移 247 处;
  bg-brand/border-brand 保持 --color-brand-rgb 不翻转(红底白字 5.58:1 不能动)
- dark 块补齐 --color-brand-bg: #2A1418(修复深色白字压浅粉底 1.04:1)
- hero 徽章新增 --badge-accent-text 桥接:accentColor 直用作深底文字不可读
  (#1e3a5f 深底 1.65:1),浅色取原色 / 深色 color-mix 提亮
- 硬编码颜色 token 化:bg-white/text-gray-*/border-gray-* → bg-bg-*/text-text-*/border-border-*
- 可访问性:触控目标 <24px 归零(footer 链接列 [&_a]:min-h-6 收口 377 处等)、
  news 搜索框补 aria-label、标题跳级 h2→h4 修正为 h3、装饰 blur 光斑容器补
  overflow-hidden 消除伪文本裁剪
- 验证:tsc 0 / eslint 0 error / jest 0 失败用例 / dogfood 33 路由 × 双主题 P1-P3 全零
This commit is contained in:
2026-09-05 08:16:31 +08:00
parent 846585af1f
commit 4b8500af1d
54 changed files with 339 additions and 280 deletions
+24
View File
@@ -46,6 +46,30 @@ Novalon 网站的**主体视觉骨架**。核心特征:
决策状态:✅ 已确认(2026-06-28 重申约束,2026-06-29 补充贯穿规则)
### 品牌色令牌的语义拆分(2026-09-04 新增 · 暗黑模式修复)
品牌红必须区分「文字」与「底色」两种用法,二者**不能共用同一个 CSS 变量**:
| utility | 变量 | 浅色 | 深色 | 适用 |
|---|---|---|---|---|
| `text-brand-ink` | `--color-brand-ink-rgb` | #C41E3A | **#F87171** | 品牌色**文字**:eyebrow、指标数字、标签、链接 hover |
| `bg-brand` / `border-brand` | `--color-brand-rgb` | #C41E3A | #C41E3A(**不翻转**) | 按钮底色、边框、图标填充 |
| `bg-brand-bg` | `--color-brand-bg` | #FEF2F4 | **#2A1418** | 品牌浅底块(与 `--color-error-bg` 同口径翻转) |
| `--badge-accent-text` | `--badge-accent`(组件注入) | accentColor 原色 | `color-mix(accent 45%, white)` | DetailHero 徽章:accentColor 直用作深底文字不可读(#1e3a5f 深底 1.65:1),经 CSS 变量间接引用后按主题自动适配 |
依据(WCAG 相对亮度实测,非估算):
- 红底白字按钮 #C41E3A × #F8FAFC = **5.58:1**;若把按钮底整体换成 #E04A68 会掉到 **3.75:1**
→ 所以**绝不能**整体提亮 `--color-brand`
- 深色下品牌文字取 **#F87171**:于 #0A0E14 / #0F1419 / #151B23 分别 **6.99 / 6.69 / 6.26**,全达 AA
且它已是深色主题 `--color-error-text` 的既有值,不引入新色值
例外 —— 以下场景保持 `bg-white` + `text-brand`**不**用 brand-ink),因为它们是恒定品牌红/深色
区块上的**白底反转元素**,白底在两主题下都不翻转:CTA 区块白底主按钮、品牌红指标块上的白底角标、
Switch / Slider 的白底圆钮。
决策状态:✅ 2026-09-04 全站审计后确认(深色对比度违规 683 → 0);
✅ 2026-09-04 生产构建终验(33 路由 × 双主题 P1=0 / P3=0,剩余 P2 全为 GA 外网噪音)
### 动效设计四原则 (Motion Design Principles)
基于 Porsche Consulting "用动效象征变革"理念,统一全站动效语言:
1. **Purposeful(有目的)**:每个动效必须服务于内容传达,不做纯装饰动效
@@ -70,7 +70,7 @@ function HeroSection({ data }: { data: AboutData }) {
<div key={i} className={`block ${i > 0 ? 'mt-4 sm:mt-6' : ''}`}>
{i === 1 ? (
<span className="relative inline-block">
<span className="relative text-brand font-black">
<span className="relative text-brand-ink font-black">
{line}
<motion.span
className="absolute bottom-0 left-0 w-full h-[3px] bg-brand"
@@ -137,7 +137,7 @@ function MetricsStrip({ data }: { data: AboutData }) {
transition={{ duration: 0.3, delay: i * 0.06, ease: EASE_OUT }}
className="text-center lg:text-left"
>
<div className={`text-3xl sm:text-4xl md:text-5xl font-black tracking-tight mb-2 ${i === 0 ? 'text-brand' : 'text-ink'}`}>
<div className={`text-3xl sm:text-4xl md:text-5xl font-black tracking-tight mb-2 ${i === 0 ? 'text-brand-ink' : 'text-ink'}`}>
{metric.value}
</div>
<div className="text-sm font-medium text-text-secondary mb-1">{metric.label}</div>
@@ -165,7 +165,7 @@ function WhoWeAreSection({ data }: { data: AboutData }) {
className="lg:col-span-5"
>
<div className="flex items-center gap-4 mb-6">
<span className="text-4xl md:text-5xl font-black text-brand/80 font-mono leading-none tabular-nums">01</span>
<span className="text-4xl md:text-5xl font-black text-brand-ink/80 font-mono leading-none tabular-nums">01</span>
<div>
<div className="text-sm font-mono tracking-[0.2em] text-text-muted uppercase">
Why We Started
@@ -194,7 +194,7 @@ function WhoWeAreSection({ data }: { data: AboutData }) {
className="lg:col-span-7"
>
<div className="flex items-center gap-4 mb-6">
<span className="text-4xl md:text-5xl font-black text-brand/80 font-mono leading-none tabular-nums">02</span>
<span className="text-4xl md:text-5xl font-black text-brand-ink/80 font-mono leading-none tabular-nums">02</span>
<div>
<div className="text-sm font-mono tracking-[0.2em] text-text-muted uppercase">
How We Work
@@ -214,7 +214,7 @@ function WhoWeAreSection({ data }: { data: AboutData }) {
{value.number}
</div>
<div className="flex-1">
<h3 className="text-xl md:text-2xl font-bold text-ink mb-3 group-hover:text-brand transition-colors duration-300">
<h3 className="text-xl md:text-2xl font-bold text-ink mb-3 group-hover:text-brand-ink transition-colors duration-300">
{value.title}
</h3>
<p className="text-text-secondary leading-relaxed">{value.description}</p>
@@ -244,7 +244,7 @@ function MilestonesSection({ data }: { data: AboutData }) {
className="max-w-3xl mb-16 sm:mb-20 md:mb-24"
>
<div className="flex items-center gap-4 mb-6">
<span className="text-4xl md:text-5xl font-black text-brand/80 font-mono leading-none tabular-nums">03</span>
<span className="text-4xl md:text-5xl font-black text-brand-ink/80 font-mono leading-none tabular-nums">03</span>
<div>
<div className="text-sm font-mono tracking-[0.2em] text-text-muted uppercase">
Where We Are Heading
@@ -272,7 +272,7 @@ function MilestonesSection({ data }: { data: AboutData }) {
<div className="grid sm:grid-cols-12 gap-4 sm:gap-8">
<div className="sm:col-span-3">
<div className={`text-2xl sm:text-3xl md:text-4xl font-black tracking-tight ${idx === 0 ? 'text-brand' : 'text-ink'}`}>
<div className={`text-2xl sm:text-3xl md:text-4xl font-black tracking-tight ${idx === 0 ? 'text-brand-ink' : 'text-ink'}`}>
{milestone.year}
</div>
</div>
@@ -80,7 +80,7 @@ export default function BrandContent() {
>
<span className="inline-flex items-center gap-2 px-3 py-1.5 bg-brand/[0.08] border border-brand/20 rounded-full">
<span className="w-1.5 h-1.5 rounded-full bg-brand" />
<span className="text-[13px] font-semibold text-brand tracking-[0.08em] uppercase">
<span className="text-[13px] font-semibold text-brand-ink tracking-[0.08em] uppercase">
</span>
</span>
@@ -99,7 +99,7 @@ export default function BrandContent() {
ariaHidden
/>
<br />
<span className="text-brand font-black"></span>
<span className="text-brand-ink font-black"></span>
</motion.h1>
{/* 数据条 */}
@@ -111,7 +111,7 @@ export default function BrandContent() {
>
{brandStats.map((stat, i) => (
<div key={i} className="flex items-baseline gap-2">
<span className="text-3xl sm:text-4xl md:text-5xl font-black text-brand tabular-nums leading-none">
<span className="text-3xl sm:text-4xl md:text-5xl font-black text-brand-ink tabular-nums leading-none">
{stat.value}
</span>
<span className="text-sm text-text-muted whitespace-nowrap">
@@ -143,13 +143,13 @@ export default function BrandContent() {
<ScrollReveal className="max-w-3xl mb-16 sm:mb-20">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.15em] font-medium text-brand">
<span className="text-[13px] tracking-[0.15em] font-medium text-brand-ink">
</span>
</div>
<h2 className="font-sans text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-ink tracking-tight leading-[1.05]">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
<p className="text-text-secondary leading-relaxed mt-6 text-base sm:text-lg max-w-2xl">
@@ -163,7 +163,7 @@ export default function BrandContent() {
<ScrollReveal key={item.title} delay={i * 0.1}>
<div className="group relative bg-bg-primary border border-border-primary p-8 h-full transition-all duration-300 hover:border-brand/20 hover:shadow-md">
<div className="absolute top-0 left-0 right-0 h-0.5 bg-brand scale-x-0 group-hover:scale-x-100 transition-transform duration-150 origin-left" />
<div className="w-12 h-12 flex items-center justify-center bg-brand/[0.06] text-brand mb-6 transition-colors duration-300 group-hover:bg-brand group-hover:text-white">
<div className="w-12 h-12 flex items-center justify-center bg-brand/[0.06] text-brand-ink mb-6 transition-colors duration-300 group-hover:bg-brand group-hover:text-white">
<item.icon className="w-5 h-5" />
</div>
<h3 className="text-lg font-bold text-ink mb-3">{item.title}</h3>
@@ -195,7 +195,7 @@ export default function BrandContent() {
<p className="text-2xl sm:text-3xl font-black text-ink leading-tight tracking-tight">
<br />
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
<br />
</p>
@@ -222,7 +222,7 @@ export default function BrandContent() {
<p className="text-2xl sm:text-3xl font-black text-dark-text-primary leading-tight tracking-tight">
<br />
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
<br />
</p>
@@ -242,13 +242,13 @@ export default function BrandContent() {
<ScrollReveal className="max-w-3xl mb-16 sm:mb-20">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.15em] font-medium text-brand">
<span className="text-[13px] tracking-[0.15em] font-medium text-brand-ink">
</span>
</div>
<h2 className="font-sans text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-ink tracking-tight leading-[1.05]">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
</ScrollReveal>
@@ -265,7 +265,7 @@ export default function BrandContent() {
<div className="md:w-1/2 flex md:justify-end items-center">
<div className={`${i % 2 === 0 ? 'md:text-right md:pr-12' : 'md:text-left md:pl-12'} flex-1`}>
<div className="flex items-center gap-4 md:justify-end mb-3">
<span className="text-3xl sm:text-4xl font-black text-brand tracking-tight">
<span className="text-3xl sm:text-4xl font-black text-brand-ink tracking-tight">
{item.year}
</span>
{/* text-muted 在 bg-tertiary(#F1F5F9) 上仅 4.34:1;换 text-secondary → 9.45:1 */}
@@ -305,13 +305,13 @@ export default function BrandContent() {
<ScrollReveal className="max-w-3xl mb-16 sm:mb-20">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.15em] font-medium text-brand">
<span className="text-[13px] tracking-[0.15em] font-medium text-brand-ink">
</span>
</div>
<h2 className="font-sans text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-ink tracking-tight leading-[1.05]">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
</ScrollReveal>
@@ -324,7 +324,7 @@ export default function BrandContent() {
].map((item, i) => (
<ScrollReveal key={item.title} delay={i * 0.1}>
<div className="group relative bg-bg-secondary border border-border-primary p-8 h-full transition-all duration-300 hover:border-brand/20 hover:bg-bg-primary hover:shadow-sm">
<div className="w-12 h-12 flex items-center justify-center bg-brand/[0.06] text-brand mb-6 transition-colors duration-300 group-hover:bg-brand group-hover:text-white">
<div className="w-12 h-12 flex items-center justify-center bg-brand/[0.06] text-brand-ink mb-6 transition-colors duration-300 group-hover:bg-brand group-hover:text-white">
<item.icon className="w-5 h-5" />
</div>
<h3 className="text-lg font-bold text-ink mb-3">{item.title}</h3>
@@ -339,7 +339,7 @@ export default function BrandContent() {
{/* ============ L4: CTA 品牌行动号召 ============ */}
<section className="relative py-24 sm:py-32 md:py-44 overflow-hidden bg-dark-bg">
<div className="absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-dark-border to-transparent" />
<div className="absolute inset-0 pointer-events-none">
<div className="absolute inset-0 pointer-events-none overflow-hidden">
<div className="absolute top-1/3 right-1/4 w-[500px] h-[500px] bg-brand/[0.04] rounded-full blur-[140px]" />
</div>
@@ -348,7 +348,7 @@ export default function BrandContent() {
<h2 className="font-sans text-2xl sm:text-3xl md:text-4xl lg:text-6xl xl:text-7xl font-black text-dark-text-primary tracking-tightest leading-[0.9] mb-8 sm:mb-10">
<br />
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
<p className="text-dark-text-secondary text-lg leading-relaxed mb-12 sm:mb-16 max-w-xl">
@@ -32,7 +32,7 @@ function CaseCard({ caseItem, index }: { caseItem: CaseStudy; index: number }) {
<div className="p-6 sm:p-7 lg:p-8 flex flex-col flex-1 relative z-10">
<div className="flex items-center gap-3 mb-5">
<span className="inline-block px-3 py-1 text-[11px] font-bold text-brand border border-brand/20 bg-brand/[0.05]">
<span className="inline-block px-3 py-1 text-[11px] font-bold text-brand-ink border border-brand/20 bg-brand/[0.05]">
{caseItem.industry}
</span>
<span className="text-[10px] tracking-[0.25em] uppercase text-text-muted font-semibold">
@@ -40,15 +40,15 @@ function CaseCard({ caseItem, index }: { caseItem: CaseStudy; index: number }) {
</span>
</div>
<h3 className="text-lg sm:text-xl font-bold text-ink mb-4 leading-tight group-hover:text-brand transition-colors duration-300">
<h3 className="text-lg sm:text-xl font-bold text-ink mb-4 leading-tight group-hover:text-brand-ink transition-colors duration-300">
{caseItem.title}
</h3>
<div className="space-y-4 mb-6 flex-1">
<div>
<div className="flex items-center gap-2 mb-2">
<Target className="w-3.5 h-3.5 text-brand" />
<span className="text-[11px] tracking-wide uppercase font-bold text-brand"></span>
<Target className="w-3.5 h-3.5 text-brand-ink" />
<span className="text-[11px] tracking-wide uppercase font-bold text-brand-ink"></span>
</div>
<p className="text-sm text-text-secondary leading-relaxed line-clamp-2 pl-5.5">
{caseItem.challenge}
@@ -69,7 +69,7 @@ function CaseCard({ caseItem, index }: { caseItem: CaseStudy; index: number }) {
{caseItem.metrics.slice(0, 2).map((m, i) => (
<div key={i}>
<div className={`text-2xl sm:text-3xl font-black mb-1 tabular-nums tracking-tight ${
i === 0 ? 'text-brand' : 'text-ink'
i === 0 ? 'text-brand-ink' : 'text-ink'
}`}>
{m.value}
</div>
@@ -83,7 +83,7 @@ function CaseCard({ caseItem, index }: { caseItem: CaseStudy; index: number }) {
<Building2 className="w-4 h-4 text-text-muted" />
<span className="text-xs text-text-muted">{caseItem.client}</span>
</div>
<div className="flex items-center gap-1.5 text-brand text-sm font-semibold">
<div className="flex items-center gap-1.5 text-brand-ink text-sm font-semibold">
<ArrowUpRight className="w-4 h-4 group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-transform duration-300" />
</div>
@@ -143,7 +143,7 @@ export default function CasesContentV3({
<div className="block">{heroTitle1}</div>
<div className="block mt-4 sm:mt-6">
<span className="relative inline-block">
<span className="relative text-brand font-black">
<span className="relative text-brand-ink font-black">
{heroTitle2}
<motion.span
className="absolute -bottom-2 left-0 w-full h-[3px] bg-brand"
@@ -177,7 +177,7 @@ export default function CasesContentV3({
transition={{ duration: 0.3, delay: 0.7, ease: EASE_OUT }}
className="flex flex-wrap gap-3"
>
<span className="px-4 py-2 text-xs font-bold text-brand border border-brand/20 bg-brand/[0.05]">
<span className="px-4 py-2 text-xs font-bold text-brand-ink border border-brand/20 bg-brand/[0.05]">
</span>
<span className="px-4 py-2 text-xs font-medium text-text-secondary border border-border-primary">
@@ -211,7 +211,7 @@ export default function CasesContentV3({
className="text-center lg:text-left"
>
<div className={`text-3xl sm:text-4xl md:text-5xl font-black tracking-tight mb-2 ${
i === 0 ? 'text-brand' : 'text-ink'
i === 0 ? 'text-brand-ink' : 'text-ink'
}`}>
{metric.value}
</div>
@@ -67,7 +67,7 @@ jest.mock('@/components/ui/labeled-input', () => ({
data-testid={dataTestId || 'labeled-input'}
{...props}
/>
{error && <span data-testid="input-error" className="text-brand text-sm mt-1">{error}</span>}
{error && <span data-testid="input-error" className="text-brand-ink text-sm mt-1">{error}</span>}
</div>
),
}));
@@ -88,7 +88,7 @@ jest.mock('@/components/ui/labeled-textarea', () => ({
data-testid={dataTestId || 'labeled-textarea'}
{...props}
/>
{error && <span data-testid="textarea-error" className="text-brand text-sm mt-1">{error}</span>}
{error && <span data-testid="textarea-error" className="text-brand-ink text-sm mt-1">{error}</span>}
</div>
),
}));
@@ -239,7 +239,7 @@ function ContactFormContent({ data }: { data: ContactData }) {
<div key={i} className={`block ${i > 0 ? 'mt-4 sm:mt-6' : ''}`}>
{i === 1 ? (
<span className="relative inline-block">
<span className="relative text-brand font-black">
<span className="relative text-brand-ink font-black">
{line}
<motion.span
className="absolute -bottom-2 left-0 w-full h-[3px] bg-brand"
@@ -292,7 +292,7 @@ function ContactFormContent({ data }: { data: ContactData }) {
<p className="text-sm text-text-muted mb-1">{data.emailLabel || ''}</p>
<a
href={`mailto:${emailAddress}`}
className="text-ink hover:text-brand transition-colors duration-300"
className="inline-flex items-center min-h-6 text-ink hover:text-brand-ink transition-colors duration-300"
data-testid="email-link"
>
{emailAddress}
@@ -317,12 +317,12 @@ function ContactFormContent({ data }: { data: ContactData }) {
<div className="relative border border-border-primary bg-bg-elevated p-8 overflow-hidden">
<div className="absolute top-0 left-0 bottom-0 w-0.5 bg-brand/60" />
<div className="flex items-center gap-3 mb-4">
<Clock className="w-5 h-5 text-brand" aria-hidden="true" />
<Clock className="w-5 h-5 text-brand-ink" aria-hidden="true" />
<h2 className="text-base font-bold text-ink">{data.workHoursTitle || ''}</h2>
</div>
<div className="flex justify-between" data-testid="work-hours-row">
<span className="text-text-secondary">{data.dayLabel || ''}</span>
<span className="text-brand font-medium">{data.hours || ''}</span>
<span className="text-brand-ink font-medium">{data.hours || ''}</span>
</div>
</div>
@@ -358,13 +358,13 @@ function ContactFormContent({ data }: { data: ContactData }) {
{Object.keys(errors).length > 0 && (
<div className="mb-6 p-4 border border-brand/30 bg-brand/5" role="alert">
<p className="text-sm font-bold text-brand mb-2">
<p className="text-sm font-bold text-brand-ink mb-2">
{Object.keys(errors).length}
</p>
<ul className="space-y-1">
{Object.entries(errors).map(([field, message]) => (
<li key={field} className="text-sm text-text-secondary flex items-start gap-2">
<span className="text-brand shrink-0 mt-0.5">&#8226;</span>
<span className="text-brand-ink shrink-0 mt-0.5">&#8226;</span>
<span>{message}</span>
</li>
))}
@@ -400,7 +400,7 @@ function ContactFormContent({ data }: { data: ContactData }) {
<span className="flex items-center gap-1.5">
<Tooltip content="用于正式沟通和方案报价">
<HelpCircle className="w-3.5 h-3.5 text-text-muted hover:text-brand cursor-help" />
<HelpCircle className="w-3.5 h-3.5 text-text-muted hover:text-brand-ink cursor-help" />
</Tooltip>
</span>
}
@@ -422,7 +422,7 @@ function ContactFormContent({ data }: { data: ContactData }) {
<span className="flex items-center gap-1.5">
<Tooltip content="接收项目进度通知和验证码,仅用于业务联系">
<HelpCircle className="w-3.5 h-3.5 text-text-muted hover:text-brand cursor-help" />
<HelpCircle className="w-3.5 h-3.5 text-text-muted hover:text-brand-ink cursor-help" />
</Tooltip>
</span>
}
+30 -30
View File
@@ -221,7 +221,7 @@ function HeroSection({ heroData }: {
{...rise(20, 0.03)}
className="mb-6"
>
<span className={`inline-flex items-center gap-2 px-3 py-1.5 rounded-full text-sm font-medium border ${dark ? 'bg-brand/10 text-brand-light border-brand/30' : 'bg-brand/5 text-brand border-brand/15'}`}>
<span className={`inline-flex items-center gap-2 px-3 py-1.5 rounded-full text-sm font-medium border ${dark ? 'bg-brand/10 text-brand-light border-brand/30' : 'bg-brand/5 text-brand-ink border-brand/15'}`}>
{slogan}
</span>
</motion.div>
@@ -289,7 +289,7 @@ function HeroStatsBand({ stats }: { stats?: Record<string, any>[] }) {
<div key={i} className="flex items-baseline gap-2">
<span className={cn(
'text-3xl sm:text-4xl md:text-5xl font-mono font-bold tabular-nums leading-none',
i === 0 ? 'text-brand' : 'text-ink'
i === 0 ? 'text-brand-ink' : 'text-ink'
)}>
{stat.value}
</span>
@@ -329,7 +329,7 @@ function TrustSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
<ScrollReveal className="mb-16 sm:mb-20">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
{eyebrow}
</span>
</div>
@@ -361,7 +361,7 @@ function TrustSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
<StaggerReveal staggerDelay={0.05}>
<div className="p-6 sm:p-8 bg-brand-bg border border-[rgba(196,30,58,0.15)]" data-testid="early-access-banner">
<div className="flex items-center gap-3 mb-4">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
{earlyLabel}
</span>
</div>
@@ -374,14 +374,14 @@ function TrustSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
<div className="grid sm:grid-cols-3 gap-4 mb-8">
{earlyStatus.map((s) => (
<div key={s.label} className="p-4 bg-bg-primary border border-brand/10">
<div className="text-sm font-semibold text-brand mb-1">{s.label}</div>
<div className="text-sm font-semibold text-brand-ink mb-1">{s.label}</div>
<div className="text-xs text-text-secondary leading-relaxed">{s.desc}</div>
</div>
))}
</div>
<StaticLink
href="/contact"
className="group inline-flex shrink-0 items-center gap-2 text-sm font-semibold text-ink hover:text-brand transition-colors"
className="group inline-flex shrink-0 items-center min-h-6 gap-2 text-sm font-semibold text-ink hover:text-brand-ink transition-colors"
>
<span>{earlyCtaLabel}</span>
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-1" />
@@ -449,7 +449,7 @@ function NarrativeSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
{act.number}
</span>
</div>
<h3 className="text-xl lg:text-2xl font-bold text-ink mb-4 group-hover:text-brand transition-colors duration-300">
<h3 className="text-xl lg:text-2xl font-bold text-ink mb-4 group-hover:text-brand-ink transition-colors duration-300">
{act.title}
</h3>
<p className="text-text-secondary leading-relaxed mb-8 text-sm">
@@ -458,7 +458,7 @@ function NarrativeSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
<div className="pt-6 border-t border-border-primary">
<a
href={act.href}
className="group/link inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand transition-colors"
className="group/link inline-flex items-center min-h-6 gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand-ink transition-colors"
>
<span>{act.cta}</span>
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover/link:translate-x-1" />
@@ -493,7 +493,7 @@ function InsightsSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
<ScrollReveal className="md:max-w-3xl">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
{eyebrow}
</span>
</div>
@@ -507,10 +507,10 @@ function InsightsSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
<ScrollReveal delay={0.1}>
<StaticLink
href="/news"
className="group inline-flex items-center gap-3 text-ink font-semibold text-sm"
className="group inline-flex items-center min-h-6 gap-3 text-ink font-semibold text-sm"
>
<ArrowRight className="w-4 h-5 transition-transform duration-300 group-hover:translate-x-2 text-text-secondary group-hover:text-brand" />
<ArrowRight className="w-4 h-5 transition-transform duration-300 group-hover:translate-x-2 text-text-secondary group-hover:text-brand-ink" />
</StaticLink>
</ScrollReveal>
</div>
@@ -523,21 +523,21 @@ function InsightsSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
className="group flex flex-col h-full bg-bg-primary p-8 sm:p-10 md:p-12 transition-colors duration-300 hover:bg-bg-secondary"
>
<div className="flex items-center justify-between mb-8">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
{insight.tag}
</span>
{insight.date && (
<span className="text-xs text-text-muted tabular-nums">{insight.date}</span>
)}
</div>
<h3 className="text-xl lg:text-2xl font-bold text-ink mb-4 leading-[1.25] group-hover:text-brand transition-colors duration-300">
<h3 className="text-xl lg:text-2xl font-bold text-ink mb-4 leading-[1.25] group-hover:text-brand-ink transition-colors duration-300">
{insight.title}
</h3>
<p className="text-text-secondary leading-relaxed mb-8 text-sm flex-1">
{insight.desc}
</p>
<div className="pt-6 border-t border-border-primary">
<span className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand transition-colors">
<span className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand-ink transition-colors">
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-1" />
</span>
@@ -606,7 +606,7 @@ function ServicesSection({ services, pageCopy }: { services?: Record<string, any
</div>
)}
<div className="mt-auto pt-2">
<div className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand transition-colors">
<div className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand-ink transition-colors">
<span></span>
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-1" />
</div>
@@ -642,12 +642,12 @@ function FounderQuoteSection({ pageCopy }: { pageCopy?: HomePageCopy | null }) {
<div className="bg-bg-primary/95 rounded-2xl p-8 sm:p-10 md:p-12 max-w-3xl mx-auto shadow-sm border border-brand/10">
<div className="flex items-center justify-center gap-3 mb-8">
<div className="w-10 h-px bg-brand/40" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
{eyebrow}
</span>
<div className="w-10 h-px bg-brand/40" />
</div>
<Quote className="w-10 h-10 mx-auto mb-8 text-brand/40" aria-hidden="true" />
<Quote className="w-10 h-10 mx-auto mb-8 text-brand-ink/40" aria-hidden="true" />
<blockquote className="text-base sm:text-xl md:text-[28px] font-medium text-ink leading-[1.7] mb-10 border-l-0 pl-0 m-0 max-w-[640px] mx-auto whitespace-pre-line">
{quoteText}
</blockquote>
@@ -693,7 +693,7 @@ function CasesSection({ cases, pageCopy }: { cases?: Record<string, any>[]; page
<ScrollReveal>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
{casesEyebrow}
</span>
</div>
@@ -705,10 +705,10 @@ function CasesSection({ cases, pageCopy }: { cases?: Record<string, any>[]; page
</p>
<StaticLink
href="/contact"
className="group inline-flex items-center gap-3 text-ink font-semibold text-sm"
className="group inline-flex items-center min-h-6 gap-3 text-ink font-semibold text-sm"
>
<ArrowRight className="w-4 h-5 transition-transform duration-300 group-hover:translate-x-2 text-text-secondary group-hover:text-brand" />
<ArrowRight className="w-4 h-5 transition-transform duration-300 group-hover:translate-x-2 text-text-secondary group-hover:text-brand-ink" />
</StaticLink>
</ScrollReveal>
<ScrollReveal delay={0.15}>
@@ -775,10 +775,10 @@ function CasesSection({ cases, pageCopy }: { cases?: Record<string, any>[]; page
<ScrollReveal delay={0.1}>
<StaticLink
href="/cases"
className="group inline-flex items-center gap-3 text-ink font-semibold text-sm"
className="group inline-flex items-center min-h-6 gap-3 text-ink font-semibold text-sm"
>
<ArrowRight className="w-4 h-5 transition-transform duration-300 group-hover:translate-x-2 text-text-secondary group-hover:text-brand" />
<ArrowRight className="w-4 h-5 transition-transform duration-300 group-hover:translate-x-2 text-text-secondary group-hover:text-brand-ink" />
</StaticLink>
</ScrollReveal>
</div>
@@ -879,7 +879,7 @@ function CasesSection({ cases, pageCopy }: { cases?: Record<string, any>[]; page
<div key={j}>
<div className={cn(
'text-xl sm:text-2xl font-black leading-none mb-2',
j === 0 ? 'text-brand' : 'text-ink'
j === 0 ? 'text-brand-ink' : 'text-ink'
)}>
{metric.value}
</div>
@@ -891,7 +891,7 @@ function CasesSection({ cases, pageCopy }: { cases?: Record<string, any>[]; page
</div>
<div className="mt-auto pt-4 border-t border-border-primary">
<div className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand transition-colors">
<div className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand-ink transition-colors">
<span></span>
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-1" />
</div>
@@ -920,7 +920,7 @@ function NewsSection({ news, pageCopy }: { news?: NewsItem[]; pageCopy?: HomePag
<ScrollReveal className="md:max-w-3xl">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
{eyebrow}
</span>
</div>
@@ -931,10 +931,10 @@ function NewsSection({ news, pageCopy }: { news?: NewsItem[]; pageCopy?: HomePag
<ScrollReveal delay={0.1}>
<StaticLink
href="/news"
className="group inline-flex items-center gap-3 text-ink font-semibold text-sm"
className="group inline-flex items-center min-h-6 gap-3 text-ink font-semibold text-sm"
>
{ctaLabel}
<ArrowRight className="w-4 h-5 transition-transform duration-300 group-hover:translate-x-2 text-text-secondary group-hover:text-brand" />
<ArrowRight className="w-4 h-5 transition-transform duration-300 group-hover:translate-x-2 text-text-secondary group-hover:text-brand-ink" />
</StaticLink>
</ScrollReveal>
</div>
@@ -947,7 +947,7 @@ function NewsSection({ news, pageCopy }: { news?: NewsItem[]; pageCopy?: HomePag
className="group bain-card block p-8 sm:p-9 h-full flex flex-col"
>
<div className="flex items-center gap-3 mb-6">
<Badge variant="outline" className="text-xs border-brand/30 text-brand">
<Badge variant="outline" className="text-xs border-brand/30 text-brand-ink">
{item.category}
</Badge>
<span className="flex items-center gap-1.5 text-xs text-text-muted">
@@ -955,14 +955,14 @@ function NewsSection({ news, pageCopy }: { news?: NewsItem[]; pageCopy?: HomePag
{item.date}
</span>
</div>
<h3 className="text-lg lg:text-xl font-bold text-ink mb-4 leading-[1.3] line-clamp-2 group-hover:text-brand transition-colors duration-300">
<h3 className="text-lg lg:text-xl font-bold text-ink mb-4 leading-[1.3] line-clamp-2 group-hover:text-brand-ink transition-colors duration-300">
{item.title}
</h3>
<p className="text-sm text-text-secondary leading-relaxed mb-6 line-clamp-2 flex-1">
{item.excerpt}
</p>
<div className="pt-4 border-t border-border-primary">
<span className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand transition-colors">
<span className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand-ink transition-colors">
<ArrowRight className="w-4 h-4 transition-transform duration-300 group-hover:translate-x-1" />
</span>
@@ -35,7 +35,7 @@ export function MethodologyContent({ data }: MethodologyContentProps) {
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, delay: 0.1, ease: EASE_OUT }}
className="inline-flex items-center gap-2 px-3 py-1.5 text-xs font-bold text-brand bg-brand/10 mb-8"
className="inline-flex items-center gap-2 px-3 py-1.5 text-xs font-bold text-brand-ink bg-brand/10 mb-8"
>
{heroSubtitle}
</motion.div>
@@ -66,7 +66,7 @@ export function MethodologyContent({ data }: MethodologyContentProps) {
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10">
<ScrollReveal className="max-w-3xl mb-14 sm:mb-16">
<h2 className="text-3xl sm:text-4xl md:text-5xl font-extrabold text-ink tracking-tight leading-tight">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
<p className="text-text-secondary text-lg mt-6 leading-relaxed">
@@ -87,12 +87,12 @@ export function MethodologyContent({ data }: MethodologyContentProps) {
className="relative overflow-hidden bg-bg-elevated border border-border-primary transition-all duration-300 hover:-translate-y-1 hover:shadow-lg"
>
<div className="p-7 md:p-8">
<div className="w-11 h-11 rounded-full flex items-center justify-center mb-5 text-base font-bold bg-brand/10 text-brand">
<div className="w-11 h-11 rounded-full flex items-center justify-center mb-5 text-base font-bold bg-brand/10 text-brand-ink">
{phase.number ?? idx + 1}
</div>
<h3 className="text-lg font-bold text-ink mb-1">{phase.title}</h3>
{phase.subtitle && (
<p className="text-xs text-brand font-medium mb-3">{phase.subtitle}</p>
<p className="text-xs text-brand-ink font-medium mb-3">{phase.subtitle}</p>
)}
{phase.description && (
<p className="text-sm text-text-secondary leading-relaxed mb-5">{phase.description}</p>
@@ -104,7 +104,7 @@ export function MethodologyContent({ data }: MethodologyContentProps) {
<ul className="space-y-1.5">
{phase.activities.map((activity, i) => (
<li key={i} className="flex items-start gap-2 text-xs text-text-secondary">
<CheckCircle2 className="w-3.5 h-3.5 text-brand mt-0.5 shrink-0" />
<CheckCircle2 className="w-3.5 h-3.5 text-brand-ink mt-0.5 shrink-0" />
{activity}
</li>
))}
@@ -147,7 +147,7 @@ export function MethodologyContent({ data }: MethodologyContentProps) {
<div className="max-w-container mx-auto px-6 lg:px-10">
<ScrollReveal className="text-center max-w-3xl mx-auto">
<h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold text-ink tracking-tight leading-tight mb-6 sm:mb-8">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
<p className="text-xl text-text-secondary mb-12 max-w-2xl mx-auto leading-relaxed">
穿
+6 -5
View File
@@ -42,13 +42,13 @@ function NewsCard({ newsItem, index }: { newsItem: NewsItem; index: number }) {
</div>
) : (
<div className="aspect-video bg-gradient-to-br from-brand/[0.08] to-bg-secondary flex items-center justify-center">
<Newspaper className="w-12 h-12 text-brand/30" />
<Newspaper className="w-12 h-12 text-brand-ink/30" />
</div>
)}
<div className="p-6 sm:p-7 lg:p-8">
<div className="flex items-center gap-3 mb-4">
<Badge variant="outline" className="text-xs border-brand/30 text-brand">
<Badge variant="outline" className="text-xs border-brand/30 text-brand-ink">
{newsItem.category}
</Badge>
<div className="flex items-center gap-1.5 text-xs text-text-muted">
@@ -57,7 +57,7 @@ function NewsCard({ newsItem, index }: { newsItem: NewsItem; index: number }) {
</div>
</div>
<h2 className="text-lg sm:text-xl font-semibold text-ink mb-3 line-clamp-2 group-hover:text-brand transition-colors duration-300 leading-snug">
<h2 className="text-lg sm:text-xl font-semibold text-ink mb-3 line-clamp-2 group-hover:text-brand-ink transition-colors duration-300 leading-snug">
{newsItem.title}
</h2>
@@ -65,7 +65,7 @@ function NewsCard({ newsItem, index }: { newsItem: NewsItem; index: number }) {
{newsItem.excerpt}
</p>
<div className="flex items-center text-brand text-sm font-medium">
<div className="flex items-center text-brand-ink text-sm font-medium">
<ArrowRight className="ml-2 w-4 h-4 group-hover:translate-x-1 transition-transform duration-300" />
</div>
@@ -131,7 +131,7 @@ export default function NewsContentV3({ news, pageCopy }: { news?: NewsItem[]; p
<ScrollReveal delay={0.1}>
<h1 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl xl:text-8xl font-bold leading-[0.92] tracking-tighter mb-10 sm:mb-12 md:mb-16">
{heroTitleLines.map((line, i) => (
<span key={i} className={i === heroTitleLines.length - 1 ? 'block mt-4 text-brand' : 'block'}>
<span key={i} className={i === heroTitleLines.length - 1 ? 'block mt-4 text-brand-ink' : 'block'}>
{line}
</span>
))}
@@ -171,6 +171,7 @@ export default function NewsContentV3({ news, pageCopy }: { news?: NewsItem[]; p
<Input
type="text"
placeholder="搜索新闻..."
aria-label="搜索新闻"
value={searchQuery}
onChange={handleSearchChange}
className="pl-12 h-12 bg-bg-elevated border-border-primary text-ink placeholder:text-text-muted focus:border-brand/50"
@@ -32,16 +32,16 @@ function RelatedNewsCard({ news, index }: { news: NewsItem; index: number }) {
/>
) : (
<div className="w-full h-full bg-gradient-to-br from-brand/[0.08] to-bg-secondary flex items-center justify-center">
<Newspaper className="w-10 h-10 text-brand/30" />
<Newspaper className="w-10 h-10 text-brand-ink/30" />
</div>
)}
</div>
<div className="p-5 sm:p-6">
<Badge variant="outline" className="mb-3 text-xs border-brand/30 text-brand">
<Badge variant="outline" className="mb-3 text-xs border-brand/30 text-brand-ink">
{news.category}
</Badge>
<h3 className="text-base font-semibold text-ink mb-2 line-clamp-2 group-hover:text-brand transition-colors duration-300 leading-snug">
<h3 className="text-base font-semibold text-ink mb-2 line-clamp-2 group-hover:text-brand-ink transition-colors duration-300 leading-snug">
{news.title}
</h3>
<p className="text-sm text-text-secondary line-clamp-2 leading-relaxed">{news.excerpt}</p>
@@ -65,7 +65,7 @@ export default function NewsDetailContentV3({ news, relatedNews = [] }: NewsDeta
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10">
<ScrollReveal>
<nav aria-label="breadcrumb" className="flex items-center gap-2 text-sm text-text-muted mb-8 sm:mb-10">
<StaticLink href="/news" className="hover:text-brand transition-colors duration-300">
<StaticLink href="/news" className="hover:text-brand-ink transition-colors duration-300">
</StaticLink>
<span>/</span>
@@ -74,7 +74,7 @@ export default function NewsDetailContentV3({ news, relatedNews = [] }: NewsDeta
</ScrollReveal>
<ScrollReveal delay={0.1} className="max-w-4xl">
<Badge variant="outline" className="mb-6 border-brand/30 text-brand text-sm">
<Badge variant="outline" className="mb-6 border-brand/30 text-brand-ink text-sm">
{news.category}
</Badge>
@@ -109,7 +109,7 @@ export default function NewsDetailContentV3({ news, relatedNews = [] }: NewsDeta
</div>
) : (
<div className="aspect-video bg-gradient-to-br from-brand/[0.08] to-bg-secondary mb-10 sm:mb-12 flex items-center justify-center border border-border-primary">
<Newspaper className="w-20 h-20 text-brand/20" />
<Newspaper className="w-20 h-20 text-brand-ink/20" />
</div>
)}
@@ -26,7 +26,7 @@ function SectionLabel({ children, className = '' }: { children: React.ReactNode;
return (
<div className={cn('flex items-center gap-5 mb-7', className)}>
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
{children}
</span>
<div className="w-14 h-px bg-brand" />
@@ -130,7 +130,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
<section className="relative pt-32 pb-32 lg:pt-40 lg:pb-40 overflow-hidden">
<div className="max-w-container mx-auto px-6 lg:px-10 relative z-10">
<ScrollReveal>
<Badge variant="outline" className="mb-8 border-brand/30 text-brand text-sm px-4 py-2">
<Badge variant="outline" className="mb-8 border-brand/30 text-brand-ink text-sm px-4 py-2">
</Badge>
</ScrollReveal>
@@ -139,7 +139,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
<h1 className="text-4xl md:text-5xl lg:text-6xl xl:text-7xl font-bold tracking-tight leading-[1.1] max-w-4xl text-ink">
ERP系统
<br />
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h1>
</ScrollReveal>
@@ -172,7 +172,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
<SectionLabel>Pain Points</SectionLabel>
<h2 className="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight leading-tight text-ink">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
</ScrollReveal>
@@ -188,7 +188,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
<div className="absolute top-0 left-0 right-0 h-1 bg-brand scale-x-0 group-hover:scale-x-100 transition-transform duration-150 origin-left" />
<div className="w-14 h-14 bg-brand/10 border border-brand/20 flex items-center justify-center mb-6">
<item.icon className="w-7 h-7 text-brand" />
<item.icon className="w-7 h-7 text-brand-ink" />
</div>
<h3 className="text-xl font-semibold mb-3 text-ink">{item.title}</h3>
@@ -206,7 +206,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
<SectionLabel>Upgrade Benefits</SectionLabel>
<h2 className="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight leading-tight text-ink">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
<p className="mt-6 text-lg text-text-secondary leading-relaxed">
@@ -223,10 +223,10 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
className="text-center p-8 border border-border-primary bg-bg-elevated hover:border-brand/30 hover:bg-bg-secondary transition-all duration-150 group"
>
<div className="w-12 h-12 mx-auto mb-6 bg-brand/10 border border-brand/20 flex items-center justify-center group-hover:scale-110 transition-transform duration-300">
<item.icon className="w-6 h-6 text-brand" />
<item.icon className="w-6 h-6 text-brand-ink" />
</div>
<div className="text-4xl md:text-5xl font-bold text-brand mb-3">{item.value}</div>
<h4 className="text-base font-semibold mb-2 text-ink">{item.title}</h4>
<div className="text-4xl md:text-5xl font-bold text-brand-ink mb-3">{item.value}</div>
<h3 className="text-base font-semibold mb-2 text-ink">{item.title}</h3>
<p className="text-sm text-text-muted leading-relaxed">{item.desc}</p>
</div>
))}
@@ -243,7 +243,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
<SectionLabel>Core Modules</SectionLabel>
<h2 className="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight leading-tight text-ink">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
</ScrollReveal>
@@ -260,7 +260,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
<div className="flex items-start gap-4">
<div className="w-12 h-12 bg-brand/10 border border-brand/20 flex items-center justify-center shrink-0">
<item.icon className="w-6 h-6 text-brand" />
<item.icon className="w-6 h-6 text-brand-ink" />
</div>
<div className="mt-3.5">
<h3 className="text-lg font-semibold mb-2 text-ink">{item.title}</h3>
@@ -280,7 +280,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
<SectionLabel>Upgrade Process</SectionLabel>
<h2 className="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight leading-tight text-ink">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
<p className="mt-6 text-lg text-text-secondary leading-relaxed">
@@ -296,10 +296,11 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
>
{UPGRADE_PROCESS.map((item, index) => (
<div key={index} className="relative">
<div className="text-6xl font-bold text-brand/10 mb-4">{item.step}</div>
{/* 大号步骤数字是水印装饰(两主题下都是 10% 透明度),步骤信息由下方标题/描述承载 */}
<div aria-hidden="true" className="text-6xl font-bold text-brand-ink/10 mb-4">{item.step}</div>
<h3 className="text-xl font-semibold mb-3 text-ink">{item.title}</h3>
<p className="text-text-secondary mb-4 leading-relaxed">{item.desc}</p>
<div className="inline-flex items-center gap-2 text-sm text-brand">
<div className="inline-flex items-center gap-2 text-sm text-brand-ink">
<Clock className="w-4 h-4" />
{item.duration}
</div>
@@ -319,7 +320,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
<SectionLabel className="justify-center">Case Study</SectionLabel>
<h2 className="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight leading-tight text-ink">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
</ScrollReveal>
<ScrollReveal delay={0.1}>
@@ -337,7 +338,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
<SectionLabel className="justify-center">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
Security & Compliance
</span>
<div className="w-14 h-px bg-brand" />
@@ -345,7 +346,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
</SectionLabel>
<h2 className="text-3xl md:text-4xl lg:text-5xl font-bold tracking-tight leading-tight text-ink">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
</ScrollReveal>
@@ -360,7 +361,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
className="group text-center p-8 border border-border-primary bg-bg-elevated hover:border-brand/30 hover:bg-bg-secondary transition-all duration-150 min-w-[200px]"
>
<div className="w-16 h-16 mx-auto mb-4 bg-brand/10 border border-brand/20 flex items-center justify-center group-hover:scale-110 transition-transform duration-300">
<Shield className="w-8 h-8 text-brand" />
<Shield className="w-8 h-8 text-brand-ink" />
</div>
<h4 className="text-base font-semibold mb-1 text-ink">{cert.name}</h4>
<p className="text-sm text-text-muted">{cert.issuer}</p>
@@ -384,7 +385,7 @@ export default function ErpUpgradeContentV2({ item }: ErpUpgradeContentV2Props)
<SectionLabel className="justify-center">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
Get Started
</span>
<div className="w-14 h-px bg-brand" />
@@ -35,11 +35,11 @@ function DetailHero({ product }: DetailHeroProps) {
transition={{ duration: 0.3, ease: EASE_OUT }}
className="flex items-center gap-4 mb-8"
>
<div className="w-16 h-16 rounded-2xl bg-brand-soft flex items-center justify-center text-brand">
<div className="w-16 h-16 rounded-2xl bg-brand-soft flex items-center justify-center text-brand-ink">
{productIcon}
</div>
<div>
<span className="px-3 py-1.5 text-xs font-bold text-brand bg-brand-soft/50">
<span className="px-3 py-1.5 text-xs font-bold text-brand-ink bg-brand-soft/50">
{product.category}
</span>
<div className="flex items-center gap-3 mt-2">
@@ -117,7 +117,7 @@ function FeaturesSection({ features }: FeaturesSectionProps) {
<SectionLabel className="justify-center">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
</span>
<div className="w-14 h-px bg-brand" />
@@ -139,7 +139,7 @@ function FeaturesSection({ features }: FeaturesSectionProps) {
className="group relative p-8 bg-bg-primary hover:bg-bg-secondary transition-all duration-150"
>
<div className="flex items-center gap-5">
<div className="w-10 h-10 rounded-xl bg-brand-soft flex items-center justify-center text-brand shrink-0">
<div className="w-10 h-10 rounded-xl bg-brand-soft flex items-center justify-center text-brand-ink shrink-0">
<Check className="w-5 h-5" />
</div>
<p className="text-lg text-ink font-medium leading-relaxed">{feature}</p>
@@ -182,7 +182,7 @@ function BenefitsSection({ benefits }: BenefitsSectionProps) {
className="group relative p-8 bg-bg-primary hover:bg-bg-secondary transition-all duration-150"
>
<div className="flex items-center gap-6">
<div className="w-12 h-12 rounded-2xl bg-brand-soft/50 flex items-center justify-center text-brand shrink-0">
<div className="w-12 h-12 rounded-2xl bg-brand-soft/50 flex items-center justify-center text-brand-ink shrink-0">
<TrendingUp className="w-6 h-6" />
</div>
<p className="text-xl text-ink font-semibold leading-relaxed">{benefit}</p>
@@ -212,7 +212,7 @@ function ProcessSection({ process }: ProcessSectionProps) {
<SectionLabel className="justify-center">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
</span>
<div className="w-14 h-px bg-brand" />
@@ -235,7 +235,7 @@ function ProcessSection({ process }: ProcessSectionProps) {
className="group relative text-center p-8 bg-bg-primary hover:bg-bg-secondary transition-all duration-150"
>
<div className="relative z-10 w-20 h-20 rounded-3xl bg-bg-secondary border border-border-primary group-hover:border-brand/50 flex items-center justify-center mx-auto mb-8 transition-all duration-150">
<span className="text-3xl font-bold text-brand">{idx + 1}</span>
<span className="text-3xl font-bold text-brand-ink">{idx + 1}</span>
</div>
<p className="text-lg text-ink font-medium leading-relaxed">{step}</p>
@@ -268,7 +268,7 @@ function CTASection({ product }: CTASectionProps) {
<div className="flex justify-center mb-7">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
使
</span>
<div className="w-14 h-px bg-brand" />
@@ -277,7 +277,7 @@ function CTASection({ product }: CTASectionProps) {
<h2 className="text-4xl md:text-5xl lg:text-6xl font-bold text-ink tracking-tight leading-tight mb-8">
{product.title} <br />
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
<p className="text-xl text-text-secondary mb-12 max-w-2xl mx-auto leading-relaxed">
@@ -299,7 +299,7 @@ function CTASection({ product }: CTASectionProps) {
使 ERP
<StaticLink
href="/products/erp-upgrade"
className="inline-flex items-center gap-1 font-medium text-brand hover:underline py-0.5"
className="inline-flex items-center gap-1 font-medium text-brand-ink hover:underline py-0.5"
>
ERP
<ArrowRight className="w-4 h-4" />
@@ -102,7 +102,7 @@ function HeroSection({ pageCopy }: { pageCopy?: PageCopy | null }) {
<div className="block">{heroTitle1}</div>
<div className="block mt-5">
<span className="relative inline-block">
<span className="text-brand font-extrabold">{heroTitle2}</span>
<span className="text-brand-ink font-extrabold">{heroTitle2}</span>
<motion.span
className="absolute -bottom-3 left-0 w-full h-[3px] bg-brand"
style={{ transformOrigin: 'left' }}
@@ -148,7 +148,7 @@ function HeroSection({ pageCopy }: { pageCopy?: PageCopy | null }) {
<StatItem value={100} suffix="%" label="自研率" start={isInView} delay={0.2} />
<div>
<div className="text-4xl lg:text-5xl font-bold text-ink tracking-tight leading-none mb-2">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</div>
<div className="text-sm text-text-muted"></div>
</div>
@@ -188,7 +188,7 @@ function ProductCard({ product, size = 'small' }: { product: Product; size?: 'la
</h3>
</div>
<div className="flex items-center gap-2 shrink-0">
<span className="px-2 py-1 text-xs bg-brand/10 text-brand" aria-hidden="true">{bundleLabel}</span>
<span className="px-2 py-1 text-xs bg-brand/10 text-brand-ink" aria-hidden="true">{bundleLabel}</span>
{isExternal && (
<span className="inline-flex items-center gap-1 px-2 py-1 text-xs border border-border-primary text-text-secondary">
<ArrowUpRight className="w-3 h-3" aria-hidden="true" />
@@ -240,7 +240,7 @@ function BundleOverview({ products, pageCopy }: { products: Product[]; pageCopy?
<ScrollReveal className="max-w-3xl mb-12 sm:mb-16 md:mb-20">
<h2 className="text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-extrabold text-ink tracking-tight leading-[0.95] mb-6">
{bundleTitleLines.map((line, i) => (
<span key={i} className={i === bundleTitleLines.length - 1 ? 'block text-brand' : 'block'}>
<span key={i} className={i === bundleTitleLines.length - 1 ? 'block text-brand-ink' : 'block'}>
{line}
</span>
))}
@@ -253,11 +253,11 @@ function BundleOverview({ products, pageCopy }: { products: Product[]; pageCopy?
<div className="grid lg:grid-cols-2 gap-px bg-border-primary">
<div className="bg-bg-secondary p-8 sm:p-10 lg:p-12">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-10 rounded-xl bg-brand-soft flex items-center justify-center text-brand">
<div className="w-10 h-10 rounded-xl bg-brand-soft flex items-center justify-center text-brand-ink">
<Package className="w-5 h-5" />
</div>
<h3 className="text-xl font-bold text-ink"></h3>
<span className="px-2 py-1 text-xs bg-brand/10 text-brand">6 </span>
<span className="px-2 py-1 text-xs bg-brand/10 text-brand-ink">6 </span>
</div>
<p className="text-sm text-text-secondary leading-relaxed mb-6">
@@ -320,7 +320,7 @@ function EnterpriseProductsSection({ products }: { products: Product[] }) {
<div className="flex flex-col lg:flex-row lg:items-end lg:justify-between gap-8 sm:gap-10 md:gap-12 mb-16 sm:mb-20 md:mb-20">
<ScrollReveal className="lg:max-w-3xl">
<div className="flex items-center gap-5 mb-8">
<div className="w-16 h-16 rounded-2xl bg-brand-soft flex items-center justify-center text-brand">
<div className="w-16 h-16 rounded-2xl bg-brand-soft flex items-center justify-center text-brand-ink">
<Package className="w-8 h-8" />
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold text-ink tracking-tight leading-tight">
@@ -433,14 +433,14 @@ function SuiteCombosSection({ products }: { products: Product[] }) {
{comboProducts.map((p, pIdx) => p && (
<div
key={pIdx}
className="w-10 h-10 rounded-xl bg-brand-soft flex items-center justify-center text-brand border-2 border-white"
className="w-10 h-10 rounded-xl bg-brand-soft flex items-center justify-center text-brand-ink border-2 border-white"
style={{ zIndex: 10 - pIdx }}
>
{PRODUCT_ICONS[p.title] || <Package className="w-5 h-5" />}
</div>
))}
</div>
<span className="px-3 py-1 text-[11px] font-bold text-brand bg-brand-soft/50">
<span className="px-3 py-1 text-[11px] font-bold text-brand-ink bg-brand-soft/50">
</span>
</div>
@@ -454,7 +454,7 @@ function SuiteCombosSection({ products }: { products: Product[] }) {
</p>
<motion.div
className="inline-flex items-center gap-2.5 text-sm font-bold text-brand"
className="inline-flex items-center gap-2.5 text-sm font-bold text-brand-ink"
whileHover={{ x: 6 }}
transition={EASE_SPRING}
>
@@ -483,7 +483,7 @@ function CTASection({ pageCopy }: { pageCopy?: PageCopy | null }) {
<ScrollReveal className="text-center max-w-3xl mx-auto">
<h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold text-ink tracking-tight leading-tight mb-6 sm:mb-8">
{ctaTitleLines.map((line, i) => (
<span key={i} className={i === ctaTitleLines.length - 1 ? 'block text-brand' : 'block'}>
<span key={i} className={i === ctaTitleLines.length - 1 ? 'block text-brand-ink' : 'block'}>
{line}
</span>
))}
@@ -147,7 +147,7 @@ export function StandaloneProductClient({ item }: StandaloneProductClientProps)
transition={{ duration: 0.3, delay: index * 0.05 }}
className="flex items-start gap-3"
>
<CheckCircle2 className="mt-0.5 h-5 w-5 shrink-0 text-brand" />
<CheckCircle2 className="mt-0.5 h-5 w-5 shrink-0 text-brand-ink" />
<span className="text-sm leading-relaxed text-text-secondary">{feature}</span>
</motion.li>
))}
@@ -171,7 +171,7 @@ export function StandaloneProductClient({ item }: StandaloneProductClientProps)
className="mb-10"
>
<div className="flex items-center gap-3 mb-4">
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-brand-soft text-brand">
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-brand-soft text-brand-ink">
<Gauge className="h-5 w-5" />
</div>
<h2 className="text-2xl font-bold text-ink"></h2>
@@ -192,7 +192,7 @@ export function StandaloneProductClient({ item }: StandaloneProductClientProps)
className="rounded-lg border border-border-primary bg-bg-primary p-5"
>
<div className="mb-2 text-sm text-text-muted">{param.name}</div>
<div className="mb-2 text-2xl font-bold text-brand">{param.value}</div>
<div className="mb-2 text-2xl font-bold text-brand-ink">{param.value}</div>
{param.description && (
<div className="text-sm leading-relaxed text-text-secondary">{param.description}</div>
)}
@@ -214,7 +214,7 @@ export function StandaloneProductClient({ item }: StandaloneProductClientProps)
className="mb-10"
>
<div className="flex items-center gap-3 mb-4">
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-brand-soft text-brand">
<div className="flex h-10 w-10 items-center justify-center rounded-xl bg-brand-soft text-brand-ink">
<FileCheck className="h-5 w-5" />
</div>
<h2 className="text-2xl font-bold text-ink"></h2>
@@ -235,7 +235,7 @@ export function StandaloneProductClient({ item }: StandaloneProductClientProps)
className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 rounded-lg border border-border-primary bg-bg-secondary p-5"
>
<div className="flex items-start gap-4">
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-bg-primary text-brand">
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-bg-primary text-brand-ink">
<FileCheck className="h-5 w-5" />
</div>
<div>
@@ -27,7 +27,7 @@ function DetailHero({ service }: { service: Service }) {
<div className="block">{service.title}</div>
<div className="block mt-4 sm:mt-6">
<span className="relative inline-block">
<span className="relative text-brand font-black">
<span className="relative text-brand-ink font-black">
{firstBenefit}
<motion.span
className="absolute -bottom-2 left-0 w-full h-[3px] bg-brand"
@@ -57,7 +57,7 @@ function DetailHero({ service }: { service: Service }) {
className="grid grid-cols-3 gap-8 mb-12 sm:mb-16 max-w-xl"
>
<div>
<div className="text-3xl sm:text-4xl font-black text-brand tracking-tight leading-none mb-2">
<div className="text-3xl sm:text-4xl font-black text-brand-ink tracking-tight leading-none mb-2">
10+
</div>
<div className="text-sm text-text-muted"></div>
@@ -131,7 +131,7 @@ function OverviewSection({ service }: { service: Service }) {
key={i}
className="inline-flex items-center gap-2 px-4 py-2 text-sm border border-border-primary text-ink"
>
<CheckCircle2 className="w-4 h-4 shrink-0 text-brand" />
<CheckCircle2 className="w-4 h-4 shrink-0 text-brand-ink" />
<span className="font-medium">{benefit}</span>
</div>
))}
@@ -177,8 +177,8 @@ function FeaturesSection({ service }: { service: Service }) {
className="group relative p-8 sm:p-10 transition-all duration-150 hover:bg-bg-secondary hover:shadow-lg hover:-translate-y-1 bg-bg-primary"
>
<div className="relative z-10">
<Icon className="w-8 h-8 mb-6 text-brand" />
<h3 className="text-lg sm:text-xl font-bold mb-3 text-ink group-hover:text-brand transition-colors duration-300">
<Icon className="w-8 h-8 mb-6 text-brand-ink" />
<h3 className="text-lg sm:text-xl font-bold mb-3 text-ink group-hover:text-brand-ink transition-colors duration-300">
{desc ? title : feature.slice(0, 10)}
</h3>
<p className="text-sm leading-relaxed text-text-secondary">
@@ -234,7 +234,7 @@ function ProcessSection({ service }: { service: Service }) {
className="w-2 h-2 rounded-full mb-6"
style={{ backgroundColor: index === 0 ? '#C41E3A' : 'var(--color-border-primary)' }}
/>
<h3 className="text-lg font-bold mb-2 text-ink group-hover:text-brand transition-colors duration-300">
<h3 className="text-lg font-bold mb-2 text-ink group-hover:text-brand-ink transition-colors duration-300">
{desc ? title : step.slice(0, 6)}
</h3>
<p className="text-sm leading-relaxed text-text-secondary">
@@ -93,7 +93,7 @@ function HeroSection({ pageCopy }: { pageCopy?: PageCopy | null }) {
<div className="block">{heroTitle1}</div>
<div className="block mt-4 sm:mt-6">
<span className="relative inline-block">
<span className="relative text-brand font-black">
<span className="relative text-brand-ink font-black">
{heroTitle2}
<motion.span
className="absolute -bottom-2 left-0 w-full h-[3px] bg-brand"
@@ -143,19 +143,19 @@ function HeroSection({ pageCopy }: { pageCopy?: PageCopy | null }) {
>
<div>
<div className="text-3xl sm:text-4xl font-black text-ink tracking-tight leading-none mb-2">
4<span className="text-brand"></span>
4<span className="text-brand-ink"></span>
</div>
<div className="text-sm text-text-muted"></div>
</div>
<div>
<div className="text-3xl sm:text-4xl font-black text-ink tracking-tight leading-none mb-2">
3<span className="text-brand"></span>
3<span className="text-brand-ink"></span>
</div>
<div className="text-sm text-text-muted"></div>
</div>
<div>
<div className="text-3xl sm:text-4xl font-black text-ink tracking-tight leading-none mb-2">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</div>
<div className="text-sm text-text-muted"></div>
</div>
@@ -216,7 +216,7 @@ function ServicesGridSection({ services, pageCopy }: { services?: Service[]; pag
className="group relative block p-8 sm:p-10 md:p-12 transition-all duration-300 hover:bg-bg-secondary hover:shadow-lg hover:-translate-y-1 bg-bg-primary border border-transparent hover:border-border-primary after:absolute after:bottom-0 after:left-0 after:h-0.5 after:w-full after:origin-left after:scale-x-0 after:bg-brand after:transition-transform after:duration-300 group-hover:after:scale-x-100"
>
<div className="relative z-10">
<h3 className="text-xl sm:text-2xl font-bold text-ink group-hover:text-brand transition-colors duration-300 mb-3">
<h3 className="text-xl sm:text-2xl font-bold text-ink group-hover:text-brand-ink transition-colors duration-300 mb-3">
{service.title}
</h3>
@@ -227,7 +227,7 @@ function ServicesGridSection({ services, pageCopy }: { services?: Service[]; pag
<ul className="space-y-2 mb-6">
{service.capabilities.map((cap) => (
<li key={cap} className="flex items-start gap-2 text-sm text-text-secondary">
<CheckCircle2 className="w-4 h-4 text-brand shrink-0 mt-0.5" />
<CheckCircle2 className="w-4 h-4 text-brand-ink shrink-0 mt-0.5" />
{cap}
</li>
))}
@@ -242,7 +242,7 @@ function ServicesGridSection({ services, pageCopy }: { services?: Service[]; pag
))}
</div>
<div className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand transition-colors duration-300">
<div className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand-ink transition-colors duration-300">
<span></span>
<ArrowUpRight className="w-4 h-4 group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-transform duration-300" />
</div>
@@ -313,7 +313,7 @@ function ProcessModesSection() {
className="group relative p-6 sm:p-7 border border-border-primary bg-bg-primary hover:bg-bg-secondary hover:border-brand/20 hover:shadow-md transition-all duration-300"
>
<div className="relative z-10">
<h3 className="text-xl font-bold text-ink mb-3 group-hover:text-brand transition-colors duration-300">
<h3 className="text-xl font-bold text-ink mb-3 group-hover:text-brand-ink transition-colors duration-300">
{mode.title}
</h3>
<p className="text-text-secondary leading-relaxed text-sm sm:text-[15px] mb-4">{mode.description}</p>
@@ -48,11 +48,11 @@ function DetailHero({ solution }: DetailHeroProps) {
transition={{ duration: 0.3, ease: EASE_OUT }}
className="flex items-center gap-4 mb-8"
>
<div className="w-16 h-16 rounded-2xl bg-brand-soft flex items-center justify-center text-brand">
<div className="w-16 h-16 rounded-2xl bg-brand-soft flex items-center justify-center text-brand-ink">
{industryIcon}
</div>
<div>
<span className="px-3 py-1.5 text-xs font-bold text-brand bg-brand-soft/50">
<span className="px-3 py-1.5 text-xs font-bold text-brand-ink bg-brand-soft/50">
{solution.industry}
</span>
<div className="text-text-muted text-sm mt-2">{solution.subtitle}</div>
@@ -126,7 +126,7 @@ function ChallengesSection({ challenges }: ChallengesSectionProps) {
>
<div className="absolute left-0 top-0 bottom-0 w-1 bg-brand scale-y-0 group-hover:scale-y-100 transition-transform duration-150 origin-top" />
<div className="flex items-start gap-6">
<div className="w-10 h-10 rounded-xl bg-brand-soft/50 flex items-center justify-center text-brand shrink-0 mt-0.5">
<div className="w-10 h-10 rounded-xl bg-brand-soft/50 flex items-center justify-center text-brand-ink shrink-0 mt-0.5">
<span className="text-lg font-bold">{idx + 1}</span>
</div>
<p className="text-lg text-ink leading-relaxed">{challenge}</p>
@@ -153,7 +153,7 @@ function SolutionsSection({ solutions }: SolutionsSectionProps) {
<SectionLabel className="justify-center">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
Solutions
</span>
<div className="w-14 h-px bg-brand" />
@@ -174,11 +174,11 @@ function SolutionsSection({ solutions }: SolutionsSectionProps) {
<div className="absolute top-0 left-0 right-0 h-1 bg-brand scale-x-0 group-hover:scale-x-100 transition-transform duration-150 origin-left" />
<div className="flex items-start gap-6">
<div className="w-14 h-14 rounded-2xl bg-brand-soft flex items-center justify-center text-brand shrink-0">
<div className="w-14 h-14 rounded-2xl bg-brand-soft flex items-center justify-center text-brand-ink shrink-0">
<Lightbulb className="w-7 h-7" />
</div>
<div>
<div className="text-xs font-bold text-brand mb-3 tracking-widest uppercase">
<div className="text-xs font-bold text-brand-ink mb-3 tracking-widest uppercase">
{idx + 1}
</div>
<p className="text-xl text-ink font-semibold leading-relaxed">{solution}</p>
@@ -208,7 +208,7 @@ function ValuePropositionSection({ valueProposition }: ValuePropositionProps) {
<SectionLabel className="justify-center">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
Value Proposition
</span>
<div className="w-14 h-px bg-brand" />
@@ -230,7 +230,7 @@ function ValuePropositionSection({ valueProposition }: ValuePropositionProps) {
>
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-1/3 h-1 bg-brand scale-x-0 group-hover:scale-x-100 transition-transform duration-150 origin-center" />
<div className="w-20 h-20 rounded-3xl bg-brand-soft flex items-center justify-center text-brand mx-auto mb-8">
<div className="w-20 h-20 rounded-3xl bg-brand-soft flex items-center justify-center text-brand-ink mx-auto mb-8">
{icon}
</div>
@@ -263,7 +263,7 @@ function SuiteCombinationSection({ suiteCombination, products }: SuiteCombinatio
<SectionLabel className="justify-center">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
Suite Combination
</span>
<div className="w-14 h-px bg-brand" />
@@ -283,11 +283,11 @@ function SuiteCombinationSection({ suiteCombination, products }: SuiteCombinatio
>
<div className="absolute top-0 left-0 right-0 h-1 bg-brand scale-x-0 group-hover:scale-x-100 transition-transform duration-150 origin-left" />
<div className="w-16 h-16 rounded-2xl bg-brand-soft flex items-center justify-center text-brand mx-auto mb-6">
<div className="w-16 h-16 rounded-2xl bg-brand-soft flex items-center justify-center text-brand-ink mx-auto mb-6">
<Package className="w-8 h-8" />
</div>
<div className="text-xs font-bold text-brand mb-2 tracking-widest uppercase">
<div className="text-xs font-bold text-brand-ink mb-2 tracking-widest uppercase">
</div>
<h3 className="text-xl font-bold text-ink mb-3">{product.title}</h3>
@@ -297,18 +297,18 @@ function SuiteCombinationSection({ suiteCombination, products }: SuiteCombinatio
</StaggerReveal>
<ScrollReveal delay={0.2} className="flex items-center justify-center lg:col-span-1 bg-bg-elevated">
<div className="w-20 h-20 rounded-full bg-brand-soft/30 border-2 border-brand/30 flex items-center justify-center text-brand font-bold text-xl">
<div className="w-20 h-20 rounded-full bg-brand-soft/30 border-2 border-brand/30 flex items-center justify-center text-brand-ink font-bold text-xl">
+
</div>
</ScrollReveal>
<ScrollReveal delay={0.3} className="lg:col-span-2">
<div className="group relative p-8 bg-brand-soft/10 hover:bg-bg-secondary transition-all duration-150 text-center h-full flex flex-col justify-center">
<div className="w-16 h-16 rounded-2xl bg-brand-soft flex items-center justify-center text-brand mx-auto mb-6">
<div className="w-16 h-16 rounded-2xl bg-brand-soft flex items-center justify-center text-brand-ink mx-auto mb-6">
<Users className="w-8 h-8" />
</div>
<div className="text-xs font-bold text-brand mb-2 tracking-widest uppercase">
<div className="text-xs font-bold text-brand-ink mb-2 tracking-widest uppercase">
</div>
<h3 className="text-xl font-bold text-ink mb-3"></h3>
@@ -321,7 +321,7 @@ function SuiteCombinationSection({ suiteCombination, products }: SuiteCombinatio
<ScrollReveal>
<div className="p-10 bg-bg-secondary text-center border border-border-primary">
<div className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand mb-4">
<div className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink mb-4">
</div>
<p className="text-xl lg:text-2xl text-ink leading-relaxed max-w-4xl mx-auto font-medium">
@@ -353,7 +353,7 @@ function CTASection({ solution }: CTASectionProps) {
<div className="flex justify-center mb-7">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
Get Started
</span>
<div className="w-14 h-px bg-brand" />
@@ -362,7 +362,7 @@ function CTASection({ solution }: CTASectionProps) {
<h2 className="text-4xl md:text-5xl lg:text-6xl font-bold text-ink tracking-tight leading-tight mb-8">
<br />
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
<p className="text-xl text-text-secondary mb-12 max-w-2xl mx-auto leading-relaxed">
@@ -41,7 +41,7 @@ function HeroSection({ pageCopy }: { pageCopy?: PageCopy | null }) {
<div className="block">{heroTitle1}</div>
<div className="block mt-4 sm:mt-6">
<span className="relative inline-block">
<span className="relative text-brand font-black">
<span className="relative text-brand-ink font-black">
{heroTitle2}
<motion.span
className="absolute -bottom-2 left-0 w-full h-[3px] bg-brand"
@@ -91,19 +91,19 @@ function HeroSection({ pageCopy }: { pageCopy?: PageCopy | null }) {
>
<div>
<div className="text-3xl sm:text-4xl font-black text-ink tracking-tight leading-none mb-2">
6<span className="text-brand"></span>
6<span className="text-brand-ink"></span>
</div>
<div className="text-sm text-text-muted"></div>
</div>
<div>
<div className="text-3xl sm:text-4xl font-black text-ink tracking-tight leading-none mb-2">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</div>
<div className="text-sm text-text-muted"></div>
</div>
<div>
<div className="text-3xl sm:text-4xl font-black text-ink tracking-tight leading-none mb-2">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</div>
<div className="text-sm text-text-muted"></div>
</div>
@@ -153,7 +153,7 @@ function SolutionCard({ solution, index, products, featured = false }: { solutio
<div className="grid grid-cols-2 gap-2 mb-4">
{solution.outcomes?.map((o) => (
<div key={o.label} className="p-2 bg-bg-secondary">
<div className="text-base font-bold text-brand">{o.value}</div>
<div className="text-base font-bold text-brand-ink">{o.value}</div>
<div className="text-xs text-text-muted">{o.label}</div>
</div>
))}
@@ -170,7 +170,7 @@ function SolutionCard({ solution, index, products, featured = false }: { solutio
</div>
</div>
<div className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand transition-colors duration-300 mt-6">
<div className="inline-flex items-center gap-2 text-sm font-semibold text-text-secondary group-hover:text-brand-ink transition-colors duration-300 mt-6">
<span></span>
<ArrowUpRight className="w-4 h-4 group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-transform duration-300" />
</div>
+12 -12
View File
@@ -76,7 +76,7 @@ function StrengthCard({ strength, index }: { strength: StrengthData; index: numb
<div className="p-8 sm:p-10">
<div className="flex items-center gap-4 mb-6">
<div className="w-12 h-12 flex items-center justify-center border border-brand/30 bg-brand/[0.08] text-brand">
<div className="w-12 h-12 flex items-center justify-center border border-brand/30 bg-brand/[0.08] text-brand-ink">
<Icon className="w-5 h-5" />
</div>
{/* 纯装饰序号:与右侧 h3 标题并列,无独立语义。
@@ -110,7 +110,7 @@ function CultureCard({ culture, index }: { culture: CultureData; index: number }
<div className="absolute top-0 left-0 right-0 h-1 bg-brand scale-x-0 group-hover:scale-x-100 transition-transform duration-150 origin-left" />
<div className="p-8 sm:p-10 lg:p-12">
<div className="w-16 h-16 mx-auto mb-6 flex items-center justify-center border border-brand/30 bg-brand/[0.08] text-brand">
<div className="w-16 h-16 mx-auto mb-6 flex items-center justify-center border border-brand/30 bg-brand/[0.08] text-brand-ink">
<Icon className="w-7 h-7" />
</div>
@@ -157,7 +157,7 @@ export default function TeamContentV3({ data }: { data: Record<string, unknown>
>
<span className="inline-flex items-center gap-2 px-3 py-1.5 bg-brand/[0.08] border border-brand/20 rounded-full">
<span className="w-1.5 h-1.5 rounded-full bg-brand" />
<span className="text-[13px] font-semibold text-brand tracking-[0.08em] uppercase">
<span className="text-[13px] font-semibold text-brand-ink tracking-[0.08em] uppercase">
{teamData.heroSubtitle || '核心团队'}
</span>
</span>
@@ -173,7 +173,7 @@ export default function TeamContentV3({ data }: { data: Record<string, unknown>
{(teamData.heroTitle || '').split('\n').map((line, i) => (
<span key={i}>
{i > 0 && <span className="block mt-4 sm:mt-6" />}
{i === 0 ? line : <span className="text-brand">{line}</span>}
{i === 0 ? line : <span className="text-brand-ink">{line}</span>}
</span>
))}
</motion.h1>
@@ -188,7 +188,7 @@ export default function TeamContentV3({ data }: { data: Record<string, unknown>
>
{stats.map((stat, i) => (
<div key={i} className="flex items-baseline gap-2">
<span className="text-3xl sm:text-4xl md:text-5xl font-black text-brand tabular-nums leading-none">
<span className="text-3xl sm:text-4xl md:text-5xl font-black text-brand-ink tabular-nums leading-none">
{stat.value}{stat.suffix}
</span>
<span className="text-sm text-text-muted whitespace-nowrap">
@@ -240,13 +240,13 @@ export default function TeamContentV3({ data }: { data: Record<string, unknown>
<ScrollReveal className="max-w-3xl mb-16 sm:mb-20">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.15em] font-medium text-brand">
<span className="text-[13px] tracking-[0.15em] font-medium text-brand-ink">
</span>
</div>
<h2 className="font-sans text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-ink tracking-tight leading-[1.05]">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
<p className="text-text-secondary leading-relaxed mt-4 text-base sm:text-lg">
@@ -273,7 +273,7 @@ export default function TeamContentV3({ data }: { data: Record<string, unknown>
<div className="max-w-4xl mx-auto p-8 sm:p-10 lg:p-16 border border-border-primary bg-bg-elevated">
<div className="flex items-center gap-3 mb-8 justify-center">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.15em] font-medium text-brand">
<span className="text-[13px] tracking-[0.15em] font-medium text-brand-ink">
</span>
<div className="w-10 h-px bg-brand" />
@@ -303,13 +303,13 @@ export default function TeamContentV3({ data }: { data: Record<string, unknown>
<ScrollReveal className="max-w-3xl mb-16 sm:mb-20">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.15em] font-medium text-brand">
<span className="text-[13px] tracking-[0.15em] font-medium text-brand-ink">
</span>
</div>
<h2 className="font-sans text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-ink tracking-tight leading-[1.05]">
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
<p className="text-text-secondary leading-relaxed mt-4 text-base sm:text-lg">
@@ -328,7 +328,7 @@ export default function TeamContentV3({ data }: { data: Record<string, unknown>
{/* ============ L4: CTA 团队行动号召 ============ */}
<section className="relative py-24 sm:py-32 md:py-44 overflow-hidden bg-dark-bg">
<div className="absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-dark-border to-transparent" />
<div className="absolute inset-0 pointer-events-none">
<div className="absolute inset-0 pointer-events-none overflow-hidden">
<div className="absolute top-1/3 right-1/4 w-[500px] h-[500px] bg-brand/[0.04] rounded-full blur-[140px]" />
</div>
@@ -337,7 +337,7 @@ export default function TeamContentV3({ data }: { data: Record<string, unknown>
<h2 className="font-sans text-2xl sm:text-3xl md:text-4xl lg:text-6xl xl:text-7xl font-black text-dark-text-primary tracking-tightest leading-[0.9] mb-8 sm:mb-10">
{teamData.ctaTitle || '成为下一个'}
<br />
<span className="text-brand"></span>
<span className="text-brand-ink"></span>
</h2>
<p className="text-dark-text-secondary text-lg leading-relaxed mb-12 sm:mb-16 max-w-xl">
{teamData.ctaDescription || '无论您处于数字化转型的哪个阶段,我们都愿意成为您的长期伙伴。'}
+28 -2
View File
@@ -26,6 +26,17 @@ body {
--color-brand-soft: rgba(196, 30, 58, 0.12);
--color-brand-bg: #FEF2F4;
--color-brand-rgb: 196 30 58;
/* 品牌「文字墨色」专用通道(text-brand-ink)。
与 --color-brand-rgb 分离的原因:--color-brand-rgb 同时服务 bg-brand / border-brand
而红底白字按钮在深底上仍需 #C41E3A(实测 5.58:1);
一旦随主题提亮,按钮会掉到 3.75:1。故文字与底色必须走两条通道。
深色下取 #F87171248 113 113):于 #0A0E14/#0F1419/#151B23 分别 6.99/6.69/6.26,全达 AA。 */
--color-brand-ink: #C41E3A;
--color-brand-ink-rgb: 196 30 58;
/* 详情页 Hero badge 的 accent 文字色(accentColor 由各页 hero-themes 传入,
经 --badge-accent 自定义属性注入)。浅色 = 原色;深色 = 45% accent + 55% 白的提亮变体
—— accentColor 多为深色系(#1e3a5f 等),直接用作深底文字仅 1.65:1 */
--badge-accent-text: var(--badge-accent, var(--color-ink));
/* 品牌色深色区块(Bain 式深红背景) */
--color-brand-section: #8B1530;
--color-brand-section-text: #F8FAFC;
@@ -452,6 +463,21 @@ html[data-theme='dark'] {
--color-error-text: #F87171;
--color-info-bg: #0E1A2A;
--color-info-text: #60A5FA;
/* 品牌色分两条通道,只有「文字」通道翻转:
- --color-brand / --color-brand-rgbbg-brand、border-brand**刻意不翻**:红底白字实测 5.58:1,
若随主题提亮到 #E04A68 反而掉到 3.75:1。
- --color-brand-ink-rgbtext-brand-ink)→ #F87171,与上方 --color-error-text 同值,不引入新色;
于三种深底 6.99 / 6.69 / 6.26,全达 AA。
- --color-brand-bg 补齐:它与 --color-error-bg 在浅色下同为 #FEF2F4
此前只翻了 error-bg,导致深色下白字压浅粉底仅 1.04:1(首页「首批客户共创计划」卡)。 */
--color-brand-ink: #F87171;
--color-brand-ink-rgb: 248 113 113;
--color-brand-bg: #2A1418;
/* hero 徽章文字:accentColor 直用作深底文字不可读(如 #1e3a5f 于 #0B1119 仅 1.65:1),
深色下按 accent 45% + 白 55% 提亮;--badge-accent 未注入时回退到反色墨字。 */
--badge-accent-text: color-mix(in srgb, var(--badge-accent, var(--color-ink)) 45%, white);
}
/* html/body 背景跟随主题 token(覆盖顶部 !important 硬编码) */
@@ -631,7 +657,7 @@ html[data-theme='dark'] body {
background: var(--color-bg-tertiary);
padding: 0.15em 0.4em;
border-radius: var(--radius-sm);
color: var(--color-brand);
color: var(--color-brand-ink);
}
pre {
@@ -684,7 +710,7 @@ html[data-theme='dark'] body {
font-weight: 600;
letter-spacing: var(--letter-spacing-eyebrow);
text-transform: uppercase;
color: var(--color-brand);
color: var(--color-brand-ink);
}
a {
+6 -6
View File
@@ -55,14 +55,14 @@ export default function TestErrorTrackingClient() {
};
return (
<div className="min-h-screen bg-gray-50 p-8">
<div className="min-h-screen bg-bg-primary p-8">
<div className="max-w-4xl mx-auto">
<h1 className="text-3xl font-bold text-gray-900 mb-8">
<h1 className="text-3xl font-bold text-text-primary mb-8">
🧪 GA4
</h1>
<div className="bg-white rounded-lg shadow-md p-6 mb-6">
<h2 className="text-xl font-semibold text-gray-800 mb-4">
<div className="bg-bg-elevated rounded-lg shadow-md p-6 mb-6">
<h2 className="text-xl font-semibold text-text-secondary mb-4">
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
@@ -94,14 +94,14 @@ export default function TestErrorTrackingClient() {
<button
onClick={clearResults}
className="mt-4 px-6 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300 transition-colors"
className="mt-4 px-6 py-2 bg-bg-secondary text-text-secondary rounded-lg hover:bg-bg-tertiary transition-colors"
>
🗑
</button>
</div>
{testResults.length > 0 && (
<div className="bg-gray-900 rounded-lg shadow-md p-6">
<div className="bg-dark-bg rounded-lg shadow-md p-6">
<h2 className="text-xl font-semibold text-green-400 mb-4">
📋
</h2>
+2 -2
View File
@@ -41,7 +41,7 @@ export function RichTextEditor({ value, onChange, placeholder = '请输入内容
Link.configure({
openOnClick: false,
HTMLAttributes: {
class: 'text-brand underline',
class: 'text-brand-ink underline',
},
}),
Placeholder.configure({
@@ -87,7 +87,7 @@ function Toolbar({ editor }: { editor: Editor }) {
const btnClass = (isActive: boolean) =>
`p-1.5 rounded transition-colors ${
isActive
? 'bg-brand/20 text-brand'
? 'bg-brand/20 text-brand-ink'
: 'text-white/60 hover:bg-white/[0.05] hover:text-white'
}`;
+2 -2
View File
@@ -128,7 +128,7 @@ export function TechStackShowcase({ title, subtitle, categories }: TechStackShow
{category.items.map((item, i) => (
<span
key={i}
className="px-3 py-1.5 text-xs font-medium bg-bg-secondary text-text-secondary border border-border-primary hover:border-brand/30 hover:text-brand transition-colors duration-300"
className="px-3 py-1.5 text-xs font-medium bg-bg-secondary text-text-secondary border border-border-primary hover:border-brand/30 hover:text-brand-ink transition-colors duration-300"
>
{item}
</span>
@@ -365,7 +365,7 @@ export function DataProofSection({ title, subtitle, metrics }: DataProofSectionP
{metric.trend && (
<div className={cn(
'mt-4 inline-flex items-center gap-1.5 text-sm font-medium',
metric.trendUp ? 'text-success' : 'text-brand'
metric.trendUp ? 'text-success' : 'text-brand-ink'
)}>
<span>{metric.trend}</span>
</div>
+1 -1
View File
@@ -56,7 +56,7 @@ export function TestimonialSection({
<div key={index} className="w-full shrink-0">
<div className="max-w-4xl mx-auto">
<div className="relative p-10 lg:p-16 border border-border-primary bg-bg-primary">
<Quote className="absolute top-8 left-8 w-12 h-12 opacity-10 text-brand" />
<Quote className="absolute top-8 left-8 w-12 h-12 opacity-10 text-brand-ink" />
<div className="relative z-10">
<p className="text-xl lg:text-2xl text-text-primary leading-relaxed font-light mb-10 lg:mb-14">
{testimonial.quote}
@@ -55,7 +55,7 @@ export function CaseStudiesSection({
<SectionLabel className="justify-center">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
</span>
<div className="w-14 h-px bg-brand" />
@@ -85,7 +85,7 @@ export function CaseStudiesSection({
</span>
</div>
<div className="absolute top-5 left-5">
<span className="px-3 py-1.5 text-xs font-bold text-brand bg-brand-soft/80 backdrop-blur-sm">
<span className="px-3 py-1.5 text-xs font-bold text-brand-ink bg-brand-soft/80 backdrop-blur-sm">
{study.industry}
</span>
</div>
@@ -99,7 +99,7 @@ export function CaseStudiesSection({
{study.challenge}
</p>
<div className="pt-6 border-t border-border-primary">
<div className="text-2xl font-bold text-brand mb-1">{study.result}</div>
<div className="text-2xl font-bold text-brand-ink mb-1">{study.result}</div>
<div className="text-xs text-text-muted"></div>
</div>
</div>
+7 -7
View File
@@ -15,20 +15,20 @@ export function CaseStudyCard({ study, index }: CaseStudyCardProps) {
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.3, delay: index * 0.06 }}
className="rounded-xl border border-gray-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md"
className="rounded-xl border border-border-primary bg-bg-elevated p-6 shadow-sm transition-shadow hover:shadow-md"
>
<div className="mb-3 flex items-center gap-2">
<span className="rounded-full bg-red-50 px-2.5 py-1 text-xs font-medium text-brand">
<span className="rounded-full bg-red-50 px-2.5 py-1 text-xs font-medium text-brand-ink">
{study.industry}
</span>
<span className="text-sm text-gray-500">{study.client}</span>
<span className="text-sm text-text-muted">{study.client}</span>
</div>
<h4 className="mb-2 text-sm font-semibold text-gray-900"></h4>
<p className="mb-4 text-sm leading-relaxed text-gray-600">{study.challenge}</p>
<h4 className="mb-2 text-sm font-semibold text-text-primary"></h4>
<p className="mb-4 text-sm leading-relaxed text-text-secondary">{study.challenge}</p>
<h4 className="mb-2 text-sm font-semibold text-gray-900"></h4>
<p className="mb-4 text-sm leading-relaxed text-gray-600">{study.solution}</p>
<h4 className="mb-2 text-sm font-semibold text-text-primary"></h4>
<p className="mb-4 text-sm leading-relaxed text-text-secondary">{study.solution}</p>
<div className="rounded-lg bg-green-50 p-3">
<p className="text-sm font-medium text-green-800">{study.result}</p>
@@ -21,13 +21,13 @@ export function CertificationList({ certifications }: CertificationListProps) {
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.3, delay: index * 0.05 }}
className="inline-flex items-center gap-2 rounded-full border border-gray-200 bg-white px-4 py-2 text-sm text-gray-700 shadow-sm transition-all hover:border-gray-300 hover:shadow-md"
className="inline-flex items-center gap-2 rounded-full border border-border-primary bg-bg-elevated px-4 py-2 text-sm text-text-secondary shadow-sm transition-all hover:border-border-secondary hover:shadow-md"
>
<Award className="h-4 w-4 text-brand" />
<Award className="h-4 w-4 text-brand-ink" />
<span className="font-medium">{cert.name}</span>
<span className="text-xs text-gray-400">{cert.issuer}</span>
<span className="text-xs text-text-muted">{cert.issuer}</span>
{cert.link && cert.link !== '#' && (
<ExternalLink className="h-3 w-3 text-gray-400" />
<ExternalLink className="h-3 w-3 text-text-muted" />
)}
</motion.a>
))}
@@ -37,7 +37,7 @@ export function CertificationsSection({ certifications }: CertificationsSectionP
<SectionLabel className="justify-center">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
</span>
<div className="w-14 h-px bg-brand" />
@@ -59,7 +59,7 @@ export function CertificationsSection({ certifications }: CertificationsSectionP
key={idx}
className="group flex items-center gap-4 px-8 py-5 bg-bg-primary hover:bg-bg-secondary transition-all duration-300"
>
<div className="w-12 h-12 rounded-xl bg-brand-soft flex items-center justify-center text-brand">
<div className="w-12 h-12 rounded-xl bg-brand-soft flex items-center justify-center text-brand-ink">
<Shield className="w-6 h-6" />
</div>
<div>
+3 -2
View File
@@ -28,7 +28,8 @@ export function DetailCTASection({
backgroundSize: '48px 48px',
}}
/>
<div className="absolute inset-0 pointer-events-none">
{/* 装饰光斑容器:overflow-hidden 防止 500px blur 圆撑大 section scrollHeight(伪文本裁剪误报源) */}
<div className="absolute inset-0 pointer-events-none overflow-hidden">
<div className="absolute top-1/3 right-1/4 w-[500px] h-[500px] bg-white/[0.03] rounded-full blur-[140px]" />
</div>
@@ -78,7 +79,7 @@ export function DetailCTASection({
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.5, duration: 0.3 }}
className="mt-10 text-sm text-white/50"
className="mt-10 text-sm text-white/70"
>
&lt; 2 · 7×24 ·
</motion.p>
+5 -2
View File
@@ -79,9 +79,12 @@ export function DetailHero({
}`}
style={{
backgroundColor: `${theme.accentColor}10`,
color: theme.accentColor,
// 文字色经 --badge-accent-text 间接引用:浅色取 accentColor 原色,
// 深色由 globals.css color-mix 自动提亮(accentColor 直用作深底文字会不可读)
color: 'var(--badge-accent-text)',
borderColor: `${theme.accentColor}25`,
}}
'--badge-accent': theme.accentColor,
} as React.CSSProperties}
>
<span>
<Sparkles className="w-3.5 h-3.5" />
+12 -12
View File
@@ -32,7 +32,7 @@ function FeatureTags({ text }: { text: string }) {
return (
<div className="space-y-3">
<h4 className="font-bold text-ink text-base">{title}</h4>
<h3 className="font-bold text-ink text-base">{title}</h3>
<div className="flex flex-wrap gap-2">
{tags.map((tag) => (
<span
@@ -99,7 +99,7 @@ function MetricCard({
<Icon className="w-6 h-6" />
</div>
<div ref={ref} className="text-3xl sm:text-4xl font-black text-brand tabular-nums leading-none mb-1">
<div ref={ref} className="text-3xl sm:text-4xl font-black text-brand-ink tabular-nums leading-none mb-1">
{displayValue}
</div>
@@ -112,7 +112,7 @@ function MetricCard({
export function ProductValueSection({ product }: ProductValueSectionProps) {
return (
<section className="relative bg-white py-20 sm:py-28 md:py-36 overflow-hidden">
<section className="relative bg-bg-primary py-20 sm:py-28 md:py-36 overflow-hidden">
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative">
<motion.div
initial={{ opacity: 0, y: 32 }}
@@ -123,13 +123,13 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-ink tracking-tight leading-[0.95] max-w-3xl">
{product.title}
<span className="text-brand"> </span>
<span className="text-brand-ink"> </span>
</h2>
<p className="text-lg text-text-secondary max-w-2xl mt-6 leading-relaxed">
{product.overview}
@@ -176,7 +176,7 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
<div>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
@@ -194,7 +194,7 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
}}
className="bain-card p-5 flex items-start gap-3"
>
<CheckCircle2 className="w-5 h-5 text-brand mt-0.5 shrink-0" />
<CheckCircle2 className="w-5 h-5 text-brand-ink mt-0.5 shrink-0" />
<p className="text-sm font-medium text-text-secondary leading-relaxed">{benefit}</p>
</motion.div>
))}
@@ -205,14 +205,14 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
<div>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
<div className="bain-card p-6">
<div className="flex items-center gap-3 mb-4">
<Shield className="w-5 h-5 text-brand" />
<h4 className="font-bold text-ink text-sm"></h4>
<Shield className="w-5 h-5 text-brand-ink" />
<h3 className="font-bold text-ink text-sm"></h3>
</div>
<ul className="space-y-3">
{product.specs.slice(0, 5).map((spec, index) => (
@@ -228,7 +228,7 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
}}
className="flex items-start gap-3 text-sm text-text-secondary"
>
<ArrowRight className="w-4 h-4 text-brand mt-0.5 shrink-0" />
<ArrowRight className="w-4 h-4 text-brand-ink mt-0.5 shrink-0" />
<span>{spec}</span>
</motion.li>
))}
@@ -249,7 +249,7 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
<div className="mb-12">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
@@ -54,7 +54,7 @@ function AnimatedCounter({ value, duration = 2000 }: { value: string; duration?:
}, [isInView, value, duration]);
return (
<div ref={ref} className="text-3xl sm:text-4xl font-black text-brand tabular-nums leading-none">
<div ref={ref} className="text-3xl sm:text-4xl font-black text-brand-ink tabular-nums leading-none">
{displayValue}
</div>
);
@@ -70,7 +70,7 @@ export function DetailTrustSection({
if (!hasContent) return null;
return (
<section className="relative py-20 sm:py-28 md:py-36 overflow-hidden bg-white">
<section className="relative py-20 sm:py-28 md:py-36 overflow-hidden bg-bg-primary">
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10">
{dataProofs.length > 0 && (
<div className="mb-20">
@@ -83,7 +83,7 @@ export function DetailTrustSection({
>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
@@ -31,7 +31,7 @@ export function EarlyAccessNotice() {
>
<p
id="early-access-notice-heading"
className="text-sm font-semibold text-brand mb-1"
className="text-sm font-semibold text-brand-ink mb-1"
>
{EARLY_ACCESS.label}
</p>
@@ -40,7 +40,7 @@ export function EarlyAccessNotice() {
</p>
<Link
href="/contact"
className="inline-flex items-center gap-1 text-sm font-medium text-brand underline-offset-4 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2 focus-visible:ring-offset-bg-secondary rounded"
className="inline-flex items-center gap-1 min-h-6 text-sm font-medium text-brand-ink underline-offset-4 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2 focus-visible:ring-offset-bg-secondary rounded"
>
<span aria-hidden="true"></span>
+2 -2
View File
@@ -135,12 +135,12 @@ function SignalCard({ signal }: { signal: L3Signal }) {
: 'hover:border-brand/40 hover:shadow-md hover:-translate-y-1'
)}
>
<span className="inline-block text-[11px] tracking-[0.15em] uppercase font-bold text-brand mb-4">
<span className="inline-block text-[11px] tracking-[0.15em] uppercase font-bold text-brand-ink mb-4">
{eyebrow}
</span>
<div
className="w-10 h-10 mb-4 flex items-center justify-center rounded-md bg-brand-soft text-brand"
className="w-10 h-10 mb-4 flex items-center justify-center rounded-md bg-brand-soft text-brand-ink"
aria-hidden="true"
>
<Icon className="w-5 h-5" />
+3 -3
View File
@@ -124,9 +124,9 @@ export function PressableButton({
primary:
'bg-brand text-white shadow-sm hover:shadow-brand-hover',
secondary:
'bg-white text-ink border border-border-primary hover:border-brand/30 hover:shadow-md',
'bg-bg-elevated text-ink border border-border-primary hover:border-brand/30 hover:shadow-md',
ghost:
'bg-transparent text-brand hover:bg-brand/5',
'bg-transparent text-brand-ink hover:bg-brand/5',
};
const content = (
@@ -175,7 +175,7 @@ export function HoverLink({
<a
href={href}
className={`group inline-flex items-center gap-1.5 font-medium transition-colors duration-fast ease-standard ${
color === 'brand' ? 'text-brand' : 'text-text-secondary hover:text-brand'
color === 'brand' ? 'text-brand-ink' : 'text-text-secondary hover:text-brand-ink'
} ${className}`}
>
<span className="relative inline-block">
+3 -3
View File
@@ -30,7 +30,7 @@ export function ProductCard({ product }: ProductCardProps) {
className="group"
>
<Link href={`/products/${product.id}`} className="block">
<div className="relative h-full rounded-2xl bg-white border border-border-primary overflow-hidden hover:border-brand/30 hover:shadow-lg hover:-translate-y-1 transition-all duration-300">
<div className="relative h-full rounded-2xl bg-bg-elevated border border-border-primary overflow-hidden hover:border-brand/30 hover:shadow-lg hover:-translate-y-1 transition-all duration-300">
<div className="aspect-video relative overflow-hidden bg-bg-secondary">
<Image
src={product.image}
@@ -54,7 +54,7 @@ export function ProductCard({ product }: ProductCardProps) {
</div>
<div className="p-6">
<h3 className="text-xl font-bold text-ink mb-3 group-hover:text-brand transition-colors">
<h3 className="text-xl font-bold text-ink mb-3 group-hover:text-brand-ink transition-colors">
{product.title}
</h3>
@@ -75,7 +75,7 @@ export function ProductCard({ product }: ProductCardProps) {
</div>
)}
<div className="flex items-center gap-2 text-sm font-semibold text-brand group-hover:gap-3 transition-all">
<div className="flex items-center gap-2 text-sm font-semibold text-brand-ink group-hover:gap-3 transition-all">
<ArrowRight className="w-4 h-4" />
</div>
+6 -6
View File
@@ -20,7 +20,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
const icons: LucideIcon[] = [Zap, Clock, Users, Award, TrendingUp];
return (
<section className="relative bg-white py-20 sm:py-28 md:py-36 overflow-hidden">
<section className="relative bg-bg-primary py-20 sm:py-28 md:py-36 overflow-hidden">
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative">
<motion.div
initial={{ opacity: 0, y: 32 }}
@@ -31,7 +31,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
@@ -47,7 +47,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
<div className="mb-16">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
@@ -92,7 +92,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
<div>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
@@ -110,7 +110,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
}}
className="bain-card p-5 flex items-start gap-3"
>
<CheckCircle2 className="w-5 h-5 text-brand mt-0.5 shrink-0" />
<CheckCircle2 className="w-5 h-5 text-brand-ink mt-0.5 shrink-0" />
<p className="text-sm font-medium text-text-secondary leading-relaxed">{benefit}</p>
</motion.div>
))}
@@ -122,7 +122,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
<div>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
@@ -43,7 +43,7 @@ export function SolutionCard({ solution }: SolutionCardProps) {
className="group"
>
<Link href={`/solutions/${solution.id}`} className="block">
<div className="relative h-full rounded-2xl bg-white border border-border-primary overflow-hidden hover:border-brand/30 hover:shadow-lg hover:-translate-y-1 transition-all duration-300">
<div className="relative h-full rounded-2xl bg-bg-elevated border border-border-primary overflow-hidden hover:border-brand/30 hover:shadow-lg hover:-translate-y-1 transition-all duration-300">
<div className="aspect-video relative overflow-hidden bg-bg-secondary flex items-center justify-center">
{solution.image ? (
<Image
@@ -53,7 +53,7 @@ export function SolutionCard({ solution }: SolutionCardProps) {
className="object-cover group-hover:scale-105 transition-transform duration-150"
/>
) : (
<Icon className="w-16 h-16 text-brand/20 group-hover:text-brand/40 transition-colors" />
<Icon className="w-16 h-16 text-brand-ink/20 group-hover:text-brand-ink/40 transition-colors" />
)}
<div className="absolute top-4 left-4 flex gap-2">
@@ -71,7 +71,7 @@ export function SolutionCard({ solution }: SolutionCardProps) {
</div>
<div className="p-6">
<h3 className="text-xl font-bold text-ink mb-3 group-hover:text-brand transition-colors">
<h3 className="text-xl font-bold text-ink mb-3 group-hover:text-brand-ink transition-colors">
{solution.title}
</h3>
@@ -90,7 +90,7 @@ export function SolutionCard({ solution }: SolutionCardProps) {
</div>
)}
<div className="flex items-center gap-2 text-sm font-semibold text-brand group-hover:gap-3 transition-all">
<div className="flex items-center gap-2 text-sm font-semibold text-brand-ink group-hover:gap-3 transition-all">
<ArrowRight className="w-4 h-4" />
</div>
@@ -142,7 +142,7 @@ export function ServiceCard({ service }: ServiceCardProps) {
{service.features.slice(0, 3).map((feature) => (
<span
key={feature}
className="px-2.5 py-1 rounded-md text-xs font-medium bg-white text-blue-600 border border-border-primary"
className="px-2.5 py-1 rounded-md text-xs font-medium bg-bg-elevated text-blue-600 border border-border-primary"
>
{feature.split('')[0]}
</span>
+5 -5
View File
@@ -26,12 +26,12 @@ export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-ink tracking-tight leading-[0.95] max-w-3xl">
<span className="text-brand">{solution.industry}</span>
<span className="text-brand-ink">{solution.industry}</span>
</h2>
<p className="text-lg text-text-secondary max-w-2xl mt-6 leading-relaxed">
{solution.description}
@@ -124,7 +124,7 @@ export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
<div className="mb-12">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
@@ -170,7 +170,7 @@ export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
<div className="mb-12">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
</span>
</div>
@@ -192,7 +192,7 @@ export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
{solution.suiteCombination.primaryProducts.map((product) => (
<span
key={product}
className="px-4 py-2 bg-brand-soft/50 text-brand text-sm font-semibold border border-brand/20"
className="px-4 py-2 bg-brand-soft/50 text-brand-ink text-sm font-semibold border border-brand/20"
>
{product}
</span>
+1 -1
View File
@@ -15,7 +15,7 @@ export function Footer() {
.flatMap(group => group.items);
return (
<footer className="bg-dark-bg text-white relative overflow-hidden" data-testid="footer" role="contentinfo">
<footer className="bg-dark-bg text-white relative overflow-hidden [&_a]:inline-flex [&_a]:items-center [&_a]:min-h-6" data-testid="footer" role="contentinfo">
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10">
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-12 gap-10 lg:gap-12 py-16 lg:py-20">
<div data-testid="card-brand" className="col-span-2 lg:col-span-4">
+2 -2
View File
@@ -85,7 +85,7 @@ export function MegaDropdown({ label, groups, isOpen, isActive, onToggle, onOpen
<span className="text-xs text-text-muted">{group.description}</span>
)}
{group.highlight && (
<Sparkles className="w-3.5 h-3.5 text-brand" />
<Sparkles className="w-3.5 h-3.5 text-brand-ink" />
)}
</div>
@@ -101,7 +101,7 @@ export function MegaDropdown({ label, groups, isOpen, isActive, onToggle, onOpen
<span className={`shrink-0 px-1.5 py-0.5 text-[10px] font-medium ${
item.badge === '敬请期待'
? 'bg-bg-tertiary text-text-muted'
: 'bg-brand/10 text-brand'
: 'bg-brand/10 text-brand-ink'
}`}>
{item.badge === '敬请期待' && <Lock className="w-2.5 h-2.5 inline mr-0.5" />}
{item.badge}
+2 -2
View File
@@ -60,13 +60,13 @@ export function MobileTabBar() {
<Icon
className={cn(
'w-6 h-6 transition-colors duration-300',
active ? 'text-brand' : 'text-text-muted group-hover:text-text-secondary'
active ? 'text-brand-ink' : 'text-text-muted group-hover:text-text-secondary'
)}
/>
<span
className={cn(
'text-xs mt-1 transition-colors duration-300',
active ? 'text-brand font-medium' : 'text-text-muted'
active ? 'text-brand-ink font-medium' : 'text-text-muted'
)}
>
{tab.label}
+1 -1
View File
@@ -19,7 +19,7 @@ const buttonVariants = cva(
ghost:
'text-text-secondary hover:bg-bg-secondary hover:text-text-primary active:scale-[0.97] transition-all duration-fast ease-standard',
link:
'text-text-primary underline-offset-4 hover:text-brand relative after:absolute after:bottom-0 after:left-0 after:h-[2px] after:w-0 hover:after:w-full after:bg-brand after:transition-all after:duration-normal after:ease-standard',
'text-text-primary underline-offset-4 hover:text-brand-ink relative after:absolute after:bottom-0 after:left-0 after:h-[2px] after:w-0 hover:after:w-full after:bg-brand after:transition-all after:duration-normal after:ease-standard',
destructive:
'bg-error text-white shadow-sm hover:bg-error-hover hover:-translate-y-px active:translate-y-0 active:scale-[0.97] transition-all duration-fast ease-standard',
},
+2 -2
View File
@@ -111,7 +111,7 @@ const ContextMenuCheckboxItem = React.forwardRef<
>
<span className="absolute left-2 flex size-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<Check className="size-4 text-brand" />
<Check className="size-4 text-brand-ink" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
@@ -136,7 +136,7 @@ const ContextMenuRadioItem = React.forwardRef<
>
<span className="absolute left-2 flex size-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<Circle className="size-2 fill-brand text-brand" />
<Circle className="size-2 fill-brand text-brand-ink" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
+1 -1
View File
@@ -45,7 +45,7 @@ const VARIANT_STYLES: Record<CTAButtonVariant, string> = {
dark:
'text-dark-text-primary border border-dark-border hover:border-dark-text-muted hover:bg-white/5 px-10 py-4 font-semibold text-base',
inline:
'text-text-primary hover:text-brand px-0 py-0 font-medium text-sm bg-transparent border-0',
'text-text-primary hover:text-brand-ink px-0 py-0 font-medium text-sm bg-transparent border-0',
};
const ARROW_STYLES: Record<CTAButtonVariant, string> = {
+2 -2
View File
@@ -113,7 +113,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
>
<span className="absolute left-2 flex size-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<Check className="size-4 text-brand" />
<Check className="size-4 text-brand-ink" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
@@ -138,7 +138,7 @@ const DropdownMenuRadioItem = React.forwardRef<
>
<span className="absolute left-2 flex size-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<Circle className="size-2 fill-brand text-brand" />
<Circle className="size-2 fill-brand text-brand-ink" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
+2 -2
View File
@@ -31,7 +31,7 @@ const LabeledInput = React.forwardRef<HTMLInputElement, LabeledInputProps>(
>
{label}
{required && (
<span className="text-brand ml-1.5" aria-hidden="true">*</span>
<span className="text-brand-ink ml-1.5" aria-hidden="true">*</span>
)}
</Label>
)}
@@ -56,7 +56,7 @@ const LabeledInput = React.forwardRef<HTMLInputElement, LabeledInputProps>(
{error && (
<p
id={errorId}
className="mt-1.5 text-sm text-brand"
className="mt-1.5 text-sm text-brand-ink"
role="alert"
data-testid="error-message"
>
+2 -2
View File
@@ -31,7 +31,7 @@ const LabeledTextarea = React.forwardRef<HTMLTextAreaElement, LabeledTextareaPro
>
{label}
{required && (
<span className="text-brand ml-1.5" aria-hidden="true">*</span>
<span className="text-brand-ink ml-1.5" aria-hidden="true">*</span>
)}
</Label>
)}
@@ -56,7 +56,7 @@ const LabeledTextarea = React.forwardRef<HTMLTextAreaElement, LabeledTextareaPro
{error && (
<p
id={errorId}
className="mt-1.5 text-sm text-brand"
className="mt-1.5 text-sm text-brand-ink"
role="alert"
data-testid="error-message"
>
+1 -1
View File
@@ -26,7 +26,7 @@ interface MetricCardProps {
}
const accentStyles: Record<string, string> = {
brand: 'text-brand bg-brand-bg',
brand: 'text-brand-ink bg-brand-bg',
blue: 'text-accent-blue bg-accent-blue/10',
teal: 'text-accent-teal bg-accent-teal/10',
amber: 'text-accent-amber bg-accent-amber/10',
+3 -3
View File
@@ -68,7 +68,7 @@ export function MilestoneTimeline({
)}>
<div className="w-2 h-2 rounded-full bg-brand" />
</div>
<div className="text-sm font-bold text-brand mb-1 tracking-wider">
<div className="text-sm font-bold text-brand-ink mb-1 tracking-wider">
{item.year}
</div>
<h4 className={cn('text-lg font-semibold mb-2', isDark ? 'text-white' : 'text-text-primary')}>
@@ -80,7 +80,7 @@ export function MilestoneTimeline({
{item.highlight && (
<div className={cn(
'mt-3 inline-flex items-center px-3 py-1 rounded-full text-xs font-medium',
isDark ? 'bg-brand/10 text-brand' : 'bg-brand-bg text-brand'
isDark ? 'bg-brand/10 text-brand-ink' : 'bg-brand-bg text-brand-ink'
)}>
{item.highlight}
</div>
@@ -112,7 +112,7 @@ export function MilestoneTimeline({
)}>
<div className="w-2 h-2 rounded-full bg-brand" />
</div>
<div className="text-sm font-bold text-brand mb-2 tracking-wider">
<div className="text-sm font-bold text-brand-ink mb-2 tracking-wider">
{item.year}
</div>
<h4 className={cn('text-base font-semibold mb-2 leading-snug', isDark ? 'text-white' : 'text-text-primary')}>
+1 -1
View File
@@ -36,7 +36,7 @@ export function SectionLabel({
)}
>
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.15em] font-medium text-brand">
<span className="text-[13px] tracking-[0.15em] font-medium text-brand-ink">
{children}
</span>
</div>
+2 -2
View File
@@ -30,7 +30,7 @@ const RadioGroupItem = React.forwardRef<
ref={ref}
data-slot="radio-group-item"
className={cn(
'aspect-square size-4 rounded-full border border-border-primary bg-bg-primary text-brand shadow-sm',
'aspect-square size-4 rounded-full border border-border-primary bg-bg-primary text-brand-ink shadow-sm',
'focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2',
'disabled:cursor-not-allowed disabled:opacity-50',
'data-[state=checked]:border-brand',
@@ -43,7 +43,7 @@ const RadioGroupItem = React.forwardRef<
data-slot="radio-group-indicator"
className="flex items-center justify-center"
>
<Circle className="size-2.5 fill-brand text-brand" />
<Circle className="size-2.5 fill-brand text-brand-ink" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
));
+1 -1
View File
@@ -133,7 +133,7 @@ const SelectItem = React.forwardRef<
>
<span className="absolute right-2 flex size-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="size-4 text-brand" />
<Check className="size-4 text-brand-ink" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
+3
View File
@@ -21,6 +21,9 @@ module.exports = {
},
brand: {
DEFAULT: 'rgb(var(--color-brand-rgb) / <alpha-value>)',
// 文字专用通道:深色下 --color-brand-ink-rgb 翻转为 #F87171AA 达标)。
// 不要拿 DEFAULT 当文字色用 —— 它同时是 bg-brand/border-brand 的取值,深色下不翻。
ink: 'rgb(var(--color-brand-ink-rgb) / <alpha-value>)',
hover: 'var(--color-brand-hover)',
light: 'var(--color-brand-light)',
soft: 'rgb(var(--color-brand-rgb) / calc(0.12 * <alpha-value>))',