2026-10-15 20:25:00 +08:00
{#
2026-10-26 00:50:43 +08:00
Copyright 2024-2026 ReplyPier
2026-10-15 20:25:00 +08:00
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Shared chrome for the public help center (list page + article page): head/meta,
all CSS, header, contact CTA, footer, and the chat-widget embed. Pages fill the
`hero`, `body` and `page_scripts` blocks.
Every org/FAQ value is escaped by Jinja2 autoescaping. The ONE exception is the
article body, which is pre-sanitized to an HTML allowlist by
app.services.help_center_content and rendered with `| safe`; never mark any other
org content safe. Colors: only `--brand`/`--brand-ink` come from the server
(validated hex); every other tone is derived in CSS via color-mix.
#}<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< title > {{ title }}</ title >
< meta name = "description" content = "{{ description }}" >
< link rel = "canonical" href = "{{ canonical_url }}" >
{% if favicon_url %}< link rel = "icon" href = "{{ favicon_url }}" > {% endif %}
< meta property = "og:title" content = "{{ title }}" >
< meta property = "og:description" content = "{{ description }}" >
< meta property = "og:type" content = "{{ og_type | default('website') }}" >
< meta property = "og:url" content = "{{ canonical_url }}" >
{% if og_site_name %}< meta property = "og:site_name" content = "{{ og_site_name }}" > {% endif %}
{# og:image must be absolute (scrapers don't resolve relative URLs) — the
route absolutizes it. Without an image the card degrades to a text
summary rather than showing a broken thumbnail. #}
{% if og_image %}
< meta property = "og:image" content = "{{ og_image }}" >
< meta name = "twitter:card" content = "summary_large_image" >
< meta name = "twitter:image" content = "{{ og_image }}" >
{% else %}
< meta name = "twitter:card" content = "summary" >
{% endif %}
< meta name = "twitter:title" content = "{{ title }}" >
< meta name = "twitter:description" content = "{{ description }}" >
< link rel = "preconnect" href = "https://fonts.googleapis.com" >
< link rel = "preconnect" href = "https://fonts.gstatic.com" crossorigin >
< link href = "https://fonts.googleapis.com/css2?family=Sora:wght@400;500;600;700&family=Instrument+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel = "stylesheet" >
< style >
: root {
--brand : {{ brand_color } } ;
--brand-ink : { { brand_ink } } ;
--brand-tint : color-mix ( in srgb , var ( --brand ) 9 %, # fff );
--brand-soft : color-mix ( in srgb , var ( --brand ) 30 %, # fff );
--brand-line : color-mix ( in srgb , var ( --brand ) 40 %, # fff );
--hero-bg : linear-gradient ( 180deg , color-mix ( in srgb , var ( --brand ) 10 %, # fff ), # f5f6f9 80 %);
--hero-glow : radial-gradient ( ellipse , color-mix ( in srgb , var ( --brand ) 12 %, transparent ), transparent 68 %);
--cta-bg : linear-gradient ( 120deg , var ( --brand ), color-mix ( in srgb , var ( --brand ) 78 %, # fff ));
--cta-sub : color-mix ( in srgb , var ( --brand-ink ) 72 %, transparent );
--sans : 'Instrument Sans' , system-ui , -apple-system , sans-serif ;
--display : 'Sora' , var ( --sans );
--mono : 'JetBrains Mono' , ui-monospace , monospace ;
}
* { box-sizing : border-box ; }
/* Author display rules (e.g. .hc-card { display:flex }) otherwise beat the UA
[hidden] rule, so the hidden attribute must win explicitly for JS toggling. */
[ hidden ] { display : none !important ; }
html , body { margin : 0 ; padding : 0 ; background : #f5f6f9 ; }
body { color : #1a1b25 ; font-family : var ( -- sans ); -webkit- font-smoothing : antialiased ; min-height : 100 vh ; }
a { color : var ( -- brand ); }
:: selection { background : var ( -- brand - soft ); color : #1a1b25 ; }
@ keyframes hc-rise { from { opacity : 0 ; transform : translateY ( 8 px ); } to { opacity : 1 ; transform : translateY ( 0 ); } }
@ keyframes hc-blink { 0 %, 100 % { opacity : .3 ; } 50 % { opacity : 1 ; } }
@ keyframes hc-shimmer { 0 % { background-position : 200 % 0 ; } 100 % { background-position : -200 % 0 ; } }
/* ---------- header ---------- */
. hc-header { background : #fff ; border-bottom : 1 px solid #ececf2 ; position : sticky ; top : 0 ; z-index : 40 ; }
. hc-header-in { max-width : 1120 px ; margin : 0 auto ; display : flex ; align-items : center ; justify-content : space-between ; gap : 16 px ; padding : 15 px 28 px ; }
. hc-brand { display : flex ; align-items : center ; gap : 11 px ; text-decoration : none ; color : inherit ; min-width : 0 ; }
. hc-mark { width : 30 px ; height : 30 px ; border-radius : 9 px ; background : var ( -- brand ); display : flex ; align-items : center ; justify-content : center ; flex-shrink : 0 ; }
. hc-mark span { width : 12 px ; height : 12 px ; border-radius : 3 px ; background : var ( -- brand - ink ); transform : rotate ( 45 deg ); }
. hc-logo { height : 30 px ; width : auto ; display : block ; flex-shrink : 0 ; }
. hc-name { font-family : var ( -- display ); font-weight : 700 ; font-size : 19 px ; letter-spacing : -.02 em ; white-space : nowrap ; overflow : hidden ; text-overflow : ellipsis ; }
. hc-kicker { font-size : 14 px ; color : #8a90a0 ; font-weight : 500 ; padding-left : 12 px ; border-left : 1 px solid #e4e6ec ; white-space : nowrap ; }
. hc-nav { display : flex ; align-items : center ; gap : 20 px ; font-size : 14.5 px ; flex-shrink : 0 ; }
. hc-nav a { color : #5a6172 ; text-decoration : none ; }
. hc-nav a : hover { color : #1a1b25 ; }
. hc-nav a . cta { padding : 9 px 17 px ; background : var ( -- brand ); color : var ( -- brand - ink ); border-radius : 10 px ; font-weight : 600 ; }
/* ---------- hero ---------- */
. hc-hero { position : relative ; overflow : hidden ; background : var ( -- hero - bg ); padding : 58 px 28 px 46 px ; }
. hc-hero-glow { position : absolute ; top : -90 px ; left : 50 % ; transform : translateX ( -50 % ); width : 640 px ; height : 340 px ; max-width : 100 % ; background : var ( -- hero - glow ); pointer-events : none ; }
. hc-hero-in { position : relative ; max-width : 720 px ; margin : 0 auto ; text-align : center ; }
. hc-hero h1 { font-family : var ( -- display ); font-weight : 700 ; font-size : 38 px ; line-height : 1.1 ; letter-spacing : -.03 em ; margin : 0 0 12 px ; }
. hc-hero p . lead { font-size : 16.5 px ; color : #5a6172 ; margin : 0 0 26 px ; }
. hc-searchbar { display : flex ; align-items : center ; gap : 12 px ; background : #fff ; border : 1 px solid #e4e6ec ; border-radius : 15 px ; padding : 6 px 6 px 6 px 18 px ; box-shadow : 0 12 px 34 px rgba ( 40 , 36 , 90 , .08 ); max-width : 600 px ; margin : 0 auto ; }
. hc-searchbar svg { flex-shrink : 0 ; }
. hc-searchbar input { flex : 1 ; min-width : 0 ; background : transparent ; border : none ; outline : none ; font-size : 16 px ; color : #1a1b25 ; font-family : var ( -- sans ); padding : 12 px 0 ; }
. hc-searchbar input :: placeholder { color : #9aa0ad ; }
. hc-clear { flex-shrink : 0 ; width : 34 px ; height : 34 px ; border-radius : 9 px ; background : #f1f2f6 ; border : none ; color : #8a90a0 ; cursor : pointer ; font-size : 14 px ; display : none ; }
. hc-popular { display : flex ; align-items : center ; justify-content : center ; gap : 9 px ; margin-top : 18 px ; font-size : 13.5 px ; color : #8a90a0 ; flex-wrap : wrap ; }
. hc-chip { padding : 5 px 12 px ; background : #fff ; border : 1 px solid #e4e6ec ; border-radius : 999 px ; font-size : 13 px ; color : #4a5163 ; cursor : pointer ; font-family : var ( -- sans ); text-decoration : none ; }
. hc-chip : hover { border-color : var ( -- brand - soft ); }
/* ---------- body layout ---------- */
. hc-body { max-width : 1120 px ; margin : 0 auto ; padding : 40 px 28 px 20 px ; display : grid ; grid-template-columns : 250 px 1 fr ; gap : 36 px ; align-items : start ; }
. hc-aside { position : sticky ; top : 82 px ; }
. hc-aside-label { font-family : var ( -- mono ); font-size : 11 px ; letter-spacing : .09 em ; color : #9aa0ad ; padding : 0 6 px ; margin-bottom : 12 px ; }
. hc-topics { display : flex ; flex-direction : column ; gap : 4 px ; }
. hc-topic { display : flex ; align-items : center ; gap : 11 px ; width : 100 % ; padding : 9 px 10 px ; border-radius : 12 px ; cursor : pointer ; font-family : var ( -- sans ); border : 1 px solid transparent ; background : transparent ; color : #4a5163 ; transition : background .15 s ; text-decoration : none ; text-align : left ; }
. hc-topic : hover { background : #fff ; }
. hc-topic . active { border-color : var ( -- brand - soft ); background : var ( -- brand - tint ); color : #1a1b25 ; }
. hc-topic-icon { width : 30 px ; height : 30 px ; flex-shrink : 0 ; border-radius : 9 px ; display : flex ; align-items : center ; justify-content : center ; background : color-mix ( in srgb , var ( -- ic ) 12 % , #fff ); color : var ( -- ic ); }
. hc-topic-name { flex : 1 ; min-width : 0 ; text-align : left ; font-size : 14.5 px ; font-weight : 500 ; white-space : nowrap ; overflow : hidden ; text-overflow : ellipsis ; }
. hc-topic . active . hc-topic-name { font-weight : 600 ; }
. hc-topic-count { flex-shrink : 0 ; font-family : var ( -- mono ); font-size : 12 px ; color : #b4b9c4 ; }
. hc-topic . active . hc-topic-count { color : var ( -- brand ); }
. hc-help-card { margin-top : 22 px ; padding : 18 px ; background : #fff ; border : 1 px solid #ececf2 ; border-radius : 16 px ; box-shadow : 0 2 px 10 px rgba ( 40 , 36 , 90 , .04 ); }
. hc-help-card h3 { font-family : var ( -- display ); font-weight : 600 ; font-size : 14.5 px ; margin : 0 0 5 px ; }
. hc-help-card p { font-size : 13 px ; color : #8a90a0 ; line-height : 1.5 ; margin : 0 0 13 px ; }
. hc-main { min-width : 0 ; }
/* ---------- AI answer ---------- */
. hc-ai-wrap { margin-bottom : 24 px ; }
. hc-ask-btn { display : inline-flex ; align-items : center ; gap : 8 px ; padding : 11 px 18 px ; background : #fff ; border : 1 px solid var ( -- brand - soft ); color : var ( -- brand ); border-radius : 12 px ; font-size : 14 px ; font-weight : 600 ; cursor : pointer ; font-family : var ( -- sans ); }
. hc-ask-btn : hover { background : var ( -- brand - tint ); }
. hc-ai { background : #fff ; border : 1 px solid var ( -- brand - soft ); border-radius : 18 px ; padding : 22 px 24 px ; box-shadow : 0 12 px 34 px rgba ( 40 , 36 , 90 , .06 ); animation : hc-rise .3 s ease ; }
. hc-ai-head { display : flex ; align-items : center ; gap : 10 px ; margin-bottom : 13 px ; flex-wrap : wrap ; }
. hc-badge { display : inline-flex ; align-items : center ; gap : 7 px ; padding : 5 px 11 px ; background : var ( -- brand - tint ); border : 1 px solid var ( -- brand - soft ); border-radius : 999 px ; font-family : var ( -- mono ); font-size : 11 px ; font-weight : 500 ; color : var ( -- brand ); letter-spacing : .04 em ; }
. hc-dots { display : inline-flex ; gap : 3 px ; }
. hc-dots span { width : 4 px ; height : 4 px ; border-radius : 50 % ; background : var ( -- brand ); animation : hc-blink 1 s ease-in-out infinite ; }
. hc-dots span : nth-child ( 2 ) { animation-delay : .18 s ; }
. hc-dots span : nth-child ( 3 ) { animation-delay : .36 s ; }
. hc-ai-note { font-size : 12 px ; color : #9aa0ad ; }
. hc-ai-answer { font-size : 16 px ; line-height : 1.65 ; color : #2a303e ; margin : 0 ; white-space : pre-line ; }
. hc-ai-foot { display : flex ; align-items : center ; justify-content : flex-end ; gap : 16 px ; flex-wrap : wrap ; padding-top : 14 px ; margin-top : 14 px ; border-top : 1 px solid #f1f2f6 ; }
. hc-skeleton { display : flex ; flex-direction : column ; gap : 9 px ; }
. hc-skeleton span { height : 12 px ; border-radius : 6 px ; background : linear-gradient ( 90 deg , #eef0f4 , #f6f7f9 , #eef0f4 ); background-size : 200 % 100 % ; animation : hc-shimmer 1.3 s linear infinite ; }
/* ---------- content header ---------- */
. hc-head { display : flex ; align-items : center ; gap : 12 px ; margin-bottom : 18 px ; }
. hc-head-icon { width : 38 px ; height : 38 px ; flex-shrink : 0 ; border-radius : 11 px ; display : flex ; align-items : center ; justify-content : center ; background : color-mix ( in srgb , var ( -- ic ) 12 % , #fff ); color : var ( -- ic ); }
. hc-head h2 { font-family : var ( -- display ); font-weight : 600 ; font-size : 22 px ; letter-spacing : -.02 em ; margin : 0 ; }
. hc-head-sub { font-size : 13.5 px ; color : #8a90a0 ; margin-top : 2 px ; }
/* ---------- FAQ list (link cards) ---------- */
. hc-list { display : flex ; flex-direction : column ; gap : 10 px ; }
. hc-card { display : flex ; align-items : center ; justify-content : space-between ; gap : 16 px ; background : #fff ; border : 1 px solid #ececf2 ; border-radius : 14 px ; padding : 16 px 20 px ; text-decoration : none ; box-shadow : 0 1 px 5 px rgba ( 40 , 36 , 90 , .03 ); transition : border-color .18 s , transform .18 s ; }
. hc-card : hover { border-color : var ( -- brand - soft ); transform : translateY ( -1 px ); }
. hc-card-main { min-width : 0 ; flex : 1 ; }
. hc-tag { display : none ; font-family : var ( -- mono ); font-size : 10.5 px ; padding : 3 px 8 px ; border-radius : 6 px ; background : color-mix ( in srgb , var ( -- ic ) 12 % , #fff ); color : var ( -- ic ); margin-bottom : 8 px ; }
. hc-qtext { display : block ; font-size : 15.5 px ; font-weight : 600 ; color : #1a1b25 ; line-height : 1.4 ; }
. hc-preview { display : block ; font-size : 13.5 px ; color : #8a90a0 ; line-height : 1.5 ; margin-top : 4 px ; overflow : hidden ; text-overflow : ellipsis ; white-space : nowrap ; }
. hc-card-meta { flex-shrink : 0 ; display : flex ; align-items : center ; gap : 12 px ; }
. hc-read { font-size : 12 px ; color : #b4b9c4 ; white-space : nowrap ; }
. hc-chev { color : #8a90a0 ; display : flex ; }
/* ---------- grouped browse: every category with its own articles ---------- */
. hc-groups { display : flex ; flex-direction : column ; gap : 30 px ; }
. hc-group { scroll-margin-top : 90 px ; }
. hc-group-head { margin-bottom : 14 px ; }
. hc-group-head h2 { font-size : 19 px ; }
. hc-empty { text-align : center ; padding : 56 px 20 px ; background : #fff ; border : 1 px solid #ececf2 ; border-radius : 18 px ; }
. hc-empty-icon { width : 52 px ; height : 52 px ; margin : 0 auto 18 px ; border-radius : 14 px ; background : #f5f6f9 ; border : 1 px solid #ececf2 ; display : flex ; align-items : center ; justify-content : center ; color : #9aa0ad ; }
. hc-empty h3 { font-family : var ( -- display ); font-weight : 600 ; font-size : 19 px ; margin : 0 0 8 px ; }
. hc-empty p { font-size : 15 px ; color : #8a90a0 ; margin : 0 0 20 px ; }
/* ---------- article page ---------- */
/* Breadcrumb trail. The markup mirrors the BreadcrumbList JSON-LD exactly —
change one and change the other, or the structured data stops matching
the visible content. The current page is text, not a link. */
. hc-crumbs { display : flex ; align-items : center ; flex-wrap : wrap ; gap : 6 px ; margin-bottom : 20 px ; font-family : var ( -- sans ); font-size : 13.5 px ; color : #8a90a0 ; }
. hc-crumbs a { color : #8a90a0 ; text-decoration : none ; }
. hc-crumbs a : hover { color : #4a5163 ; text-decoration : underline ; }
. hc-crumb-sep { color : #c4c8d2 ; }
/* The article title can be long; keep the trail to one tidy line. */
. hc-crumb-current { color : #4a5163 ; max-width : min ( 100 % , 340 px ); overflow : hidden ; text-overflow : ellipsis ; white-space : nowrap ; }
. hc-article-meta { display : flex ; align-items : center ; gap : 10 px ; margin-bottom : 14 px ; flex-wrap : wrap ; }
. hc-article-tag { font-family : var ( -- mono ); font-size : 11 px ; padding : 4 px 10 px ; border-radius : 7 px ; background : color-mix ( in srgb , var ( -- ic ) 12 % , #fff ); color : var ( -- ic ); }
. hc-article-time { font-size : 13 px ; color : #9aa0ad ; }
. hc-article h1 { font-family : var ( -- display ); font-weight : 700 ; font-size : 30 px ; line-height : 1.2 ; letter-spacing : -.025 em ; margin : 0 0 22 px ; }
. hc-article-card { background : #fff ; border : 1 px solid #ececf2 ; border-radius : 18 px ; padding : 30 px 32 px ; box-shadow : 0 2 px 12 px rgba ( 40 , 36 , 90 , .04 ); }
/* rendered Markdown body */
. hc-article-body { font-size : 15.5 px ; color : #3a4152 ; line-height : 1.72 ; }
/* A short, single-paragraph answer reads larger so it doesn't look lost in
the card's whitespace. */
. hc-article-body > p : only-child { font-size : 18 px ; line-height : 1.6 ; color : #2a3040 ; }
. hc-article-body > : first-child { margin-top : 0 ; }
. hc-article-body > : last-child { margin-bottom : 0 ; }
. hc-article-body p { margin : 0 0 16 px ; }
. hc-article-body h1 , . hc-article-body h2 , . hc-article-body h3 , . hc-article-body h4 { font-family : var ( -- display ); font-weight : 600 ; letter-spacing : -.015 em ; color : #1a1b25 ; margin : 28 px 0 12 px ; line-height : 1.3 ; }
. hc-article-body h1 { font-size : 22 px ; }
. hc-article-body h2 { font-size : 19 px ; }
. hc-article-body h3 { font-size : 16.5 px ; }
. hc-article-body h4 { font-size : 15 px ; }
. hc-article-body a { color : var ( -- brand ); font-weight : 600 ; text-decoration : none ; }
. hc-article-body a : hover { text-decoration : underline ; }
. hc-article-body img { max-width : 100 % ; height : auto ; display : block ; border-radius : 14 px ; border : 1 px solid #ececf2 ; margin : 8 px 0 22 px ; }
. hc-article-body ul , . hc-article-body ol { margin : 6 px 0 22 px ; padding-left : 24 px ; }
. hc-article-body li { margin-bottom : 8 px ; }
. hc-article-body blockquote { margin : 6 px 0 22 px ; padding : 14 px 18 px ; background : var ( -- brand - tint ); border : 1 px solid var ( -- brand - soft ); border-left : 3 px solid var ( -- brand ); border-radius : 12 px ; color : #3a4152 ; }
. hc-article-body blockquote p { margin : 0 ; }
. hc-article-body code { font-family : var ( -- mono ); font-size : 13 px ; background : #f1f2f6 ; border-radius : 5 px ; padding : 1 px 6 px ; }
. hc-article-body pre { background : #f1f2f6 ; border-radius : 12 px ; padding : 14 px 16 px ; overflow-x : auto ; margin : 6 px 0 22 px ; }
. hc-article-body pre code { background : none ; padding : 0 ; }
. hc-article-body table { border-collapse : collapse ; width : 100 % ; margin : 6 px 0 22 px ; font-size : 14 px ; }
. hc-article-body th , . hc-article-body td { border : 1 px solid #ececf2 ; padding : 8 px 11 px ; text-align : left ; }
. hc-article-body th { background : #f5f6f9 ; font-weight : 600 ; }
. hc-article-body hr { border : none ; border-top : 1 px solid #ececf2 ; margin : 24 px 0 ; }
. hc-feedback { display : flex ; align-items : center ; gap : 14 px ; margin-top : 10 px ; padding-top : 20 px ; border-top : 1 px solid #f1f2f6 ; flex-wrap : wrap ; }
. hc-feedback-q { font-size : 13.5 px ; color : #8a90a0 ; }
. hc-vote { display : inline-flex ; align-items : center ; gap : 6 px ; padding : 7 px 13 px ; border-radius : 9 px ; font-size : 13 px ; cursor : pointer ; font-family : var ( -- sans ); background : #f5f6f9 ; border : 1 px solid #e4e6ec ; color : #4a5163 ; }
. hc-vote . on-yes { background : var ( -- brand - tint ); border-color : var ( -- brand - soft ); color : var ( -- brand ); }
. hc-vote . on-no { background : #fdecea ; border-color : #f3c6be ; color : #cf5b38 ; }
. hc-thanks { font-size : 12.5 px ; color : var ( -- brand ); font-weight : 600 ; }
/* related articles */
. hc-related { margin-top : 34 px ; }
. hc-related-label { font-family : var ( -- mono ); font-size : 11 px ; letter-spacing : .09 em ; color : #9aa0ad ; margin-bottom : 14 px ; }
. hc-related-grid { display : grid ; grid-template-columns : repeat ( 2 , 1 fr ); gap : 12 px ; }
. hc-related-card { display : flex ; flex-direction : column ; gap : 14 px ; height : 100 % ; padding : 18 px ; background : #fff ; border : 1 px solid #ececf2 ; border-radius : 15 px ; text-decoration : none ; box-shadow : 0 1 px 5 px rgba ( 40 , 36 , 90 , .03 ); transition : border-color .18 s , transform .18 s , box-shadow .18 s ; }
. hc-related-card : hover { border-color : var ( -- brand - soft ); transform : translateY ( -2 px ); box-shadow : 0 12 px 26 px rgba ( 40 , 36 , 90 , .08 ); }
. hc-related-top { display : flex ; align-items : center ; justify-content : space-between ; }
. hc-related-icon { width : 34 px ; height : 34 px ; border-radius : 10 px ; background : color-mix ( in srgb , var ( -- ic ) 12 % , #fff ); color : var ( -- ic ); display : flex ; align-items : center ; justify-content : center ; }
. hc-related-q { display : block ; font-family : var ( -- display ); font-size : 15 px ; font-weight : 600 ; color : #1a1b25 ; line-height : 1.35 ; letter-spacing : -.01 em ; }
. hc-related-time { display : inline-flex ; align-items : center ; gap : 6 px ; margin-top : auto ; font-size : 12.5 px ; color : #9aa0ad ; }
/* ---------- contact CTA ---------- */
. hc-cta-shell { max-width : 1120 px ; margin : 0 auto ; padding : 0 28 px ; }
. hc-cta { margin : 24 px 0 56 px ; background : var ( -- cta - bg ); border-radius : 24 px ; padding : 44 px ; display : flex ; align-items : center ; justify-content : space-between ; gap : 30 px ; flex-wrap : wrap ; color : var ( -- brand - ink ); scroll-margin-top : 90 px ; }
. hc-cta h2 { font-family : var ( -- display ); font-weight : 700 ; font-size : 26 px ; letter-spacing : -.02 em ; margin : 0 0 8 px ; }
. hc-cta p { font-size : 16 px ; color : var ( -- cta - sub ); margin : 0 ; max-width : 440 px ; line-height : 1.55 ; }
. hc-cta-btn { display : inline-flex ; align-items : center ; gap : 10 px ; padding : 15 px 26 px ; background : var ( -- brand - ink ); color : var ( -- brand ); border : none ; border-radius : 13 px ; font-size : 15.5 px ; font-weight : 600 ; cursor : pointer ; font-family : var ( -- sans ); white-space : nowrap ; text-decoration : none ; }
/* ---------- footer ---------- */
. hc-footer { border-top : 1 px solid #ececf2 ; background : #fff ; }
. hc-footer-in { max-width : 1120 px ; margin : 0 auto ; padding : 30 px 28 px ; display : flex ; align-items : center ; justify-content : space-between ; gap : 24 px ; flex-wrap : wrap ; }
. hc-footer-org { display : flex ; align-items : center ; gap : 11 px ; }
. hc-footer-org . hc-mark { width : 26 px ; height : 26 px ; border-radius : 8 px ; }
. hc-footer-org . hc-mark span { width : 10 px ; height : 10 px ; }
. hc-footer-org . hc-name { font-size : 15 px ; }
. hc-powered { display : inline-flex ; align-items : center ; gap : 8 px ; text-decoration : none ; padding : 7 px 13 px ; border : 1 px solid #ececf2 ; border-radius : 999 px ; font-size : 12.5 px ; color : #8a90a0 ; }
. hc-powered strong { display : inline-flex ; align-items : center ; gap : 6 px ; color : #1a1b25 ; font-weight : 600 ; }
2026-10-26 00:50:43 +08:00
. hc-rp-mark { width : 15 px ; height : 15 px ; border-radius : 5 px 5 px 5 px 1 px ; background : #c9f24e ; display : inline-flex ; align-items : center ; justify-content : center ; gap : 1.5 px ; }
. hc-rp-mark i { width : 2 px ; height : 2 px ; border-radius : 50 % ; background : #0b0c10 ; }
2026-10-15 20:25:00 +08:00
/* progressive enhancement: only hide things once JS takes over */
. js . hc-tag { display : none ; }
@ media ( max-width : 860px ) {
/* Compact hero so the topics and articles start higher up. */
. hc-hero { padding : 30 px 20 px 22 px ; }
. hc-hero h1 { font-size : 25 px ; margin-bottom : 6 px ; }
. hc-hero p . lead { font-size : 14.5 px ; margin-bottom : 16 px ; }
. hc-searchbar { padding : 5 px 5 px 5 px 14 px ; }
. hc-searchbar input { padding : 11 px 0 ; font-size : 15.5 px ; }
/* The 2-column topic grid below is the category picker on mobile, so the
duplicate "Popular" chips just add height. */
. hc-popular { display : none ; }
. hc-body { grid-template-columns : 1 fr ; gap : 16 px ; padding : 18 px 16 px 16 px ; }
. hc-aside { position : static ; min-width : 0 ; }
. hc-main { min-width : 0 ; }
. hc-aside-label { margin-bottom : 10 px ; }
/* Topics: a compact 3-row band that scrolls left/right. Fixed-width
auto-columns + overflow-x keep the scroll contained to this strip (the
page never scrolls sideways), so it stays short instead of a tall grid. */
. hc-topics {
display : grid ;
grid-auto-flow : column ;
grid-template-rows : repeat ( 3 , auto );
grid-auto-columns : 46 % ;
gap : 8 px ;
overflow-x : auto ;
overscroll-behavior-x : contain ;
scroll-snap-type : x proximity ;
-webkit- overflow-scrolling : touch ;
scrollbar-width : none ;
padding : 0 2 px 4 px ;
margin : 0 -2 px ;
}
. hc-topics :: -webkit-scrollbar { display : none ; }
. hc-topic { width : auto ; min-width : 0 ; padding : 10 px 11 px ; gap : 9 px ; scroll-snap-align : start ; }
. hc-topic-icon { width : 26 px ; height : 26 px ; }
. hc-topic-name { font-size : 13.5 px ; }
/* Redundant on mobile — the "Still need a hand?" CTA below covers it. */
. hc-help-card { display : none ; }
/* While searching, get the whole browse-topics column out of the way so
the results (and the Ask-AI card) sit right under the search box,
instead of on a "second page" below every category. Also tighten the
hero/body padding so results sit close to the search box. */
body . hc-searching . hc-aside { display : none ; }
body . hc-searching . hc-hero { padding-bottom : 8 px ; }
body . hc-searching . hc-body { padding-top : 8 px ; }
. hc-cta { padding : 30 px ; }
. hc-article-card { padding : 24 px 20 px ; }
. hc-related-grid { grid-template-columns : 1 fr ; }
}
</ style >
{% block extra_head %}{% endblock %}
</ head >
< body >
<!-- ============ HEADER ============ -->
< header class = "hc-header" >
< div class = "hc-header-in" >
< a class = "hc-brand" href = "{{ base_path }}/" >
{% if logo_url %}
< img class = "hc-logo" src = "{{ logo_url }}" alt = "{{ row.organization.name }} logo" >
{% else %}
< span class = "hc-mark" >< span ></ span ></ span >
{% endif %}
< span class = "hc-name" > {{ row.organization.name }}</ span >
< span class = "hc-kicker" > Help Center</ span >
</ a >
< nav class = "hc-nav" >
{% for link in header_links %}< a href = "{{ link.url }}" rel = "noopener" > {{ link.label }}</ a > {% endfor %}
{% if row.cta_enabled and row.cta_text and row.cta_url %}< a class = "cta" href = "{{ row.cta_url }}" rel = "noopener" > {{ row.cta_text }}</ a > {% endif %}
</ nav >
</ div >
</ header >
{% block hero %}{% endblock %}
{% block body %}{% endblock %}
<!-- ============ CONTACT CTA ============ -->
{% set cta_shown = row.cta_enabled and row.cta_text and row.cta_url %}
{% if widget_id or cta_shown %}
< div class = "hc-cta-shell" >
< section class = "hc-cta" id = "contact" >
< div >
< h2 > Still need a hand?</ h2 >
< p > {% if widget_id %}Our support assistant answers instantly, any time of day — and connects you to a human whenever you need one.{% else %}Reach out and our team will get back to you.{% endif %}</ p >
</ div >
{% if widget_id %}
< button class = "hc-cta-btn" type = "button" data-chat >
< svg viewBox = "0 0 24 24" width = "18" height = "18" fill = "none" stroke = "currentColor" stroke-width = "2" stroke-linecap = "round" stroke-linejoin = "round" >< path d = "M21 11.5a8.5 8.5 0 0 1-12.3 7.6L3 21l1.9-5.7A8.5 8.5 0 1 1 21 11.5z" ></ path ></ svg >
Start a chat
</ button >
{% elif cta_shown %}
< a class = "hc-cta-btn" href = "{{ row.cta_url }}" rel = "noopener" > {{ row.cta_text }}</ a >
{% endif %}
</ section >
</ div >
{% endif %}
<!-- ============ FOOTER ============ -->
< footer class = "hc-footer" >
< div class = "hc-footer-in" >
< div class = "hc-footer-org" >
{% if logo_url %}
< img class = "hc-logo" src = "{{ logo_url }}" alt = "{{ row.organization.name }} logo" >
{% else %}
< span class = "hc-mark" >< span ></ span ></ span >
{% endif %}
< span class = "hc-name" > {{ row.organization.name }}</ span >
</ div >
2026-10-26 00:50:43 +08:00
< a class = "hc-powered" href = "https://replypier.site" target = "_blank" rel = "noopener" >
2026-10-15 20:25:00 +08:00
< span > Powered by</ span >
2026-10-26 00:50:43 +08:00
< strong >< span class = "hc-rp-mark" >< i ></ i >< i ></ i >< i ></ i ></ span > ReplyPier</ strong >
2026-10-15 20:25:00 +08:00
</ a >
</ div >
</ footer >
{% if json_ld %}
< script type = "application/ld+json" >{{ json_ld | tojson }}</ script >
{% endif %}
2026-10-26 00:50:43 +08:00
<!-- open the real embedded ReplyPier widget -->
2026-10-15 20:25:00 +08:00
< script >
( function () {
2026-10-26 00:50:43 +08:00
// The widget script is async and builds its launcher (#replypier-button)
2026-10-15 20:25:00 +08:00
// a moment after load, so a click can land before it exists — poll briefly
// and click as soon as it appears instead of silently doing nothing.
function openChat () {
var tries = 0 ;
( function attempt () {
2026-10-26 00:50:43 +08:00
var btn = document . getElementById ( 'replypier-button' );
2026-10-15 20:25:00 +08:00
if ( btn ) { btn . click (); return ; }
if ( tries ++ < 40 ) { setTimeout ( attempt , 150 ); return ; } // ~6s
2026-10-26 00:50:43 +08:00
if ( window . console ) console . warn ( '[ReplyPier] chat widget is not available on this page.' );
2026-10-15 20:25:00 +08:00
})();
}
[]. slice . call ( document . querySelectorAll ( '[data-chat]' )). forEach ( function ( b ) {
b . addEventListener ( 'click' , openChat );
});
})();
</ script >
{% block page_scripts %}{% endblock %}
{% if widget_id %}
< script >
2026-10-26 00:50:43 +08:00
window . replypierId = {{ widget_id | tojson }};
2026-10-15 20:25:00 +08:00
// Must be set, exactly like the dashboard's install snippet does: the loader
// otherwise falls back to the API URL baked in at build time (the vendor
// cloud), so a self-hosted help center would ask the wrong backend for its
// widget and the visitor would just see "Chat Unavailable".
2026-10-26 00:50:43 +08:00
window . replypierBaseUrl = {{ widget_api_url | tojson }};
2026-10-15 20:25:00 +08:00
( function () {
var s = document . createElement ( 'script' );
s . src = {{ widget_script_url | tojson }};
s . async = true ;
document . body . appendChild ( s );
})();
</ script >
{% endif %}
</ body >
</ html >