feat: port cms about layout into trade-pro

Task 10e: rewrite pages/about.html from the 2-row thin variant to the
full cms about page design (about.astro, pixel baseline
dist/hesupipe/en/about/): page hero with breadcrumb + cover backdrop +
in-page anchor button, company intro two-col with derived stats bar,
rich body (gated on body), advantages grid, dark mission band with
gallery backdrop and glass feature cards, gallery-driven facility card
grid (hidden when empty), certifications grid.

Data mapping: about page = ordinary page entry; cms dict-only stats and
factory copy have no platform fields, so stats reuse the 10a home
derivation (products/categories/brands/cases counts, hidden when all
empty) and facility cards are driven by page.cover + fields.gallery
(make_context gallery, deduped, cover first); markFloatImages is not
ported (sanitize strips class attributes, same conclusion as 10d) and
the body renders through body_copy + the 10d sf-tp-article-body
typography layer via dual classing.

CSS lands in pro.css under sf-tp-about-* reusing the 10a/10b/10c
components (two-col, stats, feature/card grids, section head, page
hero, breadcrumb); responsive collapse comes from the existing 10a/10c
media blocks, with about-specific 900/620 rules in a dedicated block
(767 intentionally empty, covered by 10c page-hero).

Tests: test_trade_pro_about_layout_structure drives a data-rich /about/
(PATCHed bootstrap entry with cover/summary/rich body/gallery + product
and post entries) and an empty custom-route about page
(meta.page_template), asserting structure, data mapping, and empty-data
section hiding.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-10-23 15:58:30 +08:00
parent f15ea85db4
commit 7d7e98adfa
3 changed files with 332 additions and 2 deletions
+111
View File
@@ -401,6 +401,117 @@ def test_trade_pro_article_layout_structure(factory):
assert not re.search(r'[←→↗↘⌕▾]', ''.join(a.get_text() for a in soup.find_all('a')))
def test_trade_pro_about_layout_structure(factory):
# Task 10e:about.html 移植 cms 关于页设计(about.astro,像素基准
# dist/hesupipe/en/about/)后的结构契约。
# 区块序列:PageHero(面包屑 + 封面底图 + 页内锚点按钮)→ 公司介绍两栏
# (文案 + 实景图 + 悬浮数据条)→ 富文本正文(仅当 body 存在)→
# 优势特性网格 → 深色使命带(实景底图 + 玻璃卡)→ 厂区图集卡(仅当
# gallery 存在)→ 资质特性网格。平台事实:about 数据 = 普通页面条目
# (title/summary/body/cover + fields.gallery),cms 词典中的 stats/
# 厂区文案无对应字段——stats 复用 10a 首页的派生计数(产品/分类/品牌/
# 案例),厂区卡片由 page.cover+fields.gallery 驱动,均空则整段隐藏。
# 双构建断言:数据齐备的 /about/(bootstrap 必备栏目路由)+ 空数据的
# 自定义路由 about 页(meta.page_template 显式指定,不绑定特定路由)。
import re
sid = site(factory)
assert factory.post(f'/api/factory/sites/{sid}/bootstrap').status_code == 200
# 数据齐备的 about 条目:PATCH bootstrap 建立的 /about/(保留原路由)
entries = factory.get(f'/api/sites/{sid}/entries').json()
about_id = next(e['id'] for e in entries if e['route'] == '/about/')
cover = 'https://imgs.example/factory-floor.jpg'
shot1 = 'https://imgs.example/workshop-line.jpg'
shot2 = 'https://imgs.example/finished-goods.jpg'
patched = factory.patch(f'/api/sites/{sid}/entries/{about_id}', json={
'title': 'About Us', 'summary': 'Manufacturer and export partner since day one.',
'body': '<p>Quality control runs from raw material to loaded container.</p><h2>Our standards</h2><p>Every batch is inspected before dispatch.</p>',
'cover': cover,
'meta': {'fields': {'gallery': f'{shot1}; {shot2}'}}})
assert patched.status_code == 200, patched.text
# 3 个产品(1 品牌 1 分类)+ 1 篇文章:驱动派生 stats 与 /news/ 链接
batch = [{'type': 'product', 'title': f'Valve Series {i}', 'summary': f'Control valve {i}.',
'meta': {'fields': {'brand': 'Quanta', 'category': 'Valves'}}} for i in range(3)]
batch.append({'type': 'post', 'title': 'Plant Expansion Update', 'summary': 'New extrusion lines.'})
import io
payload = json.dumps(batch).encode('utf-8')
imported = factory.post(f'/api/sites/{sid}/import',
files={'file': ('about-batch.json', io.BytesIO(payload), 'application/json')})
assert imported.status_code == 200, imported.text[:300]
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']
# ── 数据齐备 /about/:hero + 介绍两栏 + 正文 + 四个设计区块 ──
html = factory.get(f'/preview/{sid}/{bid}/about/').text
soup = BeautifulSoup(html, 'html.parser')
assert len(soup.find_all('h1')) == 1
hero = soup.select_one('section.sf-tp-page-hero.sf-tp-about-hero')
assert hero is not None
bg = hero.select_one('.sf-tp-page-hero-bg')
assert bg is not None and 'factory-floor.jpg' in bg.get('src', '')
# 面包屑:Home + 当前页标题(非链接)
assert hero.select_one('.sf-tp-breadcrumb a')
current = hero.select_one('.sf-tp-breadcrumb-current')
assert current is not None and current.get_text(strip=True) == 'About Us'
# hero 锚点按钮(cms PageHero button → #main 的页内对应物)
assert hero.select_one('.sf-tp-page-hero-copy a.sf-tp-btn[href="#tp-about-intro"]')
assert 'Manufacturer and export partner' in hero.select_one('.sf-tp-page-hero-lead').get_text()
# 介绍两栏:文案列(摘要 + 有文章时的 /news/ 链接)+ 实景图 + 派生数据条
intro = soup.select_one('section.sf-tp-about-intro .sf-tp-two-col')
assert intro is not None
assert intro.select_one('.sf-tp-copy h2')
assert 'Manufacturer and export partner' in intro.select_one('.sf-tp-copy p').get_text()
assert intro.select_one('.sf-tp-copy a.sf-tp-btn[href$="/news/"]')
photo = intro.select_one('.sf-tp-photo img, .sf-tp-photo .sf-tp-photo-plain')
assert photo is not None
stats = intro.select('.sf-tp-stats .sf-tp-stat')
assert len(stats) >= 2 and 'Products' in intro.select_one('.sf-tp-stats').get_text()
# 富文本正文:body 存在才渲染(cms isRichAbout 分支的平台化)
body = soup.select_one('.sf-tp-about-body .pro-rich')
assert body is not None and 'Quality control' in body.get_text() and 'Our standards' in body.get_text()
# 优势 / 使命 / 资质:静态设计内容(cms 词典区块),特性卡带 SVG 图标
assert len(soup.select('.sf-tp-about-advantages .sf-tp-feature')) == 4
assert all(f.select_one('.icon-circle svg') for f in soup.select('.sf-tp-about-advantages .sf-tp-feature'))
mission = soup.select_one('section.section--dark.sf-tp-about-mission')
assert mission is not None
assert len(mission.select('.sf-tp-feature')) == 4
assert mission.select_one('.sf-tp-intro')
assert len(soup.select('.sf-tp-about-certs .sf-tp-feature')) == 4
# 厂区图集卡:cover + fields.gallery 去重共 3 图
facilities = soup.select_one('.sf-tp-about-facilities')
assert facilities is not None
cards = facilities.select('.sf-tp-about-facility')
assert len(cards) == 3
srcs = ' '.join(i.get('src', '') for i in facilities.select('img'))
assert 'workshop-line.jpg' in srcs and 'finished-goods.jpg' in srcs
# 交互箭头一律 SVG(Task 9 契约)
assert not re.search(r'[←→↗↘⌕▾]', ''.join(a.get_text() for a in soup.find_all('a')))
# ── 空数据 about(自定义路由 + meta.page_template 显式指定)──
# 无 cover/body/gallery/产品:hero 无底图、正文与图集整段隐藏、stats
# 整段隐藏、/news/ 链接不渲染;静态设计区块保留(完整页面而非两栏摘要)。
sid2 = site(factory)
made = factory.post(f'/api/sites/{sid2}/entries', json={
'type': 'page', 'title': 'Our Story', 'route': '/our-story/',
'meta': {'page_template': 'about'}})
assert made.status_code in (200, 201), made.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']
bare = factory.get(f'/preview/{sid2}/{bid2}/our-story/')
assert bare.status_code == 200, bare.text[:300]
bsoup = BeautifulSoup(bare.text, 'html.parser')
assert len(bsoup.find_all('h1')) == 1
assert bsoup.select_one('section.sf-tp-about-hero') is not None
assert bsoup.select_one('.sf-tp-page-hero-bg') is None
assert bsoup.select_one('.sf-tp-about-body') is None
assert bsoup.select_one('.sf-tp-about-facilities') is None
assert bsoup.select_one('.sf-tp-stats') is None
assert bsoup.select_one('.sf-tp-about-intro .sf-tp-copy a.sf-tp-btn[href$="/news/"]') is None
assert bsoup.select_one('.sf-tp-copy p').get_text(strip=True) # 英文兜底文案
assert len(bsoup.select('.sf-tp-about-advantages .sf-tp-feature')) == 4
assert bsoup.select_one('section.section--dark.sf-tp-about-mission') is not None
assert len(bsoup.select('.sf-tp-about-certs .sf-tp-feature')) == 4
def test_frontend_entries_include_trade_pro():
from pathlib import Path
base = Path(__file__).resolve().parent.parent
+175 -2
View File
@@ -1,2 +1,175 @@
<section class="pro-inner-hero pro-info-hero"><div class="pro-wrap"><span class="pro-eyebrow">OUR STORY</span><h1>{{page.title}}</h1><p>{{page.summary}}</p></div></section>
<section class="pro-section pro-info-section"><div class="pro-wrap pro-info-grid"><div><span class="pro-eyebrow">ABOUT / DISCOVER</span><h2>Who we are.</h2><p class="pro-muted">Company profile, capabilities and export experience.</p></div><div class="pro-info-copy">{{body_copy(content,page)}}{% if page.cover %}<img class="pro-info-photo" src="{{safe_image(page.cover)}}" alt="{{page.title}}">{% endif %}</div></div></section>
{# trade-pro about — cms 关于页设计移植(Task 10e)。
区块序列对照 D:/project/cms/runtimes/astro-site-runtime/src/pages/[locale]/about.astro
(像素基准 dist/hesupipe/en/about/):
PageHero(面包屑 + 封面底图 + 页内锚点按钮)→ 公司介绍两栏(文案 +
实景图 + 悬浮数据条)→ 富文本正文(cms 仅富文本渲染,平台 body 存在
即渲染)→ 优势特性网格(浅底)→ 使命深色带(实景底图 + 玻璃卡)→
厂区图集卡(图集驱动)→ 资质特性网格(浅底)。
与 cms 的结构决策:
1. about 数据 = 一个普通页面条目(title/summary/body/cover + fields)。
cms 词典中的 stats(26+/19+/47/10)与厂区卡文案平台无对应字段:
stats 复用 10a 首页关于两栏的派生计数(产品/分类/品牌/案例,全空
整段隐藏);厂区卡由 page.cover + fields.gallery(make_context 的
gallery 变量,去重含封面)驱动,无图整段隐藏——与首页 about 两栏
不同,这是完整页面,静态设计区块(优势/使命/资质)保留 cms 形态。
2. cms markFloatImages 构建期给正文图片打浮动 class:平台 sanitize 剥
离 class 属性(10d 同结论),不移植;正文统一 body_copy(.pro-rich
基线)+ 双挂 sf-tp-article-body 复用 10d 富文本排版层(about.astro
的 about-body 与全站 rich-body 同构)。
3. hero 的「Our History」按钮 cms 锚到 #main(hero 正下方的内容区),
平台模板不在 main 内,锚到介绍两栏的 #tp-about-intro(构建器豁免
# 锚点链接);文案列的 history 链接指向 /news/(cms 同款),无文章
时隐藏以免空栏目断链。
4. cms 使命深色带底图固定 factory.webp:平台用 gallery[0](即封面优先)
作实景底图,无图回退 theme.css .section--dark 纯渐变(10a CTA 同策)。
5. cms 的 certKicker 等词典文案是设计内容(同首页 trustbar/features
处理):移植为英文静态文案,去除 HESU 专属表述(厂名/年份)。 #}
<section class="sf-tp-page-hero sf-tp-about-hero">
{% if safe_image(page.cover) %}<img class="sf-tp-page-hero-bg" src="{{ safe_image(page.cover) }}" alt="" width="1600" height="900" fetchpriority="high" decoding="async">{% endif %}
<div class="sf-tp-page-hero-overlay" aria-hidden="true"></div>
<div class="wrap">
<nav class="sf-tp-breadcrumb" aria-label="Breadcrumb" data-reveal>
<a href="/">Home</a><span class="sf-tp-breadcrumb-current">{{ page.title }}</span>
</nav>
<div class="sf-tp-page-hero-copy" data-reveal style="--reveal-i: 1">
<span class="eyebrow">ABOUT US</span>
<h1>{{ page.title }}</h1>
{% if page.summary %}<p class="sf-tp-page-hero-lead">{{ page.summary }}</p>{% endif %}
<a class="sf-tp-btn" href="#tp-about-intro">Our history {{ icon('arrow-right') }}</a>
</div>
</div>
</section>
<section class="section sf-tp-about-intro" id="tp-about-intro">
<div class="wrap sf-tp-two-col">
<div class="sf-tp-copy" data-reveal>
<span class="eyebrow">COMPANY INTRODUCTION</span>
<h2>Who we are</h2>
<p>{{ page.summary or site.tagline or 'Company profile, capabilities and export experience.' }}</p>
{% if stories %}<a class="sf-tp-btn" href="/news/">Company history {{ icon('arrow-right') }}</a>{% endif %}
</div>
<div data-reveal style="--reveal-i: 1">
<div class="sf-tp-photo">
{% if gallery %}<img src="{{ gallery[0] }}" alt="{{ site.name }} facility" width="800" height="600" loading="lazy" decoding="async">
{% else %}<div class="sf-tp-photo-plain" aria-hidden="true"><span>EXPORT · B2B</span></div>{% endif %}
</div>
{% if groups['product'] or groups['vehicle'] or categories or brands or cases %}
<div class="sf-tp-stats">
{% if groups['product'] or groups['vehicle'] %}<div class="sf-tp-stat"><strong class="mono">{{ groups['product']|length + groups['vehicle']|length }}</strong><span>Products</span></div>{% endif %}
{% if categories %}<div class="sf-tp-stat"><strong class="mono">{{ categories|length }}</strong><span>Categories</span></div>{% endif %}
{% if brands %}<div class="sf-tp-stat"><strong class="mono">{{ brands|length }}</strong><span>Brands</span></div>{% endif %}
{% if cases %}<div class="sf-tp-stat"><strong class="mono">{{ cases|length }}</strong><span>Case studies</span></div>{% endif %}
</div>
{% endif %}
</div>
</div>
</section>
{% if content %}
<section class="section sf-tp-about-body-section">
<div class="wrap">
<div class="sf-tp-section-head" data-reveal>
<div>
<span class="eyebrow">COMPANY INTRODUCTION</span>
<h2>{{ page.title }}</h2>
</div>
</div>
<div class="sf-tp-about-body sf-tp-article-body" data-reveal>{{ body_copy(content, page) }}</div>
</div>
</section>
{% endif %}
<section class="section section--soft sf-tp-about-advantages">
<div class="wrap">
<div class="sf-tp-section-head" data-reveal>
<div>
<span class="eyebrow">OUR ADVANTAGES</span>
<h2>Why buyers choose us</h2>
</div>
</div>
<div class="sf-tp-feature-grid">
{% set tp_advantages = [
('check', 'Reliable quality', 'Strict quality control from raw material to loaded container.'),
('search', 'Advanced equipment', 'Modern production and testing facilities.'),
('phone', 'Professional team', 'Experienced technical and export service teams.'),
('location', 'Global service', 'Products delivered to worldwide markets.'),
] %}
{% for tp_icon, tp_title, tp_desc in tp_advantages %}
<div class="sf-tp-feature" data-reveal style="--reveal-i: {{ loop.index0 }}">
<div class="icon-circle" aria-hidden="true">{{ icon(tp_icon) }}</div>
<h3>{{ tp_title }}</h3>
<p>{{ tp_desc }}</p>
</div>
{% endfor %}
</div>
</div>
</section>
<section class="section section--dark sf-tp-about-mission">
{% if gallery %}<img class="sf-tp-about-mission-bg" src="{{ gallery[0] }}" alt="" loading="lazy" decoding="async">{% endif %}
<div class="wrap">
<div class="sf-tp-section-head" data-reveal>
<div>
<span class="eyebrow">OUR MISSION</span>
<h2>Reliable solutions for a better tomorrow</h2>
</div>
<p class="sf-tp-intro">Our mission is to deliver reliable products and dependable service for global development.</p>
</div>
<div class="sf-tp-feature-grid">
{% set tp_mission = [
('quote', 'Our mission', 'Reliable solutions for global development.'),
('location', 'Our vision', 'A trusted global partner in our field.'),
('check', 'Our values', 'Quality, innovation and sustainability.'),
('phone', 'Our promise', 'Long-term value for customers.'),
] %}
{% for tp_icon, tp_title, tp_desc in tp_mission %}
<div class="sf-tp-feature" data-reveal style="--reveal-i: {{ loop.index0 }}">
<div class="icon-circle" aria-hidden="true">{{ icon(tp_icon) }}</div>
<h3>{{ tp_title }}</h3>
<p>{{ tp_desc }}</p>
</div>
{% endfor %}
</div>
</div>
</section>
{% if gallery %}
<section class="section sf-tp-about-facilities">
<div class="wrap">
<div class="sf-tp-section-head" data-reveal>
<div>
<span class="eyebrow">FACTORY DISPLAY</span>
<h2>Our manufacturing facilities</h2>
</div>
</div>
<div class="sf-tp-card-grid">
{% for tp_shot in gallery[:4] %}
<figure class="sf-tp-about-facility" data-reveal style="--reveal-i: {{ loop.index0 % 4 }}">
<div class="sf-tp-card-media"><img src="{{ tp_shot }}" alt="{{ site.name }} facility {{ loop.index }}" loading="lazy" decoding="async"></div>
<figcaption><span class="sf-tp-tag">Facility {{ '%02d'|format(loop.index) }}</span></figcaption>
</figure>
{% endfor %}
</div>
</div>
</section>
{% endif %}
<section class="section section--soft sf-tp-about-certs">
<div class="wrap">
<div class="sf-tp-section-head" data-reveal>
<div>
<span class="eyebrow">CERTIFICATES</span>
<h2>International certifications</h2>
</div>
</div>
<div class="sf-tp-feature-grid">
{% set tp_certs = [
('check', 'ISO 9001', 'Quality management system.'),
('location', 'ISO 14001', 'Environmental management system.'),
('search', 'ISO 45001', 'Occupational health and safety.'),
('download', 'CE', 'European conformity marking.'),
] %}
{% for tp_icon, tp_title, tp_desc in tp_certs %}
<div class="sf-tp-feature" data-reveal style="--reveal-i: {{ loop.index0 }}">
<div class="icon-circle" aria-hidden="true">{{ icon(tp_icon) }}</div>
<h3>{{ tp_title }}</h3>
<p>{{ tp_desc }}</p>
</div>
{% endfor %}
</div>
</div>
</section>
+46
View File
@@ -445,3 +445,49 @@
.sf-theme-trade-pro .sf-tp-article-side-item{grid-template-columns:72px 1fr}
.sf-theme-trade-pro .sf-tp-article-side-cta{padding:16px}
}
/* ── Task 10e:about 关于页(about.astro 移植)──
源 src/pages/[locale]/about.astro:PageHero → 公司介绍两栏(实景图 +
悬浮数据条)→ 富文本正文 → 优势网格 → 使命深色带(实景底图 + 玻璃
特性卡,cms dark-photo/.dark .feature)→ 厂区图集卡(CardGrid cols-4,
平台 gallery 驱动)→ 资质网格。共享组件复用 10a/10b/10c 移植成果:
sf-tp-two-col/copy/photo/stats(介绍两栏 = 首页关于两栏同构,cms 源码
本就同款)、sf-tp-feature-grid/card-grid/section-head(cms 同组件)、
sf-tp-page-hero/breadcrumb(10c 内页 hero)、sf-tp-article-body(10d
富文本排版层,about-body 与全站 rich-body 同构,markup 双挂类名)。
本块只补 about 专属形态:使命带底图叠层与玻璃卡、厂区图集卡。 */
/* 使命深色带:cms dark-photo = section--dark 渐变 + 实景图(object-position
center 55%)。叠层级序(同 page-hero):图(z-1)→ ::before 渐变罩
(z-base,复刻 section--dark 渐变盖住图保证文字对比)→ .wrap(z-raised)。
无图时罩层叠在原渐变上,视觉与 .section--dark 纯渐变一致。 */
.sf-theme-trade-pro .sf-tp-about-mission{position:relative;overflow:hidden}
.sf-theme-trade-pro .sf-tp-about-mission-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 55%;z-index:calc(var(--sf-tp-z-base) - 1)}
.sf-theme-trade-pro .sf-tp-about-mission::before{content:"";position:absolute;inset:0;z-index:var(--sf-tp-z-base);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))}
.sf-theme-trade-pro .sf-tp-about-mission .wrap{position:relative;z-index:var(--sf-tp-z-raised)}
/* 玻璃特性卡(cms .dark .feature):半透明白 + 反色字。0,3,0 无条件压过
10a 的 .sf-tp-feature 底色(0,2,0),620 横排布局仍由 10a 折叠规则提供 */
.sf-theme-trade-pro .sf-tp-about-mission .sf-tp-feature{background:color-mix(in srgb,var(--sf-tp-color-neutral-0) 10%,transparent);border-color:var(--sf-tp-color-border-inverse)}
.sf-theme-trade-pro .sf-tp-about-mission .sf-tp-feature h3{color:var(--sf-tp-color-text-inverse)}
.sf-theme-trade-pro .sf-tp-about-mission .sf-tp-feature p{color:color-mix(in srgb,var(--sf-tp-color-text-inverse) 82%,transparent)}
.sf-theme-trade-pro .sf-tp-about-mission .sf-tp-intro{color:color-mix(in srgb,var(--sf-tp-color-text-inverse) 82%,transparent)}
/* 厂区图集卡(cms CardGrid 卡片形态,数据驱动无悬停语义故不复用 .sf-tp-card
的链接上抬):媒体复用 sf-tp-card-media(4:3 + 裁剪),编号 tag 补位
cms 卡片标题行 */
.sf-theme-trade-pro .sf-tp-about-facility{margin:0;background:var(--sf-tp-color-surface-default);border:var(--sf-tp-border-width-hairline) solid var(--sf-tp-color-border-subtle);border-radius:var(--sf-tp-card-border-radius);overflow:hidden;box-shadow:var(--sf-tp-shadow-xs)}
.sf-theme-trade-pro .sf-tp-about-facility figcaption{padding:var(--sf-tp-space-3) var(--sf-tp-space-4)}
/* ── about 响应式(cms 断点 900/620;767 无 about 专属规则——内页 hero
的 767 竖版由 10c 既有块覆盖。介绍两栏/数据条/特性网格/图集栅格的折叠
全部由 10a 既有块提供(复用同一批类名);10d 的 620 富文本字号经
sf-tp-article-body 双挂类名作用于本页正文。折叠规则收在本任务媒体块
内的原则只针对本任务新类名(10c 教训:同特异性按源顺序取胜)── */
@media (max-width: 900px){
.sf-theme-trade-pro .sf-tp-about-mission .sf-tp-intro{max-width:100%}
}
@media (max-width: 620px){
.sf-theme-trade-pro .sf-tp-about-mission h2{font-size:22px}
.sf-theme-trade-pro .sf-tp-about-mission .sf-tp-intro{font-size:11px}
.sf-theme-trade-pro .sf-tp-about-facility figcaption{padding:9px 10px}
.sf-theme-trade-pro .sf-tp-about-facility .sf-tp-tag{font-size:10px}
}