feat: port cms design tokens and base styles into trade-pro theme.css
Full port of astro-site-runtime tokens.css (183 tokens, V2 bright-blue) and base.css (element baseline, layout utilities, forms, FAQ, reveal motion, 620px mobile block) into the trade-pro theme. All cms variables renamed with the --sf-tp- prefix keeping semantic names; button system rebuilt as sf-tp-btn with sm/lg sizes and ghost/outline/round variants so platform custom.css (.btn/.primary/.request/.button/.nav-btn) can never restyle it. Phase-2 short token aliases (--sf-tp-primary etc.) and .pro-* bridge rules retained, now driven by the cms tokens. Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -114,6 +114,45 @@ def test_trade_pro_builds_real_site(factory):
|
||||
assert '>首页<' not in home.text
|
||||
assert '<meta name="theme-color" content="#0b3d91"' in home.text
|
||||
|
||||
def test_trade_pro_theme_css_ports_token_system():
|
||||
from pathlib import Path
|
||||
css = (Path(__file__).resolve().parent.parent / 'themes' / 'trade-pro' / 'theme.css').read_text(encoding='utf-8')
|
||||
# 令牌覆盖:cms tokens.css 的核心令牌语义都应有对应 --sf-tp-* 变量
|
||||
for token in ('primary', 'accent', 'bg', 'text', 'muted', 'radius', 'font'):
|
||||
assert f'--sf-tp-{token}' in css, token
|
||||
# 移植覆盖:cms 语义令牌以 --sf-tp- 前缀保留语义名(tokens.css 各组取样)
|
||||
for token in ('color-brand-primary', 'color-brand-secondary', 'color-neutral-900', 'color-text-primary',
|
||||
'color-surface-page', 'color-border-default', 'font-family-sans', 'font-size-display',
|
||||
'font-weight-bold', 'line-height-normal', 'space-4', 'space-section-y', 'container-page-max',
|
||||
'breakpoint-tablet', 'radius-full', 'shadow-md', 'button-height-md', 'input-border-radius',
|
||||
'card-padding-md', 'duration-fast', 'easing-standard', 'z-modal', 'focus-outline-color', 'icon-size-md'):
|
||||
assert f'--sf-tp-{token}' in css, token
|
||||
# 基础样式:base.css 元素基线、按钮体系与响应式断点已移植
|
||||
for fragment in ('box-sizing', '.sf-tp-btn--lg', '.sf-tp-btn--ghost', '@media (max-width: 620px)',
|
||||
'prefers-reduced-motion'):
|
||||
assert fragment in css, fragment
|
||||
# 样式隔离红线:不得出现平台按钮选择器
|
||||
import re
|
||||
for sel in ('.btn{', '.primary{', '.request{', '.button{', '.nav-btn{'):
|
||||
assert sel not in css, sel
|
||||
|
||||
def test_trade_pro_build_contains_tokens(factory):
|
||||
# 构建产物 assets/theme.css 含 --sf-tp- 变量(复用 test_trade_pro_builds_real_site 的构建流程)
|
||||
sid = site(factory)
|
||||
assert factory.post(f'/api/factory/sites/{sid}/bootstrap').status_code == 200
|
||||
selected = factory.put(f'/api/factory/sites/{sid}/theme', json={'theme': 'trade-pro', 'version': '1.0.0'})
|
||||
assert selected.status_code == 200, selected.text
|
||||
result = factory.post(f'/api/sites/{sid}/builds', json={})
|
||||
assert result.status_code == 200, result.text
|
||||
bid = result.json()['version']
|
||||
home = factory.get(f'/preview/{sid}/{bid}/')
|
||||
assert home.status_code == 200, home.text[:400]
|
||||
assert 'assets/theme.css' in home.text # 首页 HTML 确实链接主题样式表
|
||||
css = factory.get(f'/preview/{sid}/{bid}/assets/theme.css')
|
||||
assert css.status_code == 200, css.text[:200]
|
||||
assert '--sf-tp-primary' in css.text # Phase 2 短令牌别名随构建分发
|
||||
assert '--sf-tp-color-brand-primary' in css.text # cms 令牌全集随构建分发
|
||||
|
||||
def test_frontend_entries_include_trade_pro():
|
||||
from pathlib import Path
|
||||
base = Path(__file__).resolve().parent.parent
|
||||
|
||||
+755
-15
@@ -1,15 +1,755 @@
|
||||
/* trade-pro design tokens (skeleton; full cms port in Phase 3) */
|
||||
:root{--sf-tp-primary:#0b3d91;--sf-tp-accent:#f5a623;--sf-tp-bg:#ffffff;--sf-tp-text:#1a2332;--sf-tp-muted:#5a6a7e;--sf-tp-radius:8px;--sf-tp-font:'Inter',system-ui,-apple-system,sans-serif}
|
||||
body{margin:0;font-family:var(--sf-tp-font);color:var(--sf-tp-text);background:var(--sf-tp-bg)}
|
||||
/* trade-pro buttons use the sf-tp- prefix so the platform custom.css rules
|
||||
(.btn/.primary/.request/.button/.nav-btn) can never restyle them. */
|
||||
.sf-tp-btn{display:inline-block;padding:.7rem 1.4rem;border-radius:var(--sf-tp-radius);background:var(--sf-tp-primary);color:#fff;text-decoration:none;font-weight:600;border:1px solid var(--sf-tp-primary)}
|
||||
.sf-tp-btn:hover{background:#0a357d}
|
||||
.sf-tp-btn:focus-visible{outline:2px solid var(--sf-tp-accent);outline-offset:2px}
|
||||
.sf-tp-btn-outline{background:transparent;color:var(--sf-tp-primary)}
|
||||
.sf-tp-btn-outline:hover{background:#eef4fc;color:#0a357d}
|
||||
/* Minimal skeleton accents so the page is not unstyled before the Phase 3 port. */
|
||||
.pro-utility{background:var(--sf-tp-primary);color:#fff}
|
||||
.pro-eyebrow{color:var(--sf-tp-primary);letter-spacing:.14em}
|
||||
.pro-home-hero em{color:var(--sf-tp-primary)}
|
||||
a{color:var(--sf-tp-primary)}
|
||||
/**
|
||||
* trade-pro theme.css — cms 设计令牌与基础样式全量移植(Task 8)
|
||||
*
|
||||
* 来源:
|
||||
* - D:/project/cms/runtimes/astro-site-runtime/src/styles/tokens.css
|
||||
* (ThemeTokenSet V2「bright-blue」,183 令牌,2026-10-09 设计稿)
|
||||
* - D:/project/cms/runtimes/astro-site-runtime/src/styles/base.css
|
||||
* (元素基线 + 布局/按钮/表单/FAQ 工具类,约 445 行)
|
||||
* 像素基准:D:/project/cms/runtimes/astro-site-runtime/dist/hesupipe/en/
|
||||
* 移植日期:2026-10-23
|
||||
*
|
||||
* 移植规则:
|
||||
* 1. cms 变量统一加 --sf-tp- 前缀并保留语义名
|
||||
* (--color-brand-primary → --sf-tp-color-brand-primary,引用处同步)。
|
||||
* 2. 按钮/交互类名一律 sf-tp- 前缀:.btn → .sf-tp-btn(尺寸 --sm/--lg、
|
||||
* 变体 solid/--ghost/--outline/--round)。严禁 .btn/.primary/.request/
|
||||
* .button/.nav-btn——平台 custom.css 会无条件覆盖这些选择器。
|
||||
* 3. base.css 的元素选择器(html/body/h1-h4/p/a/:focus-visible/表单/details)
|
||||
* 保留全局形态:本文件只作用于静态站点产物与预览,不进管理后台 UI。
|
||||
* 4. cms 源文件无 Astro scoped(.astro-XXXX 哈希)规则,零跳过;组件级
|
||||
* 样式(卡片/特性栅格桌面形态等)随 Task 10 布局移植。
|
||||
* 5. 文件末尾保留 Phase 2 骨架的短令牌别名(--sf-tp-primary 等,供
|
||||
* pro.css 与既有模板引用)与 .pro-* 桥接规则,值全部改由 cms 令牌驱动。
|
||||
*/
|
||||
|
||||
:root {
|
||||
/* ── 3.1 品牌(10)明亮蓝 + 天蓝辅助 + 强调蓝 ── */
|
||||
--sf-tp-color-brand-primary: #0874df;
|
||||
--sf-tp-color-brand-primary-strong: #075ebc;
|
||||
--sf-tp-color-brand-primary-deep: #054a94;
|
||||
--sf-tp-color-brand-primary-soft: #edf7ff;
|
||||
--sf-tp-color-brand-secondary: #4bc4ff;
|
||||
--sf-tp-color-brand-secondary-strong: #2fa8e8;
|
||||
--sf-tp-color-brand-secondary-soft: #eaf6ff;
|
||||
--sf-tp-color-brand-accent: #075bb5;
|
||||
--sf-tp-color-brand-accent-strong: #054a94;
|
||||
--sf-tp-color-brand-accent-soft: #e9f4ff;
|
||||
|
||||
/* ── 3.2 中性(11)冷调蓝灰 ── */
|
||||
--sf-tp-color-neutral-0: #ffffff;
|
||||
--sf-tp-color-neutral-50: #f8fbff;
|
||||
--sf-tp-color-neutral-100: #f3f7fb;
|
||||
--sf-tp-color-neutral-200: #e5ecf4;
|
||||
--sf-tp-color-neutral-300: #dfe8f2;
|
||||
--sf-tp-color-neutral-400: #b7c5d5;
|
||||
--sf-tp-color-neutral-500: #8497aa;
|
||||
--sf-tp-color-neutral-600: #64748b;
|
||||
--sf-tp-color-neutral-700: #52647b;
|
||||
--sf-tp-color-neutral-800: #27415f;
|
||||
--sf-tp-color-neutral-900: #071b38;
|
||||
|
||||
/* ── 3.3 语义(12)── */
|
||||
--sf-tp-color-success-default: #1e7a46;
|
||||
--sf-tp-color-success-strong: #175e35;
|
||||
--sf-tp-color-success-soft: #e3f2e9;
|
||||
--sf-tp-color-warning-default: #9a6700;
|
||||
--sf-tp-color-warning-strong: #7a5200;
|
||||
--sf-tp-color-warning-soft: #fbf0d9;
|
||||
--sf-tp-color-danger-default: #c42b1c;
|
||||
--sf-tp-color-danger-strong: #9e2114;
|
||||
--sf-tp-color-danger-soft: #fbe7e4;
|
||||
--sf-tp-color-info-default: #0b5fa5;
|
||||
--sf-tp-color-info-strong: #094a80;
|
||||
--sf-tp-color-info-soft: #e5f0f9;
|
||||
|
||||
/* ── 3.4 文本(13)── */
|
||||
--sf-tp-color-text-primary: #071b38;
|
||||
--sf-tp-color-text-secondary: #52647b;
|
||||
--sf-tp-color-text-muted: #64748b;
|
||||
--sf-tp-color-text-inverse: #ffffff;
|
||||
--sf-tp-color-text-inverse-muted: #b7c5d5;
|
||||
--sf-tp-color-text-brand: #0874df;
|
||||
--sf-tp-color-text-link: #075bb5;
|
||||
--sf-tp-color-text-link-hover: #054a94;
|
||||
--sf-tp-color-text-on-brand: #ffffff;
|
||||
--sf-tp-color-text-on-brand-muted: #d9ecff;
|
||||
--sf-tp-color-text-disabled: #b7c5d5;
|
||||
--sf-tp-color-text-success: #1e7a46;
|
||||
--sf-tp-color-text-danger: #c42b1c;
|
||||
|
||||
/* ── 3.5 表面(8)── */
|
||||
--sf-tp-color-surface-page: #ffffff;
|
||||
--sf-tp-color-surface-default: #ffffff;
|
||||
--sf-tp-color-surface-muted: #f3f7fb;
|
||||
--sf-tp-color-surface-inverse: #03192f;
|
||||
--sf-tp-color-surface-inverse-muted: #0b2440;
|
||||
--sf-tp-color-surface-brand: #0874df;
|
||||
--sf-tp-color-surface-brand-soft: #edf7ff;
|
||||
--sf-tp-color-surface-overlay: rgba(3, 25, 47, 0.55);
|
||||
|
||||
/* ── 3.6 边框(5)── */
|
||||
--sf-tp-color-border-subtle: #e5ecf4;
|
||||
--sf-tp-color-border-default: #dfe8f2;
|
||||
--sf-tp-color-border-strong: #b7c5d5;
|
||||
--sf-tp-color-border-brand: #0874df;
|
||||
--sf-tp-color-border-inverse: rgba(255, 255, 255, 0.16);
|
||||
|
||||
/* ── 3.7 字体家族(3)── */
|
||||
--sf-tp-font-family-sans: "Inter", "Noto Sans SC", "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
|
||||
--sf-tp-font-family-heading: var(--sf-tp-font-family-sans);
|
||||
--sf-tp-font-family-mono: "JetBrains Mono", "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;
|
||||
|
||||
/* ── 3.8 字号阶梯(11)── */
|
||||
--sf-tp-font-size-root: 16px;
|
||||
--sf-tp-font-size-xs: 12px;
|
||||
--sf-tp-font-size-sm: 13px;
|
||||
--sf-tp-font-size-md: 16px;
|
||||
--sf-tp-font-size-lg: 17px;
|
||||
--sf-tp-font-size-xl: 20px;
|
||||
--sf-tp-font-size-2xl: 24px;
|
||||
--sf-tp-font-size-3xl: 31px;
|
||||
--sf-tp-font-size-4xl: 38px;
|
||||
--sf-tp-font-size-5xl: 48px;
|
||||
--sf-tp-font-size-display: clamp(42px, 5vw, 62px);
|
||||
|
||||
/* ── 3.9 字重/行高/字间距(11)── */
|
||||
--sf-tp-font-weight-regular: 400;
|
||||
--sf-tp-font-weight-medium: 500;
|
||||
--sf-tp-font-weight-semibold: 650;
|
||||
--sf-tp-font-weight-bold: 800;
|
||||
--sf-tp-line-height-tight: 1.05;
|
||||
--sf-tp-line-height-snug: 1.35;
|
||||
--sf-tp-line-height-normal: 1.55;
|
||||
--sf-tp-line-height-relaxed: 1.7;
|
||||
--sf-tp-letter-spacing-tight: -0.035em;
|
||||
--sf-tp-letter-spacing-normal: 0;
|
||||
--sf-tp-letter-spacing-wide: 0.16em;
|
||||
|
||||
/* ── 3.10 间距(16)4/8px 体系 ── */
|
||||
--sf-tp-space-0: 0;
|
||||
--sf-tp-space-1: 4px;
|
||||
--sf-tp-space-2: 8px;
|
||||
--sf-tp-space-3: 12px;
|
||||
--sf-tp-space-4: 16px;
|
||||
--sf-tp-space-5: 20px;
|
||||
--sf-tp-space-6: 24px;
|
||||
--sf-tp-space-8: 32px;
|
||||
--sf-tp-space-10: 40px;
|
||||
--sf-tp-space-12: 48px;
|
||||
--sf-tp-space-16: 64px;
|
||||
--sf-tp-space-20: 80px;
|
||||
--sf-tp-space-24: 96px;
|
||||
--sf-tp-space-section-y: clamp(48px, 6vw, 84px);
|
||||
--sf-tp-space-field-gap: 20px;
|
||||
--sf-tp-space-grid-gutter: 20px;
|
||||
|
||||
/* ── 3.11 布局(13)── */
|
||||
--sf-tp-container-page-max: 1160px;
|
||||
--sf-tp-container-content-max: 768px;
|
||||
--sf-tp-container-narrow-max: 640px;
|
||||
--sf-tp-container-page-margin-mobile: 20px;
|
||||
--sf-tp-container-page-margin-desktop: 40px;
|
||||
--sf-tp-grid-columns-mobile: 4;
|
||||
--sf-tp-grid-columns-tablet: 8;
|
||||
--sf-tp-grid-columns-desktop: 12;
|
||||
--sf-tp-breakpoint-mobile-min: 320px;
|
||||
--sf-tp-breakpoint-tablet: 768px;
|
||||
--sf-tp-breakpoint-desktop: 1024px;
|
||||
--sf-tp-breakpoint-wide: 1440px;
|
||||
--sf-tp-container-wide-gutter: auto;
|
||||
|
||||
/* ── 3.12 形制(15)明亮蓝灰调阴影 ── */
|
||||
--sf-tp-radius-none: 0;
|
||||
--sf-tp-radius-xs: 4px;
|
||||
--sf-tp-radius-sm: 10px;
|
||||
--sf-tp-radius-md: 8px;
|
||||
--sf-tp-radius-lg: 12px;
|
||||
--sf-tp-radius-full: 999px;
|
||||
--sf-tp-border-width-hairline: 1px;
|
||||
--sf-tp-border-width-medium: 2px;
|
||||
--sf-tp-border-width-strong: 3px;
|
||||
--sf-tp-shadow-none: none;
|
||||
--sf-tp-shadow-xs: 0 7px 22px rgba(4, 32, 64, 0.05);
|
||||
--sf-tp-shadow-sm: 0 10px 26px rgba(10, 45, 85, 0.08);
|
||||
--sf-tp-shadow-md: 0 14px 38px rgba(10, 45, 85, 0.10);
|
||||
--sf-tp-shadow-lg: 0 18px 48px rgba(10, 45, 85, 0.16);
|
||||
--sf-tp-shadow-focus-ring: 0 0 0 3px rgba(8, 116, 223, 0.30);
|
||||
|
||||
/* ── 3.13 Button(8)── */
|
||||
--sf-tp-button-height-sm: 36px;
|
||||
--sf-tp-button-height-md: 46px;
|
||||
--sf-tp-button-height-lg: 52px;
|
||||
--sf-tp-button-padding-x-sm: 18px;
|
||||
--sf-tp-button-padding-x-md: 26px;
|
||||
--sf-tp-button-padding-x-lg: 34px;
|
||||
--sf-tp-button-border-radius: 10px;
|
||||
--sf-tp-button-font-weight: 700;
|
||||
|
||||
/* ── 3.14 Input(6)── */
|
||||
--sf-tp-input-height-sm: 36px;
|
||||
--sf-tp-input-height-md: 46px;
|
||||
--sf-tp-input-padding-x: 14px;
|
||||
--sf-tp-input-border-radius: 6px;
|
||||
--sf-tp-input-border-width: 1px;
|
||||
--sf-tp-input-font-size: 16px;
|
||||
|
||||
/* ── 3.15 Card(5)── */
|
||||
--sf-tp-card-border-radius: 8px;
|
||||
--sf-tp-card-border-width: 1px;
|
||||
--sf-tp-card-padding-sm: 16px;
|
||||
--sf-tp-card-padding-md: 20px;
|
||||
--sf-tp-card-padding-lg: 30px;
|
||||
|
||||
/* ── 3.16 图片比例(9)── */
|
||||
--sf-tp-ratio-square: 1 / 1;
|
||||
--sf-tp-ratio-portrait: 3 / 4;
|
||||
--sf-tp-ratio-landscape: 4 / 3;
|
||||
--sf-tp-ratio-photo: 3 / 2;
|
||||
--sf-tp-ratio-cinema: 21 / 9;
|
||||
--sf-tp-ratio-product-main: 4 / 3;
|
||||
--sf-tp-ratio-product-thumb: 1 / 1;
|
||||
--sf-tp-ratio-case-cover: 16 / 9;
|
||||
--sf-tp-ratio-news-cover: 3 / 2;
|
||||
|
||||
/* ── 3.17 动效(8)── */
|
||||
--sf-tp-duration-instant: 100ms;
|
||||
--sf-tp-duration-fast: 180ms;
|
||||
--sf-tp-duration-normal: 240ms;
|
||||
--sf-tp-duration-slow: 400ms;
|
||||
--sf-tp-easing-standard: cubic-bezier(0.2, 0, 0, 1);
|
||||
--sf-tp-easing-emphasized: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--sf-tp-easing-entry: cubic-bezier(0.05, 0.7, 0.1, 1);
|
||||
--sf-tp-easing-exit: cubic-bezier(0.3, 0, 0.8, 0.15);
|
||||
|
||||
/* ── 3.18 z-index(10)── */
|
||||
--sf-tp-z-base: 0;
|
||||
--sf-tp-z-raised: 10;
|
||||
--sf-tp-z-dropdown: 100;
|
||||
--sf-tp-z-sticky: 200;
|
||||
--sf-tp-z-drawer: 300;
|
||||
--sf-tp-z-overlay: 400;
|
||||
--sf-tp-z-modal: 500;
|
||||
--sf-tp-z-tooltip: 600;
|
||||
--sf-tp-z-toast: 700;
|
||||
--sf-tp-z-skip-link: 1000;
|
||||
|
||||
/* ── 3.19 焦点(5)── */
|
||||
--sf-tp-focus-outline-width: 2px;
|
||||
--sf-tp-focus-outline-style: solid;
|
||||
--sf-tp-focus-outline-color: #0874df;
|
||||
--sf-tp-focus-outline-offset: 2px;
|
||||
--sf-tp-focus-outline-color-inverse: #4bc4ff;
|
||||
|
||||
/* ── 3.20 图标(4)── */
|
||||
--sf-tp-icon-size-sm: 16px;
|
||||
--sf-tp-icon-size-md: 20px;
|
||||
--sf-tp-icon-size-lg: 24px;
|
||||
--sf-tp-icon-size-xl: 46px;
|
||||
|
||||
/* ── Phase 2 短令牌别名(pro.css 与既有模板引用;值随 cms 令牌走)── */
|
||||
--sf-tp-primary: var(--sf-tp-color-brand-primary);
|
||||
--sf-tp-accent: var(--sf-tp-color-brand-secondary);
|
||||
--sf-tp-bg: var(--sf-tp-color-surface-page);
|
||||
--sf-tp-text: var(--sf-tp-color-text-primary);
|
||||
--sf-tp-muted: var(--sf-tp-color-text-muted);
|
||||
--sf-tp-radius: var(--sf-tp-radius-md);
|
||||
--sf-tp-font: var(--sf-tp-font-family-sans);
|
||||
}
|
||||
|
||||
/* ── 元素基线(base.css)── */
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: var(--sf-tp-font-size-root);
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--sf-tp-color-surface-page);
|
||||
color: var(--sf-tp-color-text-primary);
|
||||
font-family: var(--sf-tp-font-family-sans);
|
||||
font-size: var(--sf-tp-font-size-md);
|
||||
line-height: var(--sf-tp-line-height-normal);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
font-family: var(--sf-tp-font-family-heading);
|
||||
font-weight: var(--sf-tp-font-weight-bold);
|
||||
line-height: var(--sf-tp-line-height-tight);
|
||||
letter-spacing: var(--sf-tp-letter-spacing-tight);
|
||||
margin: 0 0 var(--sf-tp-space-4);
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
h1 { font-size: var(--sf-tp-font-size-display); }
|
||||
h2 { font-size: var(--sf-tp-font-size-3xl); }
|
||||
h3 { font-size: var(--sf-tp-font-size-xl); }
|
||||
h4 { font-size: var(--sf-tp-font-size-lg); }
|
||||
|
||||
p {
|
||||
margin: 0 0 var(--sf-tp-space-4);
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline: var(--sf-tp-focus-outline-width) var(--sf-tp-focus-outline-style) var(--sf-tp-focus-outline-color);
|
||||
outline-offset: var(--sf-tp-focus-outline-offset);
|
||||
}
|
||||
|
||||
/* ── 布局工具 ── */
|
||||
|
||||
.wrap {
|
||||
width: min(1440px, 90vw);
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding-block: var(--sf-tp-space-section-y);
|
||||
}
|
||||
|
||||
.section--soft {
|
||||
background: linear-gradient(135deg, var(--sf-tp-color-neutral-50), var(--sf-tp-color-surface-brand-soft));
|
||||
}
|
||||
|
||||
.section--dark {
|
||||
color: var(--sf-tp-color-text-inverse);
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
color-mix(in srgb, var(--sf-tp-color-surface-inverse) 94%, transparent),
|
||||
color-mix(in srgb, var(--sf-tp-color-brand-primary) 60%, transparent)
|
||||
);
|
||||
}
|
||||
|
||||
.section--dark h2,
|
||||
.section--dark h3 {
|
||||
color: var(--sf-tp-color-text-inverse);
|
||||
}
|
||||
|
||||
/* 眉题(eyebrow):强调蓝 + 宽字距大写(.pro-eyebrow 为 Phase 2 桥接同款) */
|
||||
.eyebrow,
|
||||
.pro-eyebrow {
|
||||
color: var(--sf-tp-color-brand-accent);
|
||||
font-weight: var(--sf-tp-font-weight-bold);
|
||||
letter-spacing: var(--sf-tp-letter-spacing-wide);
|
||||
text-transform: uppercase;
|
||||
font-size: var(--sf-tp-font-size-xs);
|
||||
margin-block-end: var(--sf-tp-space-3);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.section--dark .eyebrow {
|
||||
color: var(--sf-tp-color-text-inverse-muted);
|
||||
}
|
||||
|
||||
/* 圆形图标位 */
|
||||
.icon-circle {
|
||||
width: var(--sf-tp-icon-size-xl);
|
||||
height: var(--sf-tp-icon-size-xl);
|
||||
margin: 0 auto 8px;
|
||||
border-radius: var(--sf-tp-radius-full);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: var(--sf-tp-color-text-brand);
|
||||
background: var(--sf-tp-color-surface-brand-soft);
|
||||
font-size: var(--sf-tp-font-size-2xl);
|
||||
font-weight: var(--sf-tp-font-weight-bold);
|
||||
}
|
||||
|
||||
/* 等宽数据 */
|
||||
.mono {
|
||||
font-family: var(--sf-tp-font-family-mono);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* ── Button(cms §4.2 V2:蓝底白字 + 悬浮上抬;类名 sf-tp- 前缀隔离平台 custom.css)── */
|
||||
|
||||
.sf-tp-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--sf-tp-space-2);
|
||||
min-height: var(--sf-tp-button-height-md);
|
||||
padding-inline: var(--sf-tp-button-padding-x-md);
|
||||
font-family: var(--sf-tp-font-family-sans);
|
||||
font-size: var(--sf-tp-font-size-md);
|
||||
font-weight: var(--sf-tp-button-font-weight);
|
||||
line-height: var(--sf-tp-line-height-snug);
|
||||
border-radius: var(--sf-tp-button-border-radius);
|
||||
border: var(--sf-tp-border-width-hairline) solid var(--sf-tp-color-border-brand);
|
||||
background: var(--sf-tp-color-surface-brand);
|
||||
color: var(--sf-tp-color-text-on-brand);
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
transition:
|
||||
background-color var(--sf-tp-duration-fast) var(--sf-tp-easing-standard),
|
||||
border-color var(--sf-tp-duration-fast) var(--sf-tp-easing-standard),
|
||||
color var(--sf-tp-duration-fast) var(--sf-tp-easing-standard),
|
||||
box-shadow var(--sf-tp-duration-fast) var(--sf-tp-easing-standard),
|
||||
transform var(--sf-tp-duration-fast) var(--sf-tp-easing-standard);
|
||||
}
|
||||
|
||||
.sf-tp-btn:hover {
|
||||
transform: translateY(calc(-1 * var(--sf-tp-space-1)));
|
||||
background: var(--sf-tp-color-brand-primary-strong);
|
||||
box-shadow: var(--sf-tp-shadow-sm);
|
||||
}
|
||||
|
||||
.sf-tp-btn:active {
|
||||
background: var(--sf-tp-color-brand-primary-deep);
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/* 尺寸 */
|
||||
.sf-tp-btn--sm {
|
||||
min-height: var(--sf-tp-button-height-sm);
|
||||
padding-inline: var(--sf-tp-button-padding-x-sm);
|
||||
font-size: var(--sf-tp-font-size-sm);
|
||||
}
|
||||
|
||||
.sf-tp-btn--lg {
|
||||
min-height: var(--sf-tp-button-height-lg);
|
||||
padding-inline: var(--sf-tp-button-padding-x-lg);
|
||||
font-size: var(--sf-tp-font-size-lg);
|
||||
}
|
||||
|
||||
/* 变体:ghost(浅底品牌字) */
|
||||
.sf-tp-btn--ghost {
|
||||
background: var(--sf-tp-color-surface-default);
|
||||
color: var(--sf-tp-color-text-brand);
|
||||
}
|
||||
|
||||
.sf-tp-btn--ghost:hover {
|
||||
background: var(--sf-tp-color-surface-brand-soft);
|
||||
color: var(--sf-tp-color-text-brand);
|
||||
}
|
||||
|
||||
/* 变体:outline(描边品牌字;.sf-tp-btn-outline 为 Phase 2 骨架既有类名) */
|
||||
.sf-tp-btn--outline,
|
||||
.sf-tp-btn-outline {
|
||||
background: transparent;
|
||||
color: var(--sf-tp-color-text-brand);
|
||||
}
|
||||
|
||||
.sf-tp-btn--outline:hover,
|
||||
.sf-tp-btn-outline:hover {
|
||||
background: var(--sf-tp-color-surface-brand-soft);
|
||||
color: var(--sf-tp-color-text-link-hover);
|
||||
}
|
||||
|
||||
/* 变体:round(药丸) */
|
||||
.sf-tp-btn--round {
|
||||
border-radius: var(--sf-tp-radius-full);
|
||||
min-height: var(--sf-tp-space-10);
|
||||
padding-inline: var(--sf-tp-space-6);
|
||||
font-size: var(--sf-tp-font-size-sm);
|
||||
}
|
||||
|
||||
/* 深色表面上的描边按钮 */
|
||||
.section--dark .sf-tp-btn--ghost,
|
||||
.cta-band .sf-tp-btn--ghost {
|
||||
background: var(--sf-tp-color-surface-default);
|
||||
color: var(--sf-tp-color-text-brand);
|
||||
}
|
||||
|
||||
/* ── Skip link(无障碍跳转,z 最高)── */
|
||||
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
inset-block-start: var(--sf-tp-space-2);
|
||||
inset-inline-start: var(--sf-tp-space-2);
|
||||
z-index: var(--sf-tp-z-skip-link);
|
||||
background: var(--sf-tp-color-surface-default);
|
||||
color: var(--sf-tp-color-text-brand);
|
||||
padding: var(--sf-tp-space-3) var(--sf-tp-space-4);
|
||||
border-radius: var(--sf-tp-radius-sm);
|
||||
box-shadow: var(--sf-tp-shadow-md);
|
||||
transform: translateY(calc(-100 * var(--sf-tp-space-4)));
|
||||
}
|
||||
|
||||
.skip-link:focus-visible {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/* ── 视觉隐藏(屏幕阅读器可用)── */
|
||||
|
||||
.visually-hidden {
|
||||
position: absolute;
|
||||
width: var(--sf-tp-space-1);
|
||||
height: var(--sf-tp-space-1);
|
||||
overflow: hidden;
|
||||
clip-path: inset(50%);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* ── 药丸选项卡 ── */
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: calc(var(--sf-tp-space-4) - var(--sf-tp-space-1));
|
||||
margin-block-end: var(--sf-tp-space-8);
|
||||
}
|
||||
|
||||
.tab {
|
||||
border: 0;
|
||||
min-width: 130px;
|
||||
padding: calc(var(--sf-tp-space-3)) var(--sf-tp-space-5);
|
||||
border-radius: var(--sf-tp-radius-full);
|
||||
background: var(--sf-tp-color-surface-muted);
|
||||
color: var(--sf-tp-color-text-secondary);
|
||||
font-weight: var(--sf-tp-font-weight-semibold);
|
||||
font-size: var(--sf-tp-font-size-sm);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background-color var(--sf-tp-duration-fast) var(--sf-tp-easing-standard),
|
||||
color var(--sf-tp-duration-fast) var(--sf-tp-easing-standard);
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
background: var(--sf-tp-color-surface-brand);
|
||||
color: var(--sf-tp-color-text-on-brand);
|
||||
}
|
||||
|
||||
/* ── 表单(label 永远可见)── */
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-weight: var(--sf-tp-font-weight-semibold);
|
||||
font-size: var(--sf-tp-font-size-sm);
|
||||
margin-block-end: var(--sf-tp-space-2);
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
border: var(--sf-tp-input-border-width) solid var(--sf-tp-color-border-default);
|
||||
border-radius: var(--sf-tp-input-border-radius);
|
||||
padding: var(--sf-tp-space-3) var(--sf-tp-space-4);
|
||||
background: var(--sf-tp-color-surface-default);
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
input:focus-visible,
|
||||
select:focus-visible,
|
||||
textarea:focus-visible {
|
||||
border-color: var(--sf-tp-color-border-brand);
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 120px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
/* ── FAQ 折叠(原生 details,静态可抓取)── */
|
||||
|
||||
details {
|
||||
border: var(--sf-tp-border-width-hairline) solid var(--sf-tp-color-border-subtle);
|
||||
border-radius: var(--sf-tp-radius-sm);
|
||||
margin-block-end: calc(var(--sf-tp-space-3) - var(--sf-tp-space-1));
|
||||
background: var(--sf-tp-color-surface-default);
|
||||
}
|
||||
|
||||
summary {
|
||||
cursor: pointer;
|
||||
padding: var(--sf-tp-space-4) calc(var(--sf-tp-space-4) + var(--sf-tp-space-1));
|
||||
font-weight: var(--sf-tp-font-weight-semibold);
|
||||
}
|
||||
|
||||
details[open] summary {
|
||||
border-block-end: var(--sf-tp-border-width-hairline) solid var(--sf-tp-color-border-subtle);
|
||||
}
|
||||
|
||||
details p {
|
||||
padding: var(--sf-tp-space-4) calc(var(--sf-tp-space-4) + var(--sf-tp-space-1));
|
||||
color: var(--sf-tp-color-text-muted);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── Phase 2 桥接:骨架期 .pro-* 强调样式改由 cms 令牌驱动(Task 10 布局移植后由组件样式接管)── */
|
||||
|
||||
.pro-utility {
|
||||
background: var(--sf-tp-color-surface-inverse);
|
||||
color: var(--sf-tp-color-text-inverse-muted);
|
||||
}
|
||||
|
||||
.pro-home-hero em {
|
||||
color: var(--sf-tp-color-text-brand);
|
||||
}
|
||||
|
||||
/* ── 滚动浮现动效(reduced-motion 与无 JS 时默认可见,渐进增强)── */
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-reveal] {
|
||||
opacity: 0;
|
||||
transform: translateY(calc(var(--sf-tp-space-3)));
|
||||
transition:
|
||||
opacity var(--sf-tp-duration-slow) var(--sf-tp-easing-entry),
|
||||
transform var(--sf-tp-duration-slow) var(--sf-tp-easing-entry);
|
||||
transition-delay: calc(var(--sf-tp-duration-fast) * var(--reveal-i, 0));
|
||||
}
|
||||
|
||||
[data-reveal].is-visible {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 令牌媒介覆盖(tokens.css)── */
|
||||
|
||||
/* 移动端栅格沟槽覆盖 */
|
||||
@media (max-width: 767px) {
|
||||
:root {
|
||||
--sf-tp-space-grid-gutter: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
/* prefers-reduced-motion:时长归零 */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
:root {
|
||||
--sf-tp-duration-instant: 0ms;
|
||||
--sf-tp-duration-fast: 0ms;
|
||||
--sf-tp-duration-normal: 0ms;
|
||||
--sf-tp-duration-slow: 0ms;
|
||||
}
|
||||
}
|
||||
|
||||
/* ════════ 移动端适配(base.css,2026-10-14 设计稿 620px 断点)════════ */
|
||||
|
||||
@media (max-width: 620px) {
|
||||
:root {
|
||||
--sf-tp-font-size-md: 13px;
|
||||
--sf-tp-font-size-lg: 13px;
|
||||
--sf-tp-font-size-xl: 15px;
|
||||
--sf-tp-font-size-2xl: 18px;
|
||||
--sf-tp-font-size-3xl: 22px;
|
||||
--sf-tp-font-size-4xl: 26px;
|
||||
--sf-tp-space-section-y: 30px;
|
||||
--sf-tp-card-border-radius: 7px;
|
||||
--sf-tp-button-height-md: 37px;
|
||||
--sf-tp-button-height-lg: 42px;
|
||||
--sf-tp-button-border-radius: 999px;
|
||||
--sf-tp-icon-size-xl: 39px;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 13px;
|
||||
line-height: 1.42;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
width: calc(100% - 30px);
|
||||
}
|
||||
|
||||
h1 { font-size: 28px; line-height: 1.05; }
|
||||
h2 { font-size: 22px; line-height: 1.1; }
|
||||
h3 { margin-block-end: 5px; }
|
||||
|
||||
.eyebrow,
|
||||
.pro-eyebrow {
|
||||
font-size: 9px;
|
||||
letter-spacing: 0.2em;
|
||||
margin-block-end: 7px;
|
||||
}
|
||||
|
||||
.sf-tp-btn {
|
||||
min-height: 37px;
|
||||
padding-inline: 18px;
|
||||
font-size: 11px;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.section { padding-block: 30px; }
|
||||
|
||||
/* 卡片:2 列紧凑(组件类,桌面形态随 Task 10 移植) */
|
||||
.cards {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.card { border-radius: 7px; }
|
||||
|
||||
.card-media {
|
||||
aspect-ratio: 16 / 9;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 9px 10px 11px;
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
font-size: 13px;
|
||||
margin-block-end: 2px;
|
||||
}
|
||||
|
||||
.card p {
|
||||
font-size: 11px;
|
||||
line-height: 1.25;
|
||||
margin-block-end: 5px;
|
||||
}
|
||||
|
||||
.more { font-size: 10px; }
|
||||
|
||||
/* 特性:2 列横排(图标左、文字右) */
|
||||
.feature-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.feature {
|
||||
min-height: 92px;
|
||||
text-align: left;
|
||||
padding: 12px;
|
||||
display: grid;
|
||||
grid-template-columns: 44px 1fr;
|
||||
align-content: center;
|
||||
column-gap: 7px;
|
||||
}
|
||||
|
||||
.feature .icon-circle {
|
||||
grid-row: 1 / 3;
|
||||
align-self: center;
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.feature h3 {
|
||||
font-size: 12px;
|
||||
margin: 0 0 3px;
|
||||
}
|
||||
|
||||
.feature p {
|
||||
font-size: 10px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
/* 选项卡 */
|
||||
.tabs { gap: 8px; margin-block-end: 16px; }
|
||||
.tab { min-width: auto; padding: 9px 14px; font-size: 11px; }
|
||||
|
||||
/* FAQ */
|
||||
details { margin-block-end: 6px; }
|
||||
summary { padding: 10px 12px; font-size: 12px; }
|
||||
details p { padding: 0 12px 10px; font-size: 11px; }
|
||||
|
||||
/* 表单 */
|
||||
input, select, textarea { padding: 8px 10px; font-size: 13px; }
|
||||
label { font-size: 11px; }
|
||||
textarea { min-height: 80px; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user