From 5ea0c8c5e81f618f06c837b05b246ae800a48276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Fri, 23 Oct 2026 10:17:31 +0800 Subject: [PATCH] feat: port cms product detail layout into trade-pro (gallery/specs/inquiry) Rewrite pages/product.html from the 3-row skeleton to the cms [slug].astro design: breadcrumb -> gallery (main + scrolling thumbs, reusing the platform pro.js data-gallery-image hooks, zero new JS) + summary column (eyebrow/h1/lead/brand+model/actions) -> flattened Product details panel -> Specifications table from fields (hidden when empty) -> related products on the home card grid -> inquiry section (left contact info, right external form only when form_endpoint is configured, CTA to /contact/ otherwise). Component CSS lands in pro.css under .sf-theme-trade-pro with 900/620 breakpoints; stale .pro-specs tint rules removed (other themes keep their pro-base skeleton); cross-theme skeleton assertion in test_theme_pro_v3.py now excludes trade-pro; new test_trade_pro_product_layout_structure covers the build output. Co-Authored-By: Claude Code --- tests/test_theme_pro_v3.py | 5 +- tests/test_theme_registry.py | 50 ++++++++++ themes/trade-pro/pages/product.html | 145 +++++++++++++++++++++++++++- themes/trade-pro/pro.css | 77 ++++++++++++++- 4 files changed, 269 insertions(+), 8 deletions(-) diff --git a/tests/test_theme_pro_v3.py b/tests/test_theme_pro_v3.py index 2ea5c9a..23cc836 100644 --- a/tests/test_theme_pro_v3.py +++ b/tests/test_theme_pro_v3.py @@ -19,7 +19,10 @@ def test_complete_theme_families_have_distinct_markup(factory): assert soup.find('footer',class_='pro-footer') assert len(soup.find_all('h1'))==1,(theme,page_type,len(soup.find_all('h1'))) assert 'pro-base.css' in r.text and 'pro.js' in r.text - if page_type=='product':assert soup.select_one('.pro-product-layout .pro-specs') + # trade-pro 的产品详情自 Task 10b 起为 cms 移植布局(sf-tp-product-*), + # 骨架断言只覆盖其余沿用 pro-base 骨架的主题(test_theme_registry.py + # 的 test_trade_pro_product_layout_structure 覆盖 trade-pro 侧)。 + if page_type=='product' and theme!='trade-pro':assert soup.select_one('.pro-product-layout .pro-specs') if page_type=='listing':assert soup.select_one('[data-pro-filter-search]') if page_type=='article':assert soup.select_one('.pro-article-hero') main.append(factory.get(f'/api/factory/themes/{theme}/preview?page_type=home').text) diff --git a/tests/test_theme_registry.py b/tests/test_theme_registry.py index 8a3e801..a211dc5 100644 --- a/tests/test_theme_registry.py +++ b/tests/test_theme_registry.py @@ -178,6 +178,56 @@ def test_trade_pro_home_layout_structure(factory): assert len(soup.find_all('h1')) == 1 +def test_trade_pro_product_layout_structure(factory): + # Task 10b:product.html 移植 cms 产品详情设计([slug].astro)后的结构契约。 + # 构建流(/preview/ HTTP)+ 带 fields/gallery 的产品条目驱动断言: + # 画廊(主图封面 + data-gallery-image 缩略图,复用平台 pro.js 增强钩子)、 + # 标题区、参数表渲染 fields 键值(品牌等管理字段不进表)、询盘 CTA、 + # 相关产品复用首页卡片网格;旧骨架 .pro-product-layout/.pro-specs 无残留。 + sid = site(factory) + assert factory.post(f'/api/factory/sites/{sid}/bootstrap').status_code == 200 + made = factory.post(f'/api/sites/{sid}/entries', json={ + 'type': 'product', 'title': 'Hydraulic Pump HP-200', 'route': '/product/hp-200/', + 'cover': 'https://imgs.example/hp-200.jpg', 'summary': 'High-pressure hydraulic pump for export.', + 'meta': {'fields': {'brand': 'Quanta', 'range': '500 km', 'pressure': '210 bar', + 'gallery': ['https://imgs.example/hp-200.jpg', 'https://imgs.example/hp-200-b.jpg']}}}) + assert made.status_code in (200, 201), made.text + other = factory.post(f'/api/sites/{sid}/entries', json={ + 'type': 'product', 'title': 'Companion Valve', 'route': '/product/valve/', + 'summary': 'Matching control valve.'}) + assert other.status_code in (200, 201), other.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'] + r = factory.get(f'/preview/{sid}/{bid}/product/hp-200/') + assert r.status_code == 200, r.text[:400] + html = r.text + soup = BeautifulSoup(html, 'html.parser') + # 画廊:主图为封面;多图时缩略图带 data-gallery-image(pro.js 切换/灯箱钩子) + media = soup.select_one('.sf-tp-product-grid .sf-tp-product-media img') + assert media is not None and 'hp-200.jpg' in media.get('src', '') + thumbs = soup.select('.sf-tp-product-thumbs [data-gallery-image]') + assert len(thumbs) == 2 + # 标题区(唯一 h1)+ 询盘 CTA 指向联系页(/preview/ 响应会把根相对 + # href 重写为 /preview/{sid}/{bid}/contact/,故用后缀匹配) + assert soup.select_one('.sf-tp-product-summary h1.sf-tp-product-title') + assert soup.select_one('.sf-tp-product-actions a.sf-tp-btn[href$="/contact/"]') + # 参数表:fields 键值渲染(下划线转空格 + 首字母大写),空表整段隐藏 + spec_table = soup.select_one('table.sf-tp-spec-table') + assert spec_table is not None + spec_text = spec_table.get_text() + assert 'Pressure' in spec_text and '210 bar' in spec_text and '500 km' in spec_text + assert 'Quanta' not in spec_text # brand 等管理字段不进参数表 + # 相关产品:复用 sf-tp-card-grid;自身不出现在相关列表 + cards = soup.select('.sf-tp-card-grid .sf-tp-card') + assert cards and any('Companion Valve' in c.get_text() for c in cards) + assert all('Hydraulic Pump' not in c.get_text() for c in cards) + # 询盘板块存在(左联系信息 + 右 CTA/表单位) + assert soup.select_one('.sf-tp-product-quote') is not None + # 旧骨架清理:无 .pro-product-layout/.pro-specs 残留类依赖 + assert 'pro-product-layout' not in html and 'pro-specs' not in html + assert len(soup.find_all('h1')) == 1 + + def test_frontend_entries_include_trade_pro(): from pathlib import Path base = Path(__file__).resolve().parent.parent diff --git a/themes/trade-pro/pages/product.html b/themes/trade-pro/pages/product.html index d490316..ec1abe3 100644 --- a/themes/trade-pro/pages/product.html +++ b/themes/trade-pro/pages/product.html @@ -1,3 +1,142 @@ -
Home/Products/{{page.title}}
-
PRODUCT DETAILS / {{fields.get('brand') or 'CATALOGUE'}}

