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:
+24
@@ -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">•</span>
|
||||
<span className="text-brand-ink shrink-0 mt-0.5">•</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>
|
||||
}
|
||||
|
||||
@@ -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">
|
||||
我们的咨询服务贯穿方法论的每个阶段,从战略规划到落地实施全程陪伴。
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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。故文字与底色必须走两条通道。
|
||||
深色下取 #F87171(248 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-rgb(bg-brand、border-brand)**刻意不翻**:红底白字实测 5.58:1,
|
||||
若随主题提亮到 #E04A68 反而掉到 3.75:1。
|
||||
- --color-brand-ink-rgb(text-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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'
|
||||
}`;
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
平均响应时间 < 2小时 · 7×24小时技术支持 · 无需预付费用
|
||||
</motion.p>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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> = {
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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')}>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
));
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -21,6 +21,9 @@ module.exports = {
|
||||
},
|
||||
brand: {
|
||||
DEFAULT: 'rgb(var(--color-brand-rgb) / <alpha-value>)',
|
||||
// 文字专用通道:深色下 --color-brand-ink-rgb 翻转为 #F87171(AA 达标)。
|
||||
// 不要拿 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>))',
|
||||
|
||||
Reference in New Issue
Block a user