diff --git a/tests/test_theme_registry.py b/tests/test_theme_registry.py
index 1ca5cf9..2712018 100644
--- a/tests/test_theme_registry.py
+++ b/tests/test_theme_registry.py
@@ -798,6 +798,182 @@ def test_trade_pro_standard_layout_structure(factory):
assert ssoup.select_one('.sf-tp-page-hero-lead') is not None # bootstrap 摘要在导语位
+def test_trade_pro_variant_pages_structure(factory):
+ # Task 11:brand/service/faq/search/notfound 五个次要页面精修(布局移植
+ # 收官)。设计参照:上游四主题 1.3.0/1.4.0 对应页面的信息架构
+ # (automotive 1.4.0 brand 页最完整:横幅 + 面包屑 + 锚点按钮 + 车型
+ # 网格 + 品牌故事;其余为通用信息页骨架)+ 已建立的 sf-tp 设计语言
+ # (page-hero/面包屑/卡片网格/排版层/空态)。
+ # 数据事实(make_context):brand kind 由 related 提供同品牌产品
+ # (fields.brand == 页题);service/faq 仅页面条目上下文(正文富文本,
+ # sanitize 剥离 details/summary——theme.css 的折叠样式只服务块系统注入
+ # 的 custom_blocks,模板正文只能走排版层);search 为构建器生成的
+ # noindex 静态页(site-runtime.js + search-index.json 的 ?q= 客户端检索,
+ # 上游四主题同款机制,#sf-search/#sf-search-results/#sf-search-count
+ # 三钩子是平台 JS 契约);notfound 走 mode='notfound'(noindex meta)。
+ import re
+ sid = site(factory)
+ assert factory.post(f'/api/factory/sites/{sid}/bootstrap').status_code == 200
+ # ── 数据夹具:显式品牌(正文/封面)+ 2 同品牌产品 + 1 异品牌产品 +
+ # 服务条目(正文/封面)+ FAQ 页(page_template 显式指定)──
+ made = factory.post(f'/api/sites/{sid}/entries', json={
+ 'type': 'brand', 'title': 'Quanta', 'route': '/brands/quanta/',
+ 'cover': 'https://imgs.example/quanta-hall.jpg',
+ 'summary': 'German engineering brand for flow control systems.',
+ 'body': '
Quanta manufactures flow control systems for export markets.
Heritage
Founded as an industrial valve maker.
'})
+ assert made.status_code in (200, 201), made.text
+ batch = [
+ {'type': 'product', 'title': 'Quanta Valve V1', 'route': '/product/quanta-valve-v1/',
+ 'summary': 'Control valve from Quanta.', 'meta': {'fields': {'brand': 'Quanta', 'category': 'Valves'}}},
+ {'type': 'product', 'title': 'Quanta Pump P2', 'route': '/product/quanta-pump-p2/',
+ 'summary': 'Centrifugal pump from Quanta.', 'meta': {'fields': {'brand': 'Quanta'}}},
+ {'type': 'product', 'title': 'Rival Actuator A9', 'route': '/product/rival-actuator/',
+ 'summary': 'Actuator from another brand.', 'meta': {'fields': {'brand': 'Rival'}}},
+ {'type': 'service', 'title': 'Export Documentation Service', 'route': '/services/export-docs/',
+ 'cover': 'https://imgs.example/docs-desk.jpg',
+ 'summary': 'Certificates of origin, packing lists and customs paperwork.',
+ 'body': 'We prepare the complete document set for every shipment.
What is included
Commercial invoice, packing list and certificate of origin.
'},
+ {'type': 'page', 'title': 'Shipping FAQ', 'route': '/faq-shipping/',
+ 'summary': 'Frequently asked questions about shipping and documents.',
+ 'body': 'Answers about lead times and paperwork.
How long is the lead time?
Standard orders ship in 15 working days.
',
+ 'meta': {'page_template': 'faq'}},
+ ]
+ for row in batch:
+ r = factory.post(f'/api/sites/{sid}/entries', json=row)
+ assert r.status_code in (200, 201), r.text
+ assert factory.put(f'/api/factory/sites/{sid}/theme', json={'theme': 'trade-pro', 'version': '1.0.0'}).status_code == 200
+ bid = factory.post(f'/api/sites/{sid}/builds', json={}).json()['version']
+
+ # ── v3 契约抽验:五种页面 200 / 唯一 h1 / pro-header + pro-footer ──
+ variant_urls = ['/brands/quanta/', '/services/export-docs/', '/faq-shipping/', '/search/', '/404.html']
+ pages = {}
+ for url in variant_urls:
+ r = factory.get(f'/preview/{sid}/{bid}{url}')
+ assert r.status_code == 200, (url, r.text[:200])
+ soup = BeautifulSoup(r.text, 'html.parser')
+ assert len(soup.find_all('h1')) == 1, url
+ assert soup.select_one('.pro-header') and soup.select_one('.pro-footer'), url
+ # 交互箭头一律 SVG(Task 9 契约)
+ assert not re.search(r'[←→↗↘⌕▾]', ''.join(a.get_text() for a in soup.find_all('a'))), url
+ pages[url] = soup
+
+ # ── brand:hero(面包屑 Home › Brands › 品名 + 封面底图 + 锚点按钮)+
+ # 同品牌产品网格(related,异品牌不混入)+ 品牌介绍(正文存在才渲染)──
+ bsoup = pages['/brands/quanta/']
+ hero = bsoup.select_one('section.sf-tp-page-hero.sf-tp-brand-hero')
+ assert hero is not None
+ bg = hero.select_one('.sf-tp-page-hero-bg')
+ assert bg is not None and 'quanta-hall.jpg' in bg.get('src', '')
+ assert hero.select_one('.sf-tp-breadcrumb a[href$="/"]')
+ assert hero.select_one('.sf-tp-breadcrumb a[href$="/brands/"]')
+ assert hero.select_one('.sf-tp-breadcrumb-current').get_text(strip=True) == 'Quanta'
+ assert hero.select_one('.sf-tp-page-hero-copy h1').get_text(strip=True) == 'Quanta'
+ # hero 锚点按钮(automotive 1.4.0 同款信息架构):有产品才渲染
+ assert hero.select_one('.sf-tp-page-hero-copy a.sf-tp-btn[href="#tp-brand-products"]') is not None
+ # 产品网格:related(fields.brand == 页题),异品牌产品不出现在页面上
+ # (groups 无稳定顺序——断言与插入顺序解耦,只验集合内容)
+ grid = bsoup.select_one('.sf-tp-brand-products')
+ assert grid is not None and grid.get('id') == 'tp-brand-products'
+ cards = grid.select('.sf-tp-card-grid .sf-tp-card')
+ assert len(cards) == 2
+ card_titles = {c.select_one('h3').get_text(strip=True) for c in cards}
+ assert card_titles == {'Quanta Valve V1', 'Quanta Pump P2'}
+ assert 'Rival Actuator' not in grid.get_text()
+ assert cards[0].select_one('.sf-tp-card-media') and cards[0].select_one('a.sf-tp-more svg')
+ assert grid.select_one('.sf-tp-section-head a.sf-tp-more[href$="/products/"] svg')
+ # 品牌介绍:body 存在才渲染(排版层双挂);空品牌不虚构介绍
+ profile = bsoup.select_one('.sf-tp-brand-profile .sf-tp-article-body .pro-rich')
+ assert profile is not None and 'Heritage' in profile.get_text()
+
+ # ── service:hero(面包屑 Home › Services › 标题)+ 正文排版层 + CTA 侧卡 ──
+ ssoup = pages['/services/export-docs/']
+ shero = ssoup.select_one('section.sf-tp-page-hero.sf-tp-service-hero')
+ assert shero is not None
+ sbg = shero.select_one('.sf-tp-page-hero-bg')
+ assert sbg is not None and 'docs-desk.jpg' in sbg.get('src', '')
+ assert shero.select_one('.sf-tp-breadcrumb a[href$="/services/"]')
+ assert shero.select_one('.sf-tp-breadcrumb-current').get_text(strip=True) == 'Export Documentation Service'
+ body = ssoup.select_one('.sf-tp-service-body.sf-tp-article-body .pro-rich')
+ assert body is not None and 'What is included' in body.get_text()
+ aside = ssoup.select_one('.sf-tp-service-aside')
+ assert aside is not None
+ assert aside.select_one('a.sf-tp-btn[href$="/contact/"]') is not None # CTA
+ assert aside.select_one('a[href$="/services/"]') is not None # 返回服务列表
+
+ # ── faq:hero + 正文排版层(平台无 faq 内容类型,正文富文本承担)+
+ # 引导联系卡 ──
+ fsoup = pages['/faq-shipping/']
+ fhero = fsoup.select_one('section.sf-tp-page-hero.sf-tp-faq-hero')
+ assert fhero is not None
+ assert fhero.select_one('.sf-tp-breadcrumb a[href$="/faq/"]')
+ fbody = fsoup.select_one('.sf-tp-faq-body.sf-tp-article-body .pro-rich')
+ assert fbody is not None and 'How long is the lead time?' in fbody.get_text()
+ guide = fsoup.select_one('.sf-tp-faq-guide')
+ assert guide is not None and guide.select_one('a.sf-tp-btn[href$="/contact/"]')
+
+ # ── search:与上游四主题同款平台机制(site-runtime.js ?q= 客户端检索
+ # search-index.json),三钩子契约保留 + noindex + sf-tp 化的搜索面板 ──
+ psoup = pages['/search/']
+ assert 'noindex' in str(psoup.find('meta', attrs={'name': 'robots'}))
+ assert psoup.select_one('main#main-content.sf-search-page')
+ assert psoup.select_one('label[for="sf-search"]')
+ inp = psoup.select_one('input#sf-search[type="search"]')
+ assert inp is not None and inp.get('autofocus') is not None
+ assert psoup.select_one('#sf-search-results') is not None
+ assert psoup.select_one('#sf-search-count[aria-live="polite"]') is not None
+ assert psoup.find('h1').get_text(strip=True) == 'Site Search'
+ # 机制资源随构建分发:site-runtime.js 页面引用 + 检索索引含真实内容
+ # (write_assets 把 search-index.json 写在 dist 根,site-runtime.js 以
+ # 相对解析——检索 URL 契约)
+ sr = factory.get(f'/preview/{sid}/{bid}/search/')
+ assert 'site-runtime.js' in sr.text
+ idx = factory.get(f'/preview/{sid}/{bid}/search-index.json')
+ assert idx.status_code == 200 and 'Quanta Valve V1' in idx.text
+ # search/notfound 无结尾 CTA 带(pro.html 既有分支)
+ assert 'pro-end-cta' not in sr.text
+
+ # ── notfound:品牌化 404(大标题 + 英文文案 + 双按钮 + SVG 图标)──
+ nsoup = pages['/404.html']
+ assert 'noindex' in str(nsoup.find('meta', attrs={'name': 'robots'}))
+ nsec = nsoup.select_one('.sf-tp-notfound')
+ assert nsec is not None
+ assert nsec.find('h1').get_text(strip=True) == '404'
+ assert nsec.select_one('.icon-circle svg') is not None # icon 宏渲染
+ assert nsec.select_one('a.sf-tp-btn[href$="/"]') is not None # Back to home
+ assert nsec.select_one('a[href$="/products/"]') is not None # Browse products
+ assert 'pro-end-cta' not in str(nsoup)
+
+ # 本构建链接全通(新增面包屑/CTA/锚点不产生断链)
+ report = factory.get(f'/api/sites/{sid}/builds/{bid}/report').json()
+ assert not report['errors'] and not report['broken_links'] and not report['missing_local_images']
+
+ # ── 空数据形态:空品牌(无产品/无正文)只显空态不虚构介绍;空服务/
+ # 空 FAQ 正文整段隐藏、CTA/引导保留 ──
+ sid2 = site(factory)
+ for row in [
+ {'type': 'brand', 'title': 'Orphan', 'route': '/brands/orphan/'},
+ {'type': 'service', 'title': 'Placeholder Service', 'route': '/services/placeholder/'},
+ {'type': 'page', 'title': 'Bare FAQ', 'route': '/faq-bare/', 'meta': {'page_template': 'faq'}},
+ ]:
+ r = factory.post(f'/api/sites/{sid2}/entries', json=row)
+ assert r.status_code in (200, 201), r.text
+ assert factory.put(f'/api/factory/sites/{sid2}/theme', json={'theme': 'trade-pro', 'version': '1.0.0'}).status_code == 200
+ bid2 = factory.post(f'/api/sites/{sid2}/builds', json={}).json()['version']
+ for url, absent, present in [
+ ('/brands/orphan/', ['.sf-tp-brand-products', '.sf-tp-brand-profile', '.sf-tp-card'], ['.sf-tp-listing-empty']),
+ ('/services/placeholder/', ['.sf-tp-service-body'], ['.sf-tp-service-aside']),
+ ('/faq-bare/', ['.sf-tp-faq-body'], ['.sf-tp-faq-guide']),
+ ]:
+ r = factory.get(f'/preview/{sid2}/{bid2}{url}')
+ assert r.status_code == 200, (url, r.text[:200])
+ soup = BeautifulSoup(r.text, 'html.parser')
+ assert len(soup.find_all('h1')) == 1, url
+ for sel in absent:
+ assert soup.select_one(sel) is None, (url, sel)
+ for sel in present:
+ assert soup.select_one(sel) is not None, (url, sel)
+
+
def test_trade_pro_chrome_layout(factory):
# Task 10j:cms 页眉/页脚 chrome 视觉还原 + 手机端抽屉导航。
# 设计源 D:/project/cms/runtimes/astro-site-runtime/src/components/
diff --git a/themes/trade-pro/pages/brand.html b/themes/trade-pro/pages/brand.html
index 9705456..d4105cc 100644
--- a/themes/trade-pro/pages/brand.html
+++ b/themes/trade-pro/pages/brand.html
@@ -1 +1,85 @@
-BRAND PROFILE / PARTNERS{{page.title}}
{{page.summary}}
{{cover(page,'brand')}}
{{body_copy(content,page)}}{% if related %}{{section_title('PRODUCT LINE','Related products','/products/')}}{{grid(related,'product')}}{% endif %}
+{# trade-pro brand detail — 品牌详情精修(Task 11,次要页面收官)。
+ 设计参照(本轮无 cms 源对应):上游 themes/automotive/versions/1.4.0/
+ pages/brand.html 的信息架构——品牌横幅(面包屑 + 眉题/h1/导语 + 页内
+ 锚点按钮 + 品牌图)→ 车型/产品网格(section heading + "全部"动作位)→
+ 品牌故事(眉题 + h2 + 正文);industrial 1.3.0 为同构薄形态。本模板以
+ sf-tp 设计语言重组:sf-tp-page-hero(10c 内页 hero:封面底图 + brand-soft
+ 罩层)+ sf-tp-section-head/card-grid(10a 卡片系)+ sf-tp-article-body
+ 排版层双挂(10d)。
+ 数据事实(make_context 对 brand kind):related = fields.brand 与页题
+ (或 fields.brand 字段)一致的产品/车型集合——品牌页的产品网格只信它;
+ 派生品牌页(builder 从产品 brand 字段派生 /brands//)body/cover
+ 恒空、summary 是平台占位串「相关品牌及产品」——导语按 authored 判定
+ 排除占位串(home.html 排除「首页」同款决策),空品牌不虚构介绍:
+ 无产品给数据无关的英文导语 + 空态卡,绝不编造品牌故事。
+ 面包屑 Brands 链接 /brands/(required_sections 恒保证该路由存在);
+ hero 锚点按钮锚到 #tp-brand-products(构建器豁免 # 锚点,10h 同款)。 #}
+{% set tp_brand_summary = page.summary if page.summary and page.summary != '相关品牌及产品' else '' %}
+{# 导语优先级:authored 摘要 > 数据派生计数(Jinja 三元与 or 的优先级易误读,
+ 显式分行赋值避免歧义)> 空品牌通用引导 #}
+{% if tp_brand_summary %}{% set tp_brand_lead = tp_brand_summary %}
+{% elif related %}{% set tp_brand_lead = ('One product from ' if related|length == 1 else related|length ~ ' products from ') ~ page.title ~ ' — specifications and export documentation included.' %}
+{% else %}{% set tp_brand_lead = 'Products assigned to this brand in the admin console appear here automatically.' %}{% endif %}
+
+ {% if safe_image(page.cover) %}
{% endif %}
+
+
+
+{% if related %}
+
+{% else %}
+
+{% endif %}
+{% if content %}
+
+
+
+
+ BRAND PROFILE
+
About {{ page.title }}
+
+
+
{{ body_copy(content, page) }}
+
+
+{% endif %}
diff --git a/themes/trade-pro/pages/faq.html b/themes/trade-pro/pages/faq.html
index 6db86e9..c8e6db5 100644
--- a/themes/trade-pro/pages/faq.html
+++ b/themes/trade-pro/pages/faq.html
@@ -1,2 +1,56 @@
-SUPPORT / FAQ{{page.title}}
{{page.summary}}
-ANSWERSFrequently asked questions.
Cooperation process, trade terms and common questions.
{{body_copy(content,page)}}{% if page.cover %}
}})
{% endif %}
+{# trade-pro faq — FAQ 页精修(Task 11)。
+ 设计参照(本轮无 cms 源对应):上游 industrial/automotive 1.3.0/1.4.0 的
+ faq 页与 service 共用通用信息页薄形态;本模板以 sf-tp 设计语言定 FAQ
+ 专属口径:sf-tp-page-hero(10c)→ 问题正文(sf-tp-article-body 排版层
+ 双挂,10d)→ 深色引导联系卡(找不到答案 → /contact/,10d 侧栏 CTA
+ 同款深底白按钮语汇)。
+ 数据事实(make_context 对 faq kind):平台无 faq 内容类型——FAQ 页由
+ 普通页面条目承担(meta.page_template='faq' 显式指定,或 /faq 前缀路由
+ 推断),内容 = 单一富文本 body。sanitize 的 ALLOWED_TAGS 不含
+ details/summary(正文富文本带不进折叠结构);theme.css 的 details/
+ summary 折叠样式(Task 8)服务的是块系统注入的 custom_blocks(编辑器
+ faq 块原生 details 渲染在 sf-canvas 区),与本模板正交共存——模板
+ 正文只能走排版层,问题/答案的分节由正文自身 h2/h3 承担(10g/10h 同
+ 决策)。body 为空 → 正文区块整段隐藏换空态卡;引导联系卡恒渲染
+ (真实动作位)。面包屑/链接指向 /faq/(required_sections 恒保证;
+ 当前页恰为 /faq/ 时自指隐藏)。 #}
+
+ {% if safe_image(page.cover) %}
{% endif %}
+
+
+
+
+
SUPPORT / FAQ
+
{{ page.title }}
+ {% if page.summary %}
{{ page.summary }}
{% endif %}
+
+
+
+
+
+ {% if content %}
+
+
+ ANSWERS
+
Frequently asked questions
+
+
+
{{ body_copy(content, page) }}
+ {% else %}
+
+
No answers published here yet
+
Questions added to this page in the admin console appear here automatically.
+
+ {% endif %}
+
+
+
diff --git a/themes/trade-pro/pages/notfound.html b/themes/trade-pro/pages/notfound.html
index cf49837..f07242b 100644
--- a/themes/trade-pro/pages/notfound.html
+++ b/themes/trade-pro/pages/notfound.html
@@ -1 +1,22 @@
-
+{# trade-pro notfound — 品牌化 404(Task 11)。
+ 设计参照(本轮无 cms 源对应):上游 industrial/automotive 1.3.0/1.4.0
+ 的 404 为「眉题 + 巨号 404 + 一句文案 + 返回首页」的居中薄形态;本模板
+ 保留该信息架构并以 sf-tp 深色带语汇品牌化(10a 应用带的藏青渐变 + 光晕
+ 底、反色文案、白底按钮反色),双动作位:返回首页 + 浏览产品目录。
+ 渲染流:构建器以 mode='notfound' 渲染(noindex meta),pro.html 对
+ notfound 不渲染结尾 CTA 带;h1 唯一(「404」大标题即页题)。图标走
+ Task 9 icon 宏(search:找不到页面的语义),无裸箭头字符。 #}
+
+
+
+
{{ icon('search') }}
+
ERROR / 404
+
404
+
The page you are looking for does not exist or has been moved.
+
+
+
+
diff --git a/themes/trade-pro/pages/search.html b/themes/trade-pro/pages/search.html
index 56a6217..db8f944 100644
--- a/themes/trade-pro/pages/search.html
+++ b/themes/trade-pro/pages/search.html
@@ -1,2 +1,31 @@
-SEARCH / CONTENTSite Search
Search products, brands, news and cases across this site.
-
+{# trade-pro search — 站内搜索页精修(Task 11)。
+ 机制决策:采用与上游四主题完全相同的平台静态检索机制(V8.31 起全主题
+ 共享,非 automotive 专属)——构建器为每个构建打包 search-index.json
+ (全站条目标题/摘要/类型/品牌),site-runtime.js 在客户端完成 ?q= 深链
+ 读取 + 关键词过滤 + 结果渲染,无任何服务端 API。JS 寻址的是 ID 钩子
+ (#sf-search 输入 / #sf-search-results 容器 / #sf-search-count 计数,
+ factory.css 的 .sf-search-page 提供基线观感)——三钩子与 .sf-search-page
+ 类名必须原样保留(平台契约),否则检索退化为一页死输入框。
+ 本模板的精修是观感层:hero 换 sf-tp-page-hero(10c 内页 hero 同款浅
+ 品牌横幅,搜索是工具页无层级——不带面包屑,与上游一致),搜索面板由
+ pro.css 的 Task 11 作用域规则把 factory.css 的 system-ui 基线覆写为
+ cms 令牌观感(含 site-runtime.js 注入的 .sf-search-result 结果卡)。
+ 构建器生成本页时 kind='search'(route 推断先于显式模板),robots 为
+ noindex,follow;pro.html 对 search 页不渲染结尾 CTA 带。页面为英文
+ (构建器的中文页题「站内搜索」仅进 ,不进正文)。 #}
+
+
+
+
+
SEARCH / CONTENT
+
Site Search
+
Search products, brands, news and cases across this site.
+
+
+
+
+
+
+
+
+
diff --git a/themes/trade-pro/pages/service.html b/themes/trade-pro/pages/service.html
index 2f57ad8..e4af976 100644
--- a/themes/trade-pro/pages/service.html
+++ b/themes/trade-pro/pages/service.html
@@ -1,2 +1,47 @@
-OUR SERVICES{{page.title}}
{{page.summary}}
-SERVICE / SUPPORT{{page.title}}
Working process, service scope and support commitments.
{{body_copy(content,page)}}{% if page.cover %}
}})
{% endif %}
+{# trade-pro service detail — 服务详情精修(Task 11)。
+ 设计参照(本轮无 cms 源对应):上游 industrial/automotive 1.3.0/1.4.0 的
+ service 页为通用信息页薄形态(hero + 双栏正文 + 封面图);本模板以
+ sf-tp 设计语言重组为「详情页」口径:sf-tp-page-hero(10c:封面底图 +
+ 面包屑)→ detail 双栏(10g 案例页同构 1.2fr/0.8fr:文案列 = 眉题 + h2 +
+ 正文排版层;侧列 = sticky CTA 卡 + 返回服务列表)。
+ 数据事实(make_context 对 service kind):仅页面条目上下文(title/
+ summary/body/cover),无服务专属集合;正文 = 单一富文本 body,小节结构
+ 由正文自身 h2 承担(10g/10h 同决策),sf-tp-article-body 排版层双挂
+ (10d)。body 为空 → 正文区块整段隐藏,双栏退化为居中单列(CTA 卡
+ 保留——真实动作位,非虚构内容)。
+ 面包屑/返回链接指向 /services/(required_sections 恒保证该路由存在;
+ 当前页恰为 /services/ 时自指链接隐藏,面包屑降级为 Home › 标题)。 #}
+
+ {% if safe_image(page.cover) %}
{% endif %}
+
+
+
+
+
SERVICE / SUPPORT
+
{{ page.title }}
+ {% if page.summary %}
{{ page.summary }}
{% endif %}
+
+
+
+
+
+ {% if content %}
+
+
SERVICE DETAIL
+
{{ page.title }}
+
{{ body_copy(content, page) }}
+
+ {% endif %}
+
+
+
diff --git a/themes/trade-pro/pro.css b/themes/trade-pro/pro.css
index f1b37bf..805f8ea 100644
--- a/themes/trade-pro/pro.css
+++ b/themes/trade-pro/pro.css
@@ -745,3 +745,85 @@ body.sf-theme-trade-pro{overflow-x:hidden;overflow-x:clip}
.sf-theme-trade-pro .pro-footer-top{grid-template-columns:1fr;gap:var(--sf-tp-space-8)}
.sf-theme-trade-pro .pro-footer-bottom{display:block}
}
+
+/* ── Task 11:brand/service/faq/search/notfound 次要页面精修 ──
+ 设计参照:上游四主题 1.3.0/1.4.0 对应页的信息架构(automotive 1.4.0
+ brand 页最完整:横幅 + 面包屑 + 锚点按钮 + 车型网格 + 品牌故事;其余为
+ 通用信息页骨架)+ 已建立的 sf-tp 设计语言。共享组件零重复声明:
+ brand 的 hero/卡片网格/正文分别由 10c page-hero、10a card-grid、
+ 10d article-body 既有规则(含 10a/10c 的 900/767/620 折叠块)覆盖——
+ brand 模板无新增视觉规则;本块只补 service 双栏/CTA 卡、faq 引导卡、
+ search 面板与结果卡、notfound 深色带。级联:全部为 Task 11 新类名的
+ 首次声明,位于 10a-10j 既有块之后,无同特异性竞争;search 段按
+ .sf-theme-trade-pro 作用域(0,2,0+)覆写 factory.css 的 .sf-search-page
+ 基线(0,1,0)与 site-runtime.js 注入的 .sf-search-result,机制钩子
+ (ID 与类名)不在样式层触碰。 */
+
+/* service 双栏(10g 案例页 1.2fr/0.8fr 同构):文案列 + sticky CTA 侧列;
+ 正文为空时 --solo 单列,CTA 卡居中收窄 */
+.sf-theme-trade-pro .sf-tp-service-grid{display:grid;grid-template-columns:1.2fr 0.8fr;gap:calc(var(--sf-tp-space-12) + var(--sf-tp-space-4));align-items:start}
+.sf-theme-trade-pro .sf-tp-service-grid--solo{grid-template-columns:minmax(0,1fr)}
+.sf-theme-trade-pro .sf-tp-service-grid--solo .sf-tp-service-aside{width:100%;max-width:560px;margin-inline:auto}
+.sf-theme-trade-pro .sf-tp-service-copy h2{margin-block:var(--sf-tp-space-2) var(--sf-tp-space-6)}
+.sf-theme-trade-pro .sf-tp-service-aside{position:sticky;top:calc(var(--sf-tp-space-16) + var(--sf-tp-space-4));display:grid;gap:var(--sf-tp-space-4);justify-items:start}
+.sf-theme-trade-pro .sf-tp-service-cta{display:grid;gap:var(--sf-tp-space-3);padding:var(--sf-tp-card-padding-md);background:var(--sf-tp-color-surface-muted);border-radius:var(--sf-tp-card-border-radius)}
+.sf-theme-trade-pro .sf-tp-service-cta h3{margin:0;font-size:var(--sf-tp-font-size-xl)}
+.sf-theme-trade-pro .sf-tp-service-cta p{margin:0;color:var(--sf-tp-color-text-muted);font-size:var(--sf-tp-font-size-sm)}
+.sf-theme-trade-pro .sf-tp-service-cta .sf-tp-btn{justify-self:start}
+.sf-theme-trade-pro .sf-tp-service-back{display:inline-flex;align-items:center;gap:var(--sf-tp-space-2);font-size:var(--sf-tp-font-size-sm);font-weight:var(--sf-tp-font-weight-semibold);color:var(--sf-tp-color-text-link)}
+.sf-theme-trade-pro .sf-tp-service-back:hover{color:var(--sf-tp-color-text-link-hover)}
+
+/* faq 引导联系卡(10d 侧栏 CTA 深底白按钮语汇):正文之后横排收束 */
+.sf-theme-trade-pro .sf-tp-faq-guide{display:flex;align-items:center;justify-content:space-between;gap:var(--sf-tp-space-6);flex-wrap:wrap;margin-block-start:var(--sf-tp-space-10);padding:var(--sf-tp-card-padding-md);background:var(--sf-tp-color-surface-inverse);border-radius:var(--sf-tp-card-border-radius);color:var(--sf-tp-color-text-inverse)}
+.sf-theme-trade-pro .sf-tp-faq-guide .eyebrow{color:var(--sf-tp-color-text-inverse-muted)}
+.sf-theme-trade-pro .sf-tp-faq-guide h3{margin-block-end:var(--sf-tp-space-2);color:var(--sf-tp-color-text-inverse)}
+.sf-theme-trade-pro .sf-tp-faq-guide p{margin:0;color:color-mix(in srgb,var(--sf-tp-color-text-inverse) 82%,transparent);font-size:var(--sf-tp-font-size-sm)}
+.sf-theme-trade-pro .sf-tp-faq-guide .sf-tp-btn{background:var(--sf-tp-color-surface-default);border-color:var(--sf-tp-color-surface-default);color:var(--sf-tp-color-text-brand)}
+.sf-theme-trade-pro .sf-tp-faq-guide .sf-tp-btn:hover{background:var(--sf-tp-color-brand-primary);border-color:var(--sf-tp-color-brand-primary);color:var(--sf-tp-color-text-on-brand)}
+/* 空态卡内的按钮(brand 空品牌/browse 产品):与文案拉开间距 */
+.sf-theme-trade-pro .sf-tp-listing-empty .sf-tp-btn{margin-block-start:var(--sf-tp-space-4)}
+
+/* search 面板:factory.css 的 .sf-search-page system-ui 基线 → cms 令牌
+ 观感(含 site-runtime.js 注入的 .sf-search-result 结果卡样式);
+ #sf-search/#sf-search-results/#sf-search-count 三钩子为平台 JS 契约 */
+.sf-theme-trade-pro .sf-search-page{min-height:auto;width:min(880px,calc(100% - 32px));margin-inline:auto;padding-block:calc(var(--sf-tp-space-10) + var(--sf-tp-space-4)) calc(var(--sf-tp-space-16) + var(--sf-tp-space-8));font-family:var(--sf-tp-font-family-sans);color:var(--sf-tp-color-text-primary)}
+.sf-theme-trade-pro .sf-search-page>label{display:block;margin:0 0 var(--sf-tp-space-3);font-size:var(--sf-tp-font-size-xs);font-weight:var(--sf-tp-font-weight-semibold);letter-spacing:var(--sf-tp-letter-spacing-wide);text-transform:uppercase;color:var(--sf-tp-color-text-muted)}
+.sf-theme-trade-pro .sf-search-page input[type="search"]{display:block;width:100%;padding:var(--sf-tp-space-4) calc(var(--sf-tp-space-4) + var(--sf-tp-space-1));font-size:var(--sf-tp-font-size-lg);font-family:inherit;border:var(--sf-tp-border-width-hairline) solid var(--sf-tp-color-border-default);border-radius:var(--sf-tp-radius-sm);background:var(--sf-tp-color-surface-default);color:var(--sf-tp-color-text-primary)}
+.sf-theme-trade-pro .sf-search-page #sf-search-count{margin:var(--sf-tp-space-5) 0 var(--sf-tp-space-3);color:var(--sf-tp-color-text-muted);font-size:var(--sf-tp-font-size-sm)}
+.sf-theme-trade-pro .sf-search-result{padding:var(--sf-tp-space-5) 0;border-block-end:var(--sf-tp-border-width-hairline) solid var(--sf-tp-color-border-subtle)}
+.sf-theme-trade-pro .sf-search-result a{color:var(--sf-tp-color-text-primary);font-size:var(--sf-tp-font-size-xl);font-weight:var(--sf-tp-font-weight-bold);text-decoration:none}
+.sf-theme-trade-pro .sf-search-result a:hover{color:var(--sf-tp-color-text-brand)}
+.sf-theme-trade-pro .sf-search-result small{display:block;margin-block-start:var(--sf-tp-space-1);color:var(--sf-tp-color-text-brand);font-size:var(--sf-tp-font-size-xs);letter-spacing:var(--sf-tp-letter-spacing-wide);text-transform:uppercase}
+.sf-theme-trade-pro .sf-search-result p{margin-block-start:var(--sf-tp-space-2);color:var(--sf-tp-color-text-muted);font-size:var(--sf-tp-font-size-sm)}
+
+/* notfound 深色带(10a 应用带语汇:藏青渐变 + 光晕 + 反色文案):
+ 居中单列,巨号 404 为唯一 h1;双按钮(实底 + 深底上的白底反色 ghost) */
+.sf-theme-trade-pro .sf-tp-notfound{position:relative;overflow:hidden;padding-block:calc(var(--sf-tp-space-16) + var(--sf-tp-space-8)) calc(var(--sf-tp-space-16) + var(--sf-tp-space-4));color:var(--sf-tp-color-text-inverse);background:linear-gradient(115deg,var(--sf-tp-color-surface-inverse),var(--sf-tp-color-brand-primary-deep) 78%)}
+.sf-theme-trade-pro .sf-tp-notfound::before{content:"";position:absolute;inset:0;background:radial-gradient(circle at 15% 20%,color-mix(in srgb,var(--sf-tp-color-brand-primary) 24%,transparent),transparent 42%);pointer-events:none}
+.sf-theme-trade-pro .sf-tp-notfound .wrap{position:relative;z-index:var(--sf-tp-z-raised)}
+.sf-theme-trade-pro .sf-tp-notfound-inner{display:grid;justify-items:center;max-width:560px;margin-inline:auto;text-align:center}
+.sf-theme-trade-pro .sf-tp-notfound-inner .eyebrow{color:var(--sf-tp-color-text-inverse-muted)}
+.sf-theme-trade-pro .sf-tp-notfound-inner h1{margin-block:var(--sf-tp-space-2) var(--sf-tp-space-3);font-size:clamp(120px,22vw,220px);line-height:.9;letter-spacing:var(--sf-tp-letter-spacing-tight);color:var(--sf-tp-color-text-inverse)}
+.sf-theme-trade-pro .sf-tp-notfound-icon{background:color-mix(in srgb,var(--sf-tp-color-neutral-0) 12%,transparent);color:var(--sf-tp-color-text-inverse)}
+.sf-theme-trade-pro .sf-tp-notfound-lead{color:color-mix(in srgb,var(--sf-tp-color-text-inverse) 88%,transparent);font-size:var(--sf-tp-font-size-lg);margin-block-end:var(--sf-tp-space-8)}
+.sf-theme-trade-pro .sf-tp-notfound-actions{display:flex;gap:var(--sf-tp-space-4);flex-wrap:wrap;justify-content:center}
+.sf-theme-trade-pro .sf-tp-notfound .sf-tp-btn--ghost{background:var(--sf-tp-color-surface-default);border-color:var(--sf-tp-color-surface-default);color:var(--sf-tp-color-text-brand)}
+
+/* ── Task 11 响应式(新类名折叠收本块;hero 竖版/卡片栅格/正文紧凑由
+ 10c/10a/10d 既有媒体块经共用类名覆盖——10c 教训:同特异性按源顺序
+ 取胜,本块只声明 Task 11 新类名)── */
+@media (max-width: 900px){
+ .sf-theme-trade-pro .sf-tp-service-grid{grid-template-columns:1fr;gap:var(--sf-tp-space-8)}
+ .sf-theme-trade-pro .sf-tp-service-aside{position:static}
+}
+@media (max-width: 620px){
+ .sf-theme-trade-pro .sf-tp-service-cta{padding:16px}
+ .sf-theme-trade-pro .sf-tp-faq-guide{display:block}
+ .sf-theme-trade-pro .sf-tp-faq-guide .sf-tp-btn{margin-block-start:12px}
+ .sf-theme-trade-pro .sf-search-page{padding-block:28px 72px}
+ .sf-theme-trade-pro .sf-search-page input[type="search"]{padding:13px 16px;font-size:var(--sf-tp-font-size-md)}
+ .sf-theme-trade-pro .sf-search-result a{font-size:var(--sf-tp-font-size-lg)}
+ .sf-theme-trade-pro .sf-tp-notfound{padding-block:64px 56px}
+ .sf-theme-trade-pro .sf-tp-notfound-inner h1{font-size:clamp(96px,26vw,140px)}
+ .sf-theme-trade-pro .sf-tp-notfound-actions{display:grid;grid-template-columns:1fr;justify-items:stretch}
+}