{{page.title}}

{{page.summary or 'Detailed product information and specifications.'}}

{% if fields.get('brand') %}

Brand · {{fields.get('brand')}}

{% endif %}Inquire about this product {{ icon('arrow-right') }}
-
OVERVIEW

Product overview

{{body_copy(content,page)}}
SPECIFICATIONS

Specifications

{% for row in specs %}
{{row.label}}{{row.value}}
{% else %}

Specifications have not been filled in yet.

{% endfor %}
+{# trade-pro product detail — cms 产品详情设计移植(Task 10b)。 + 区块序列对照 D:/project/cms/runtimes/astro-site-runtime/src/pages/[locale]/products/[slug].astro + (像素基准 dist/hesupipe/en/products/alloy-resin-system-window/): + 面包屑 → 画廊(主图 + 单行横滚缩略图)+ 标题区(眉题/h1/导语/品牌行/ + CTA 对)→ 正文 Product Details → 参数表 Specifications(fields 键值, + 空则整段隐藏)→ 相关产品(卡片网格)→ 询盘板块(左联系信息 + 右 CTA/ + 外部表单)。 + 与 cms 的两处结构决策: + 1. Tab 导航平铺:cms 的 Tab 序列承载每产品自定义区块,平台正文是单一 + 富文本 + 参数表,仅两个面板不值得引入 JS Tab;cms 无 JS 回退形态 + 本就是面板平铺,这里固定为平铺(无 JS 依赖、静态可抓取)。 + 2. 画廊交互复用平台 pro.js 既有钩子(.pro-product-media / + .pro-gallery-thumbs / [data-gallery-image]):缩略图点击换主图 + + 主图灯箱,零新增 JS;无 JS 时全部图片仍平铺可读。无图回退封面, + 再无则占位渐变(空值不破版)。 #} +
+
+ +
+ +
+ PRODUCT DETAILS / {{ fields.get('brand') or 'CATALOGUE' }} +

{{ page.title }}

+

{{ page.summary or 'Detailed product information, specifications and export packaging are published on this page.' }}

+ {% if fields.get('brand') or fields.get('model') %} +

{% if fields.get('brand') %}Brand · {{ fields.get('brand') }}{% endif %}{% if fields.get('model') %}Model · {{ fields.get('model') }}{% endif %}

+ {% endif %} + +
+
+
+
+
+
+ OVERVIEW +

Product details

+
{{ body_copy(content, page) }}
+
+
+{% if specs %} +
+
+ SPECIFICATIONS +

Specifications

+
+ + + {% for row in specs %} + + {% endfor %} + +
{{ row.label }}{{ row.value }}
+
+
+
+{% endif %} +{% set tp_related = (groups['product'] + groups['vehicle']) | rejectattr('route', 'equalto', page.route) | list %} +{% if tp_related %} +
+
+
+
+ RELATED PRODUCTS +

You may also need

+
+ Browse all products {{ icon('arrow-right', cls='sf-tp-icon--sm') }} +
+
+ {% for tp_item in tp_related[:4] %} + + {% endfor %} +
+
+
+{% endif %} +
+
+
+ REQUEST A QUOTE +

Inquire about this product

+

Send the specifications you need for {{ page.title }} and our trade desk replies with pricing, lead time and export packaging within one business day.

+
+ {% if footer_email %} +
+ + +
+ {% endif %} +
+ +
Direct sourcing desk

One contact from inquiry to container loading.

+
+
+
+
+ {% if form_endpoint %} +

Get a quote for {{ page.title }}

+
+ + + + + +

Submissions are handled by the external form service configured by the site administrator.

+
+ {% else %} +

Get a quote for {{ page.title }}

+

Share your specifications and target market through the contact page; our trade desk replies within one business day.

+ Contact us {{ icon('arrow-right') }} + {% endif %} +
+
+
diff --git a/themes/trade-pro/pro.css b/themes/trade-pro/pro.css index fd9cdb1..3866383 100644 --- a/themes/trade-pro/pro.css +++ b/themes/trade-pro/pro.css @@ -1,9 +1,12 @@ /* trade-pro pro.css — component layer. Phase 2 shipped a skeleton tint layer; Phase 3 Task 10a prepends the ported - cms home components. Sources (scoped CSS + dist pixel baseline - D:/project/cms/runtimes/astro-site-runtime/dist/hesupipe/en/index.html): + cms home components; Task 10b adds the product detail components. Sources + (scoped CSS + dist pixel baseline + D:/project/cms/runtimes/astro-site-runtime/dist/hesupipe/en/): - src/pages/[locale]/index.astro (hero / trustbar / two-col about / applications band / section-head / card / feature / cta-band) + - src/pages/[locale]/products/[slug].astro (product hero gallery / + summary / panel titles / spec table / quote grid) - src/components/{PageHero,FeatureGrid,CardGrid,Cta,SectionHead}.astro Layer split with theme.css (= tokens + element baseline + shared utilities): pro.css owns the sf-tp-* component classes; markup composes on the @@ -101,10 +104,64 @@ .sf-theme-trade-pro .sf-tp-cta h2{margin-block-end:var(--sf-tp-space-2);color:var(--sf-tp-color-text-inverse)} .sf-theme-trade-pro .sf-tp-cta p{color:color-mix(in srgb,var(--sf-tp-color-text-inverse) 83%,transparent);margin:0} +/* ── 产品详情(Task 10b,[slug].astro 移植):画廊 + 标题区 + 参数表 + 询盘 ── */ +.sf-theme-trade-pro .sf-tp-product-hero{padding-block:calc(var(--sf-tp-space-8) + var(--sf-tp-space-4)) var(--sf-tp-space-8)} +.sf-theme-trade-pro .sf-tp-breadcrumb{display:flex;flex-wrap:wrap;align-items:center;color:var(--sf-tp-color-text-muted);font-size:var(--sf-tp-font-size-sm);margin-block-end:var(--sf-tp-space-6)} +.sf-theme-trade-pro .sf-tp-breadcrumb>*+*::before{content:"›";margin-inline:var(--sf-tp-space-3) calc(var(--sf-tp-space-3) - var(--sf-tp-space-1));color:var(--sf-tp-color-neutral-400)} +.sf-theme-trade-pro .sf-tp-breadcrumb a:hover{color:var(--sf-tp-color-text-link)} +.sf-theme-trade-pro .sf-tp-breadcrumb-current{color:var(--sf-tp-color-text-secondary);font-weight:var(--sf-tp-font-weight-semibold)} +.sf-theme-trade-pro .sf-tp-product-grid{display:grid;grid-template-columns:1.08fr 0.92fr;gap:calc(var(--sf-tp-space-12) + var(--sf-tp-space-4));align-items:center} +/* grid 列最小宽归零:缩略图横滚依赖列宽被约束(cms 同款注释) */ +.sf-theme-trade-pro .sf-tp-product-gallery,.sf-theme-trade-pro .sf-tp-product-summary{min-width:0} +/* 主图:cms product-main-image(4:3 + 圆角 + 浅底);覆盖 pro-product-media 的骨架固定高。 + .pro-product-media 类仅作 pro.js 画廊钩子(querySelector 定位主图)保留。 */ +.sf-theme-trade-pro .sf-tp-product-media{height:auto;aspect-ratio:var(--sf-tp-ratio-product-main);overflow:hidden;border-radius:var(--sf-tp-radius-sm);background:var(--sf-tp-color-surface-muted)} +.sf-theme-trade-pro .sf-tp-product-media img{width:100%;height:100%;object-fit:cover;display:block} +/* 缩略图:单行横滚 + scroll-snap(cms product-thumbs);激活态沿用 pro.js + 维护的 aria-pressed,品牌描边 + 焦点环 */ +.sf-theme-trade-pro .sf-tp-product-thumbs{display:flex;gap:var(--sf-tp-space-3);margin-block-start:var(--sf-tp-space-3);overflow-x:auto;scroll-behavior:smooth;scrollbar-width:thin;scroll-snap-type:x proximity;padding-block-end:var(--sf-tp-space-1)} +.sf-theme-trade-pro .sf-tp-product-thumb{flex:0 0 120px;aspect-ratio:var(--sf-tp-ratio-landscape);padding:0;overflow:hidden;border:var(--sf-tp-border-width-medium) solid transparent;border-radius:var(--sf-tp-radius-xs);background:var(--sf-tp-color-surface-muted);cursor:pointer;scroll-snap-align:center} +.sf-theme-trade-pro .sf-tp-product-thumb[aria-pressed="true"],.sf-theme-trade-pro .sf-tp-product-thumb:focus-visible{border-color:var(--sf-tp-color-border-brand);box-shadow:var(--sf-tp-shadow-focus-ring)} +.sf-theme-trade-pro .sf-tp-product-thumb img{width:100%;height:100%;object-fit:cover;display:block} +/* 标题区:产品名 h1 用 cms 量级(2xl,非巨型 display),导语 + 管理字段行 + CTA 对 */ +.sf-theme-trade-pro .sf-tp-product-title{font-size:var(--sf-tp-font-size-2xl);line-height:var(--sf-tp-line-height-snug);letter-spacing:var(--sf-tp-letter-spacing-normal);margin-block-end:var(--sf-tp-space-3)} +.sf-theme-trade-pro .sf-tp-product-lead{color:var(--sf-tp-color-text-muted);line-height:var(--sf-tp-line-height-relaxed);margin-block-end:var(--sf-tp-space-4)} +.sf-theme-trade-pro .sf-tp-product-meta{display:flex;flex-wrap:wrap;gap:var(--sf-tp-space-2) var(--sf-tp-space-5);color:var(--sf-tp-color-text-secondary);font-size:var(--sf-tp-font-size-sm);margin-block-end:var(--sf-tp-space-6)} +.sf-theme-trade-pro .sf-tp-product-actions{display:flex;gap:var(--sf-tp-space-4);flex-wrap:wrap} +.sf-theme-trade-pro .sf-tp-product-actions .sf-tp-btn{border-radius:var(--sf-tp-radius-full)} +/* 详情面板标题:品牌色下划短线(cms .detail-section h2 层次) */ +.sf-theme-trade-pro .sf-tp-panel-title{display:inline-block;margin-block-end:var(--sf-tp-space-6);padding-block-end:var(--sf-tp-space-3);border-block-end:var(--sf-tp-border-width-strong) solid var(--sf-tp-color-border-brand)} +/* 正文:迁移富文本(.pro-rich 基线之上补表格形态——WP 迁移正文常带规格表) */ +.sf-theme-trade-pro .sf-tp-product-body table{width:100%;border-collapse:collapse;table-layout:auto;font-size:var(--sf-tp-font-size-sm);margin-block:var(--sf-tp-space-6)} +.sf-theme-trade-pro .sf-tp-product-body th,.sf-theme-trade-pro .sf-tp-product-body td{border:var(--sf-tp-border-width-hairline) solid var(--sf-tp-color-border-default);padding:var(--sf-tp-space-3) var(--sf-tp-space-4);text-align:start;vertical-align:middle;word-break:break-word} +.sf-theme-trade-pro .sf-tp-product-body tbody tr:nth-child(even) td{background:var(--sf-tp-color-neutral-50)} +/* 参数表(cms spec-table):键列灰底,横向可滚(宽表不溢出容器) */ +.sf-theme-trade-pro .sf-tp-table-scroll{overflow-x:auto} +.sf-theme-trade-pro .sf-tp-spec-table{width:100%;border-collapse:collapse;font-size:var(--sf-tp-font-size-sm)} +.sf-theme-trade-pro .sf-tp-spec-table th,.sf-theme-trade-pro .sf-tp-spec-table td{border:var(--sf-tp-border-width-hairline) solid var(--sf-tp-color-border-default);padding:var(--sf-tp-space-3) var(--sf-tp-space-4);text-align:start} +.sf-theme-trade-pro .sf-tp-spec-table th{background:var(--sf-tp-color-surface-muted);font-weight:var(--sf-tp-font-weight-semibold);white-space:nowrap} +/* 询盘板块(cms quote-grid 同构):左联系信息 + 右表单卡 */ +.sf-theme-trade-pro .sf-tp-quote-grid{display:grid;grid-template-columns:0.85fr 1.15fr;gap:calc(var(--sf-tp-space-12) + var(--sf-tp-space-4));align-items:start} +.sf-theme-trade-pro .sf-tp-quote-info>p{color:var(--sf-tp-color-text-muted)} +.sf-theme-trade-pro .sf-tp-quote-list{display:grid;gap:var(--sf-tp-space-5);margin-block-start:var(--sf-tp-space-6)} +.sf-theme-trade-pro .sf-tp-quote-item{display:flex;align-items:center;gap:var(--sf-tp-space-4)} +.sf-theme-trade-pro .sf-tp-quote-item .icon-circle{margin:0;flex-shrink:0} +.sf-theme-trade-pro .sf-tp-quote-item strong{display:block;margin-block-end:var(--sf-tp-space-1)} +.sf-theme-trade-pro .sf-tp-quote-item p{margin:0;color:var(--sf-tp-color-text-muted);font-size:var(--sf-tp-font-size-sm)} +.sf-theme-trade-pro .sf-tp-quote-item a:hover{color:var(--sf-tp-color-text-link)} +.sf-theme-trade-pro .sf-tp-quote-form{background:var(--sf-tp-color-surface-muted);padding:calc(var(--sf-tp-space-8) + var(--sf-tp-space-1));border-radius:var(--sf-tp-radius-sm)} +.sf-theme-trade-pro .sf-tp-quote-form form{display:grid;gap:var(--sf-tp-space-4)} +.sf-theme-trade-pro .sf-tp-quote-form .sf-tp-btn{justify-self:start} +.sf-theme-trade-pro .sf-tp-quote-form textarea{min-height:110px} +.sf-theme-trade-pro .sf-tp-quote-note{font-size:var(--sf-tp-font-size-xs);color:var(--sf-tp-color-text-muted);margin:0} + /* ── 响应式(断点随 cms 设计稿:900 栅格堆叠 / 767 hero 竖版 / 620 紧凑)── */ @media (max-width: 900px){ .sf-theme-trade-pro .sf-tp-applications-grid{grid-template-columns:1fr;gap:calc(var(--sf-tp-space-8) + var(--sf-tp-space-1))} .sf-theme-trade-pro .sf-tp-two-col{grid-template-columns:1fr} + /* 产品详情:画廊/标题区上下堆叠;询盘左右并排收窄间距(cms 900 同款) */ + .sf-theme-trade-pro .sf-tp-product-grid{grid-template-columns:1fr;gap:var(--sf-tp-space-8)} + .sf-theme-trade-pro .sf-tp-quote-grid{grid-template-columns:1fr;gap:var(--sf-tp-space-8)} .sf-theme-trade-pro .sf-tp-card-grid,.sf-theme-trade-pro .sf-tp-card-grid--news{grid-template-columns:repeat(2,minmax(0,1fr))} .sf-theme-trade-pro .sf-tp-feature-grid,.sf-theme-trade-pro .sf-tp-trust-grid{grid-template-columns:1fr 1fr} .sf-theme-trade-pro .sf-tp-trust-item{border-inline-end:0;border-block-end:var(--sf-tp-border-width-hairline) solid var(--sf-tp-color-border-subtle)} @@ -166,6 +223,20 @@ .sf-theme-trade-pro .sf-tp-cta h2{font-size:22px} .sf-theme-trade-pro .sf-tp-cta p{font-size:11px} .sf-theme-trade-pro .sf-tp-cta .sf-tp-btn{margin-block-start:12px} + /* 产品详情 620 紧凑(cms 移动端设计稿):面包屑收紧、缩略图缩格、 + CTA 双列铺满、表单卡与参数表留白降档 */ + .sf-theme-trade-pro .sf-tp-product-hero{padding-block:14px 21px} + .sf-theme-trade-pro .sf-tp-breadcrumb{margin-block-end:8px;font-size:10px} + .sf-theme-trade-pro .sf-tp-product-grid{gap:14px} + .sf-theme-trade-pro .sf-tp-product-media{aspect-ratio:16/9} + .sf-theme-trade-pro .sf-tp-product-thumbs{gap:8px;margin-block-start:7px} + .sf-theme-trade-pro .sf-tp-product-thumb{flex-basis:86px} + .sf-theme-trade-pro .sf-tp-product-lead{font-size:11px;line-height:1.35} + .sf-theme-trade-pro .sf-tp-product-actions{display:grid;grid-template-columns:1fr 1fr;gap:8px} + .sf-theme-trade-pro .sf-tp-product-actions .sf-tp-btn{min-height:37px;font-size:11px} + .sf-theme-trade-pro .sf-tp-quote-list{gap:12px;margin-block-start:16px} + .sf-theme-trade-pro .sf-tp-quote-form{padding:16px} + .sf-theme-trade-pro .sf-tp-spec-table th,.sf-theme-trade-pro .sf-tp-spec-table td{padding:9px 12px} } /* ── Phase 2 skeleton tint layer(chrome 着色,供其余页面与 pro-base 骨架)── */ @@ -183,8 +254,6 @@ .sf-theme-trade-pro .pro-card h3{color:var(--sf-tp-text,#1a2332)} .sf-theme-trade-pro .pro-card:hover{border-color:var(--sf-tp-primary,#0b3d91)} .sf-theme-trade-pro .pro-card-link{color:var(--sf-tp-primary,#0b3d91)} -.sf-theme-trade-pro .pro-specs div{border-bottom:1px solid #e3e9f2} -.sf-theme-trade-pro .pro-specs span{color:var(--sf-tp-muted,#5a6a7e)} .sf-theme-trade-pro .pro-end-cta{background:var(--sf-tp-primary,#0b3d91);color:#fff} .sf-theme-trade-pro .pro-end-cta .pro-eyebrow{color:var(--sf-tp-accent,#f5a623)} .sf-theme-trade-pro .pro-end-cta .sf-tp-btn{background:#fff;color:var(--sf-tp-primary,#0b3d91);border-color:#fff}