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

- 拆分品牌色「文字/底色」双通道:新增 --color-brand-ink(-rgb)(深色 #F87171)
  与 tailwind brand.ink;text-brand → text-brand-ink 迁移 247 处;
  bg-brand/border-brand 保持 --color-brand-rgb 不翻转(红底白字 5.58:1 不能动)
- dark 块补齐 --color-brand-bg: #2A1418(修复深色白字压浅粉底 1.04:1)
- hero 徽章新增 --badge-accent-text 桥接:accentColor 直用作深底文字不可读
  (#1e3a5f 深底 1.65:1),浅色取原色 / 深色 color-mix 提亮
- 硬编码颜色 token 化:bg-white/text-gray-*/border-gray-* → bg-bg-*/text-text-*/border-border-*
- 可访问性:触控目标 <24px 归零(footer 链接列 [&_a]:min-h-6 收口 377 处等)、
  news 搜索框补 aria-label、标题跳级 h2→h4 修正为 h3、装饰 blur 光斑容器补
  overflow-hidden 消除伪文本裁剪
- 验证:tsc 0 / eslint 0 error / jest 0 失败用例 / dogfood 33 路由 × 双主题 P1-P3 全零
This commit is contained in:
2026-09-05 08:16:31 +08:00
parent 846585af1f
commit 4b8500af1d
54 changed files with 339 additions and 280 deletions
+2 -2
View File
@@ -41,7 +41,7 @@ export function RichTextEditor({ value, onChange, placeholder = '请输入内容
Link.configure({
openOnClick: false,
HTMLAttributes: {
class: 'text-brand underline',
class: 'text-brand-ink underline',
},
}),
Placeholder.configure({
@@ -87,7 +87,7 @@ function Toolbar({ editor }: { editor: Editor }) {
const btnClass = (isActive: boolean) =>
`p-1.5 rounded transition-colors ${
isActive
? 'bg-brand/20 text-brand'
? 'bg-brand/20 text-brand-ink'
: 'text-white/60 hover:bg-white/[0.05] hover:text-white'
}`;
+2 -2
View File
@@ -128,7 +128,7 @@ export function TechStackShowcase({ title, subtitle, categories }: TechStackShow
{category.items.map((item, i) => (
<span
key={i}
className="px-3 py-1.5 text-xs font-medium bg-bg-secondary text-text-secondary border border-border-primary hover:border-brand/30 hover:text-brand transition-colors duration-300"
className="px-3 py-1.5 text-xs font-medium bg-bg-secondary text-text-secondary border border-border-primary hover:border-brand/30 hover:text-brand-ink transition-colors duration-300"
>
{item}
</span>
@@ -365,7 +365,7 @@ export function DataProofSection({ title, subtitle, metrics }: DataProofSectionP
{metric.trend && (
<div className={cn(
'mt-4 inline-flex items-center gap-1.5 text-sm font-medium',
metric.trendUp ? 'text-success' : 'text-brand'
metric.trendUp ? 'text-success' : 'text-brand-ink'
)}>
<span>{metric.trend}</span>
</div>
+1 -1
View File
@@ -56,7 +56,7 @@ export function TestimonialSection({
<div key={index} className="w-full shrink-0">
<div className="max-w-4xl mx-auto">
<div className="relative p-10 lg:p-16 border border-border-primary bg-bg-primary">
<Quote className="absolute top-8 left-8 w-12 h-12 opacity-10 text-brand" />
<Quote className="absolute top-8 left-8 w-12 h-12 opacity-10 text-brand-ink" />
<div className="relative z-10">
<p className="text-xl lg:text-2xl text-text-primary leading-relaxed font-light mb-10 lg:mb-14">
「{testimonial.quote}」
@@ -55,7 +55,7 @@ export function CaseStudiesSection({
<SectionLabel className="justify-center">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
客户案例
</span>
<div className="w-14 h-px bg-brand" />
@@ -85,7 +85,7 @@ export function CaseStudiesSection({
</span>
</div>
<div className="absolute top-5 left-5">
<span className="px-3 py-1.5 text-xs font-bold text-brand bg-brand-soft/80 backdrop-blur-sm">
<span className="px-3 py-1.5 text-xs font-bold text-brand-ink bg-brand-soft/80 backdrop-blur-sm">
{study.industry}
</span>
</div>
@@ -99,7 +99,7 @@ export function CaseStudiesSection({
{study.challenge}
</p>
<div className="pt-6 border-t border-border-primary">
<div className="text-2xl font-bold text-brand mb-1">{study.result}</div>
<div className="text-2xl font-bold text-brand-ink mb-1">{study.result}</div>
<div className="text-xs text-text-muted">核心成果</div>
</div>
</div>
+7 -7
View File
@@ -15,20 +15,20 @@ export function CaseStudyCard({ study, index }: CaseStudyCardProps) {
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.3, delay: index * 0.06 }}
className="rounded-xl border border-gray-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md"
className="rounded-xl border border-border-primary bg-bg-elevated p-6 shadow-sm transition-shadow hover:shadow-md"
>
<div className="mb-3 flex items-center gap-2">
<span className="rounded-full bg-red-50 px-2.5 py-1 text-xs font-medium text-brand">
<span className="rounded-full bg-red-50 px-2.5 py-1 text-xs font-medium text-brand-ink">
{study.industry}
</span>
<span className="text-sm text-gray-500">{study.client}</span>
<span className="text-sm text-text-muted">{study.client}</span>
</div>
<h4 className="mb-2 text-sm font-semibold text-gray-900">挑战</h4>
<p className="mb-4 text-sm leading-relaxed text-gray-600">{study.challenge}</p>
<h4 className="mb-2 text-sm font-semibold text-text-primary">挑战</h4>
<p className="mb-4 text-sm leading-relaxed text-text-secondary">{study.challenge}</p>
<h4 className="mb-2 text-sm font-semibold text-gray-900">解决方案</h4>
<p className="mb-4 text-sm leading-relaxed text-gray-600">{study.solution}</p>
<h4 className="mb-2 text-sm font-semibold text-text-primary">解决方案</h4>
<p className="mb-4 text-sm leading-relaxed text-text-secondary">{study.solution}</p>
<div className="rounded-lg bg-green-50 p-3">
<p className="text-sm font-medium text-green-800">{study.result}</p>
@@ -21,13 +21,13 @@ export function CertificationList({ certifications }: CertificationListProps) {
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.3, delay: index * 0.05 }}
className="inline-flex items-center gap-2 rounded-full border border-gray-200 bg-white px-4 py-2 text-sm text-gray-700 shadow-sm transition-all hover:border-gray-300 hover:shadow-md"
className="inline-flex items-center gap-2 rounded-full border border-border-primary bg-bg-elevated px-4 py-2 text-sm text-text-secondary shadow-sm transition-all hover:border-border-secondary hover:shadow-md"
>
<Award className="h-4 w-4 text-brand" />
<Award className="h-4 w-4 text-brand-ink" />
<span className="font-medium">{cert.name}</span>
<span className="text-xs text-gray-400">{cert.issuer}</span>
<span className="text-xs text-text-muted">{cert.issuer}</span>
{cert.link && cert.link !== '#' && (
<ExternalLink className="h-3 w-3 text-gray-400" />
<ExternalLink className="h-3 w-3 text-text-muted" />
)}
</motion.a>
))}
@@ -37,7 +37,7 @@ export function CertificationsSection({ certifications }: CertificationsSectionP
<SectionLabel className="justify-center">
<div className="flex items-center gap-5">
<div className="w-14 h-px bg-brand" />
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand">
<span className="text-[11px] tracking-[0.4em] uppercase font-bold text-brand-ink">
资质认证
</span>
<div className="w-14 h-px bg-brand" />
@@ -59,7 +59,7 @@ export function CertificationsSection({ certifications }: CertificationsSectionP
key={idx}
className="group flex items-center gap-4 px-8 py-5 bg-bg-primary hover:bg-bg-secondary transition-all duration-300"
>
<div className="w-12 h-12 rounded-xl bg-brand-soft flex items-center justify-center text-brand">
<div className="w-12 h-12 rounded-xl bg-brand-soft flex items-center justify-center text-brand-ink">
<Shield className="w-6 h-6" />
</div>
<div>
+3 -2
View File
@@ -28,7 +28,8 @@ export function DetailCTASection({
backgroundSize: '48px 48px',
}}
/>
<div className="absolute inset-0 pointer-events-none">
{/* 装饰光斑容器:overflow-hidden 防止 500px blur 圆撑大 section scrollHeight(伪文本裁剪误报源) */}
<div className="absolute inset-0 pointer-events-none overflow-hidden">
<div className="absolute top-1/3 right-1/4 w-[500px] h-[500px] bg-white/[0.03] rounded-full blur-[140px]" />
</div>
@@ -78,7 +79,7 @@ export function DetailCTASection({
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: 0.5, duration: 0.3 }}
className="mt-10 text-sm text-white/50"
className="mt-10 text-sm text-white/70"
>
平均响应时间 &lt; 2小时 · 7×24小时技术支持 · 无需预付费用
</motion.p>
+5 -2
View File
@@ -79,9 +79,12 @@ export function DetailHero({
}`}
style={{
backgroundColor: `${theme.accentColor}10`,
color: theme.accentColor,
// 文字色经 --badge-accent-text 间接引用:浅色取 accentColor 原色,
// 深色由 globals.css color-mix 自动提亮(accentColor 直用作深底文字会不可读)
color: 'var(--badge-accent-text)',
borderColor: `${theme.accentColor}25`,
}}
'--badge-accent': theme.accentColor,
} as React.CSSProperties}
>
<span>
<Sparkles className="w-3.5 h-3.5" />
+12 -12
View File
@@ -32,7 +32,7 @@ function FeatureTags({ text }: { text: string }) {
return (
<div className="space-y-3">
<h4 className="font-bold text-ink text-base">{title}</h4>
<h3 className="font-bold text-ink text-base">{title}</h3>
<div className="flex flex-wrap gap-2">
{tags.map((tag) => (
<span
@@ -99,7 +99,7 @@ function MetricCard({
<Icon className="w-6 h-6" />
</div>
<div ref={ref} className="text-3xl sm:text-4xl font-black text-brand tabular-nums leading-none mb-1">
<div ref={ref} className="text-3xl sm:text-4xl font-black text-brand-ink tabular-nums leading-none mb-1">
{displayValue}
</div>
@@ -112,7 +112,7 @@ function MetricCard({
export function ProductValueSection({ product }: ProductValueSectionProps) {
return (
<section className="relative bg-white py-20 sm:py-28 md:py-36 overflow-hidden">
<section className="relative bg-bg-primary py-20 sm:py-28 md:py-36 overflow-hidden">
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative">
<motion.div
initial={{ opacity: 0, y: 32 }}
@@ -123,13 +123,13 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
产品功能
</span>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-ink tracking-tight leading-[0.95] max-w-3xl">
{product.title}
<span className="text-brand"> 核心能力</span>
<span className="text-brand-ink"> 核心能力</span>
</h2>
<p className="text-lg text-text-secondary max-w-2xl mt-6 leading-relaxed">
{product.overview}
@@ -176,7 +176,7 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
<div>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
核心优势
</span>
</div>
@@ -194,7 +194,7 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
}}
className="bain-card p-5 flex items-start gap-3"
>
<CheckCircle2 className="w-5 h-5 text-brand mt-0.5 shrink-0" />
<CheckCircle2 className="w-5 h-5 text-brand-ink mt-0.5 shrink-0" />
<p className="text-sm font-medium text-text-secondary leading-relaxed">{benefit}</p>
</motion.div>
))}
@@ -205,14 +205,14 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
<div>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
技术规格
</span>
</div>
<div className="bain-card p-6">
<div className="flex items-center gap-3 mb-4">
<Shield className="w-5 h-5 text-brand" />
<h4 className="font-bold text-ink text-sm">技术保障</h4>
<Shield className="w-5 h-5 text-brand-ink" />
<h3 className="font-bold text-ink text-sm">技术保障</h3>
</div>
<ul className="space-y-3">
{product.specs.slice(0, 5).map((spec, index) => (
@@ -228,7 +228,7 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
}}
className="flex items-start gap-3 text-sm text-text-secondary"
>
<ArrowRight className="w-4 h-4 text-brand mt-0.5 shrink-0" />
<ArrowRight className="w-4 h-4 text-brand-ink mt-0.5 shrink-0" />
<span>{spec}</span>
</motion.li>
))}
@@ -249,7 +249,7 @@ export function ProductValueSection({ product }: ProductValueSectionProps) {
<div className="mb-12">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
效果数据
</span>
</div>
@@ -54,7 +54,7 @@ function AnimatedCounter({ value, duration = 2000 }: { value: string; duration?:
}, [isInView, value, duration]);
return (
<div ref={ref} className="text-3xl sm:text-4xl font-black text-brand tabular-nums leading-none">
<div ref={ref} className="text-3xl sm:text-4xl font-black text-brand-ink tabular-nums leading-none">
{displayValue}
</div>
);
@@ -70,7 +70,7 @@ export function DetailTrustSection({
if (!hasContent) return null;
return (
<section className="relative py-20 sm:py-28 md:py-36 overflow-hidden bg-white">
<section className="relative py-20 sm:py-28 md:py-36 overflow-hidden bg-bg-primary">
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative z-10">
{dataProofs.length > 0 && (
<div className="mb-20">
@@ -83,7 +83,7 @@ export function DetailTrustSection({
>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
用真实效果证明价值
</span>
</div>
@@ -31,7 +31,7 @@ export function EarlyAccessNotice() {
>
<p
id="early-access-notice-heading"
className="text-sm font-semibold text-brand mb-1"
className="text-sm font-semibold text-brand-ink mb-1"
>
{EARLY_ACCESS.label}
</p>
@@ -40,7 +40,7 @@ export function EarlyAccessNotice() {
</p>
<Link
href="/contact"
className="inline-flex items-center gap-1 text-sm font-medium text-brand underline-offset-4 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2 focus-visible:ring-offset-bg-secondary rounded"
className="inline-flex items-center gap-1 min-h-6 text-sm font-medium text-brand-ink underline-offset-4 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2 focus-visible:ring-offset-bg-secondary rounded"
>
了解共创合作
<span aria-hidden="true">→</span>
+2 -2
View File
@@ -135,12 +135,12 @@ function SignalCard({ signal }: { signal: L3Signal }) {
: 'hover:border-brand/40 hover:shadow-md hover:-translate-y-1'
)}
>
<span className="inline-block text-[11px] tracking-[0.15em] uppercase font-bold text-brand mb-4">
<span className="inline-block text-[11px] tracking-[0.15em] uppercase font-bold text-brand-ink mb-4">
{eyebrow}
</span>
<div
className="w-10 h-10 mb-4 flex items-center justify-center rounded-md bg-brand-soft text-brand"
className="w-10 h-10 mb-4 flex items-center justify-center rounded-md bg-brand-soft text-brand-ink"
aria-hidden="true"
>
<Icon className="w-5 h-5" />
+3 -3
View File
@@ -124,9 +124,9 @@ export function PressableButton({
primary:
'bg-brand text-white shadow-sm hover:shadow-brand-hover',
secondary:
'bg-white text-ink border border-border-primary hover:border-brand/30 hover:shadow-md',
'bg-bg-elevated text-ink border border-border-primary hover:border-brand/30 hover:shadow-md',
ghost:
'bg-transparent text-brand hover:bg-brand/5',
'bg-transparent text-brand-ink hover:bg-brand/5',
};
const content = (
@@ -175,7 +175,7 @@ export function HoverLink({
<a
href={href}
className={`group inline-flex items-center gap-1.5 font-medium transition-colors duration-fast ease-standard ${
color === 'brand' ? 'text-brand' : 'text-text-secondary hover:text-brand'
color === 'brand' ? 'text-brand-ink' : 'text-text-secondary hover:text-brand-ink'
} ${className}`}
>
<span className="relative inline-block">
+3 -3
View File
@@ -30,7 +30,7 @@ export function ProductCard({ product }: ProductCardProps) {
className="group"
>
<Link href={`/products/${product.id}`} className="block">
<div className="relative h-full rounded-2xl bg-white border border-border-primary overflow-hidden hover:border-brand/30 hover:shadow-lg hover:-translate-y-1 transition-all duration-300">
<div className="relative h-full rounded-2xl bg-bg-elevated border border-border-primary overflow-hidden hover:border-brand/30 hover:shadow-lg hover:-translate-y-1 transition-all duration-300">
<div className="aspect-video relative overflow-hidden bg-bg-secondary">
<Image
src={product.image}
@@ -54,7 +54,7 @@ export function ProductCard({ product }: ProductCardProps) {
</div>
<div className="p-6">
<h3 className="text-xl font-bold text-ink mb-3 group-hover:text-brand transition-colors">
<h3 className="text-xl font-bold text-ink mb-3 group-hover:text-brand-ink transition-colors">
{product.title}
</h3>
@@ -75,7 +75,7 @@ export function ProductCard({ product }: ProductCardProps) {
</div>
)}
<div className="flex items-center gap-2 text-sm font-semibold text-brand group-hover:gap-3 transition-all">
<div className="flex items-center gap-2 text-sm font-semibold text-brand-ink group-hover:gap-3 transition-all">
了解详情
<ArrowRight className="w-4 h-4" />
</div>
+6 -6
View File
@@ -20,7 +20,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
const icons: LucideIcon[] = [Zap, Clock, Users, Award, TrendingUp];
return (
<section className="relative bg-white py-20 sm:py-28 md:py-36 overflow-hidden">
<section className="relative bg-bg-primary py-20 sm:py-28 md:py-36 overflow-hidden">
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10 relative">
<motion.div
initial={{ opacity: 0, y: 32 }}
@@ -31,7 +31,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
服务能力
</span>
</div>
@@ -47,7 +47,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
<div className="mb-16">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
核心能力
</span>
</div>
@@ -92,7 +92,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
<div>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
服务优势
</span>
</div>
@@ -110,7 +110,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
}}
className="bain-card p-5 flex items-start gap-3"
>
<CheckCircle2 className="w-5 h-5 text-brand mt-0.5 shrink-0" />
<CheckCircle2 className="w-5 h-5 text-brand-ink mt-0.5 shrink-0" />
<p className="text-sm font-medium text-text-secondary leading-relaxed">{benefit}</p>
</motion.div>
))}
@@ -122,7 +122,7 @@ export function ServiceValueSection({ service }: ServiceValueSectionProps) {
<div>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
服务流程
</span>
</div>
@@ -43,7 +43,7 @@ export function SolutionCard({ solution }: SolutionCardProps) {
className="group"
>
<Link href={`/solutions/${solution.id}`} className="block">
<div className="relative h-full rounded-2xl bg-white border border-border-primary overflow-hidden hover:border-brand/30 hover:shadow-lg hover:-translate-y-1 transition-all duration-300">
<div className="relative h-full rounded-2xl bg-bg-elevated border border-border-primary overflow-hidden hover:border-brand/30 hover:shadow-lg hover:-translate-y-1 transition-all duration-300">
<div className="aspect-video relative overflow-hidden bg-bg-secondary flex items-center justify-center">
{solution.image ? (
<Image
@@ -53,7 +53,7 @@ export function SolutionCard({ solution }: SolutionCardProps) {
className="object-cover group-hover:scale-105 transition-transform duration-150"
/>
) : (
<Icon className="w-16 h-16 text-brand/20 group-hover:text-brand/40 transition-colors" />
<Icon className="w-16 h-16 text-brand-ink/20 group-hover:text-brand-ink/40 transition-colors" />
)}
<div className="absolute top-4 left-4 flex gap-2">
@@ -71,7 +71,7 @@ export function SolutionCard({ solution }: SolutionCardProps) {
</div>
<div className="p-6">
<h3 className="text-xl font-bold text-ink mb-3 group-hover:text-brand transition-colors">
<h3 className="text-xl font-bold text-ink mb-3 group-hover:text-brand-ink transition-colors">
{solution.title}
</h3>
@@ -90,7 +90,7 @@ export function SolutionCard({ solution }: SolutionCardProps) {
</div>
)}
<div className="flex items-center gap-2 text-sm font-semibold text-brand group-hover:gap-3 transition-all">
<div className="flex items-center gap-2 text-sm font-semibold text-brand-ink group-hover:gap-3 transition-all">
查看方案
<ArrowRight className="w-4 h-4" />
</div>
@@ -142,7 +142,7 @@ export function ServiceCard({ service }: ServiceCardProps) {
{service.features.slice(0, 3).map((feature) => (
<span
key={feature}
className="px-2.5 py-1 rounded-md text-xs font-medium bg-white text-blue-600 border border-border-primary"
className="px-2.5 py-1 rounded-md text-xs font-medium bg-bg-elevated text-blue-600 border border-border-primary"
>
{feature.split(':')[0]}
</span>
+5 -5
View File
@@ -26,12 +26,12 @@ export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
>
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
行业方案
</span>
</div>
<h2 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-black text-ink tracking-tight leading-[0.95] max-w-3xl">
为<span className="text-brand">{solution.industry}</span>量身定制
为<span className="text-brand-ink">{solution.industry}</span>量身定制
</h2>
<p className="text-lg text-text-secondary max-w-2xl mt-6 leading-relaxed">
{solution.description}
@@ -124,7 +124,7 @@ export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
<div className="mb-12">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
价值主张
</span>
</div>
@@ -170,7 +170,7 @@ export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
<div className="mb-12">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand">
<span className="text-[13px] tracking-[0.12em] font-semibold text-brand-ink">
产品组合
</span>
</div>
@@ -192,7 +192,7 @@ export function SolutionValueSection({ solution }: SolutionValueSectionProps) {
{solution.suiteCombination.primaryProducts.map((product) => (
<span
key={product}
className="px-4 py-2 bg-brand-soft/50 text-brand text-sm font-semibold border border-brand/20"
className="px-4 py-2 bg-brand-soft/50 text-brand-ink text-sm font-semibold border border-brand/20"
>
{product}
</span>
+1 -1
View File
@@ -15,7 +15,7 @@ export function Footer() {
.flatMap(group => group.items);
return (
<footer className="bg-dark-bg text-white relative overflow-hidden" data-testid="footer" role="contentinfo">
<footer className="bg-dark-bg text-white relative overflow-hidden [&_a]:inline-flex [&_a]:items-center [&_a]:min-h-6" data-testid="footer" role="contentinfo">
<div className="max-w-container mx-auto px-4 sm:px-6 lg:px-10">
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-12 gap-10 lg:gap-12 py-16 lg:py-20">
<div data-testid="card-brand" className="col-span-2 lg:col-span-4">
+2 -2
View File
@@ -85,7 +85,7 @@ export function MegaDropdown({ label, groups, isOpen, isActive, onToggle, onOpen
<span className="text-xs text-text-muted">{group.description}</span>
)}
{group.highlight && (
<Sparkles className="w-3.5 h-3.5 text-brand" />
<Sparkles className="w-3.5 h-3.5 text-brand-ink" />
)}
</div>
@@ -101,7 +101,7 @@ export function MegaDropdown({ label, groups, isOpen, isActive, onToggle, onOpen
<span className={`shrink-0 px-1.5 py-0.5 text-[10px] font-medium ${
item.badge === '敬请期待'
? 'bg-bg-tertiary text-text-muted'
: 'bg-brand/10 text-brand'
: 'bg-brand/10 text-brand-ink'
}`}>
{item.badge === '敬请期待' && <Lock className="w-2.5 h-2.5 inline mr-0.5" />}
{item.badge}
+2 -2
View File
@@ -60,13 +60,13 @@ export function MobileTabBar() {
<Icon
className={cn(
'w-6 h-6 transition-colors duration-300',
active ? 'text-brand' : 'text-text-muted group-hover:text-text-secondary'
active ? 'text-brand-ink' : 'text-text-muted group-hover:text-text-secondary'
)}
/>
<span
className={cn(
'text-xs mt-1 transition-colors duration-300',
active ? 'text-brand font-medium' : 'text-text-muted'
active ? 'text-brand-ink font-medium' : 'text-text-muted'
)}
>
{tab.label}
+1 -1
View File
@@ -19,7 +19,7 @@ const buttonVariants = cva(
ghost:
'text-text-secondary hover:bg-bg-secondary hover:text-text-primary active:scale-[0.97] transition-all duration-fast ease-standard',
link:
'text-text-primary underline-offset-4 hover:text-brand relative after:absolute after:bottom-0 after:left-0 after:h-[2px] after:w-0 hover:after:w-full after:bg-brand after:transition-all after:duration-normal after:ease-standard',
'text-text-primary underline-offset-4 hover:text-brand-ink relative after:absolute after:bottom-0 after:left-0 after:h-[2px] after:w-0 hover:after:w-full after:bg-brand after:transition-all after:duration-normal after:ease-standard',
destructive:
'bg-error text-white shadow-sm hover:bg-error-hover hover:-translate-y-px active:translate-y-0 active:scale-[0.97] transition-all duration-fast ease-standard',
},
+2 -2
View File
@@ -111,7 +111,7 @@ const ContextMenuCheckboxItem = React.forwardRef<
>
<span className="absolute left-2 flex size-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<Check className="size-4 text-brand" />
<Check className="size-4 text-brand-ink" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
@@ -136,7 +136,7 @@ const ContextMenuRadioItem = React.forwardRef<
>
<span className="absolute left-2 flex size-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<Circle className="size-2 fill-brand text-brand" />
<Circle className="size-2 fill-brand text-brand-ink" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
+1 -1
View File
@@ -45,7 +45,7 @@ const VARIANT_STYLES: Record<CTAButtonVariant, string> = {
dark:
'text-dark-text-primary border border-dark-border hover:border-dark-text-muted hover:bg-white/5 px-10 py-4 font-semibold text-base',
inline:
'text-text-primary hover:text-brand px-0 py-0 font-medium text-sm bg-transparent border-0',
'text-text-primary hover:text-brand-ink px-0 py-0 font-medium text-sm bg-transparent border-0',
};
const ARROW_STYLES: Record<CTAButtonVariant, string> = {
+2 -2
View File
@@ -113,7 +113,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
>
<span className="absolute left-2 flex size-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<Check className="size-4 text-brand" />
<Check className="size-4 text-brand-ink" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
@@ -138,7 +138,7 @@ const DropdownMenuRadioItem = React.forwardRef<
>
<span className="absolute left-2 flex size-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator>
<Circle className="size-2 fill-brand text-brand" />
<Circle className="size-2 fill-brand text-brand-ink" />
</DropdownMenuPrimitive.ItemIndicator>
</span>
{children}
+2 -2
View File
@@ -31,7 +31,7 @@ const LabeledInput = React.forwardRef<HTMLInputElement, LabeledInputProps>(
>
{label}
{required && (
<span className="text-brand ml-1.5" aria-hidden="true">*</span>
<span className="text-brand-ink ml-1.5" aria-hidden="true">*</span>
)}
</Label>
)}
@@ -56,7 +56,7 @@ const LabeledInput = React.forwardRef<HTMLInputElement, LabeledInputProps>(
{error && (
<p
id={errorId}
className="mt-1.5 text-sm text-brand"
className="mt-1.5 text-sm text-brand-ink"
role="alert"
data-testid="error-message"
>
+2 -2
View File
@@ -31,7 +31,7 @@ const LabeledTextarea = React.forwardRef<HTMLTextAreaElement, LabeledTextareaPro
>
{label}
{required && (
<span className="text-brand ml-1.5" aria-hidden="true">*</span>
<span className="text-brand-ink ml-1.5" aria-hidden="true">*</span>
)}
</Label>
)}
@@ -56,7 +56,7 @@ const LabeledTextarea = React.forwardRef<HTMLTextAreaElement, LabeledTextareaPro
{error && (
<p
id={errorId}
className="mt-1.5 text-sm text-brand"
className="mt-1.5 text-sm text-brand-ink"
role="alert"
data-testid="error-message"
>
+1 -1
View File
@@ -26,7 +26,7 @@ interface MetricCardProps {
}
const accentStyles: Record<string, string> = {
brand: 'text-brand bg-brand-bg',
brand: 'text-brand-ink bg-brand-bg',
blue: 'text-accent-blue bg-accent-blue/10',
teal: 'text-accent-teal bg-accent-teal/10',
amber: 'text-accent-amber bg-accent-amber/10',
+3 -3
View File
@@ -68,7 +68,7 @@ export function MilestoneTimeline({
)}>
<div className="w-2 h-2 rounded-full bg-brand" />
</div>
<div className="text-sm font-bold text-brand mb-1 tracking-wider">
<div className="text-sm font-bold text-brand-ink mb-1 tracking-wider">
{item.year}
</div>
<h4 className={cn('text-lg font-semibold mb-2', isDark ? 'text-white' : 'text-text-primary')}>
@@ -80,7 +80,7 @@ export function MilestoneTimeline({
{item.highlight && (
<div className={cn(
'mt-3 inline-flex items-center px-3 py-1 rounded-full text-xs font-medium',
isDark ? 'bg-brand/10 text-brand' : 'bg-brand-bg text-brand'
isDark ? 'bg-brand/10 text-brand-ink' : 'bg-brand-bg text-brand-ink'
)}>
{item.highlight}
</div>
@@ -112,7 +112,7 @@ export function MilestoneTimeline({
)}>
<div className="w-2 h-2 rounded-full bg-brand" />
</div>
<div className="text-sm font-bold text-brand mb-2 tracking-wider">
<div className="text-sm font-bold text-brand-ink mb-2 tracking-wider">
{item.year}
</div>
<h4 className={cn('text-base font-semibold mb-2 leading-snug', isDark ? 'text-white' : 'text-text-primary')}>
+1 -1
View File
@@ -36,7 +36,7 @@ export function SectionLabel({
)}
>
<div className="w-10 h-px bg-brand" />
<span className="text-[13px] tracking-[0.15em] font-medium text-brand">
<span className="text-[13px] tracking-[0.15em] font-medium text-brand-ink">
{children}
</span>
</div>
+2 -2
View File
@@ -30,7 +30,7 @@ const RadioGroupItem = React.forwardRef<
ref={ref}
data-slot="radio-group-item"
className={cn(
'aspect-square size-4 rounded-full border border-border-primary bg-bg-primary text-brand shadow-sm',
'aspect-square size-4 rounded-full border border-border-primary bg-bg-primary text-brand-ink shadow-sm',
'focus:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2',
'disabled:cursor-not-allowed disabled:opacity-50',
'data-[state=checked]:border-brand',
@@ -43,7 +43,7 @@ const RadioGroupItem = React.forwardRef<
data-slot="radio-group-indicator"
className="flex items-center justify-center"
>
<Circle className="size-2.5 fill-brand text-brand" />
<Circle className="size-2.5 fill-brand text-brand-ink" />
</RadioGroupPrimitive.Indicator>
</RadioGroupPrimitive.Item>
));
+1 -1
View File
@@ -133,7 +133,7 @@ const SelectItem = React.forwardRef<
>
<span className="absolute right-2 flex size-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="size-4 text-brand" />
<Check className="size-4 text-brand-ink" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>