Files
pangolin/design/prototype/index.html
T

944 lines
68 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>穿山甲 Pangolin · 设计系统</title>
<link rel="stylesheet" href="tokens.css">
<link rel="stylesheet" href="atoms.css">
<script src="icons.js"></script>
<style>
/* ── 登记页自身骨架(chrome)— 尽量走 token,登记页外壳可适度宽松 ── */
body{ margin:0; background:var(--bg); color:var(--fg1); font-family:var(--font-sans);
-webkit-font-smoothing:antialiased; transition:background-color var(--dur-base) var(--ease-out); overflow-x:hidden; }
.ic{ width:22px; height:22px; color:currentColor; }
/* 顶栏 */
.ds-top{ position:sticky; top:0; z-index:50; height:60px; background:var(--surface);
border-bottom:1px solid var(--border); display:flex; align-items:center; gap:14px;
padding:0 var(--space-6); box-shadow:var(--shadow-sm); }
.ds-brand{ display:flex; align-items:center; gap:var(--space-3); font-family:var(--font-display);
font-weight:700; color:var(--fg1); font-size:var(--text-body); }
.ds-brand .mk{ width:30px; height:30px; border-radius:var(--radius-md);
background:linear-gradient(135deg,var(--clay-500),var(--clay-800));
color:#fff; display:flex; align-items:center; justify-content:center; }
.ds-brand .mk svg{ width:17px; height:17px; }
.ds-tag{ font-size:var(--text-caption); color:var(--fg3); padding-left:var(--space-3);
border-left:1px solid var(--border); font-weight:500; }
.theme-toggle{ margin-left:auto; display:inline-flex; align-items:center; gap:var(--space-2);
background:var(--bg-subtle); border:1px solid var(--border); color:var(--fg2);
border-radius:var(--radius-full); padding:var(--space-2) var(--space-4);
font-family:var(--font-sans); font-weight:600; font-size:var(--text-caption);
cursor:pointer; transition:border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out); }
.theme-toggle:hover{ border-color:var(--border-strong); color:var(--fg1); }
.theme-toggle svg{ width:15px; height:15px; }
/* 三栏文档布局 */
.doc{ display:flex; align-items:flex-start; max-width:1360px; margin:0 auto; }
.doc-nav{ width:238px; flex:none; position:sticky; top:60px; height:calc(100vh - 60px);
overflow-y:auto; overscroll-behavior:contain; border-right:1px solid var(--border);
padding:var(--space-5) var(--space-4) calc(var(--space-16) * 2);
transition:width var(--dur-base) var(--ease-out); }
/* 收起态(宽度由 JS 置 0,此处收内边距/边框) */
.doc.nav-collapsed .doc-nav{ padding-left:0; padding-right:0; border-right:none; overflow:hidden; }
.doc.nav-collapsed .nav-resize{ display:none; }
/* 拖拽把手(改侧栏宽度) */
.nav-resize{ flex:none; align-self:stretch; position:sticky; top:60px; height:calc(100vh - 60px);
width:9px; margin-left:-5px; cursor:col-resize; z-index:40; background:transparent; }
.nav-resize::after{ content:""; position:absolute; left:4px; top:0; bottom:0; width:2px; border-radius:var(--radius-full);
background:transparent; transition:background-color var(--dur-fast) var(--ease-out); }
.nav-resize:hover::after, .nav-resize.dragging::after{ background:var(--accent); }
body.nav-dragging{ cursor:col-resize; user-select:none; }
/* 顶栏收起按钮 */
.nav-toggle{ display:inline-flex; align-items:center; justify-content:center; width:34px; height:34px; flex:none;
border:1px solid var(--border); border-radius:var(--radius-md); background:var(--bg-subtle);
color:var(--fg2); cursor:pointer; transition:color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out); }
.nav-toggle:hover{ color:var(--fg1); border-color:var(--border-strong); }
.nav-toggle svg{ width:18px; height:18px; }
/* L1 分组头 —— 分隔线 + 提亮加粗,与二级明显区分 */
.dgroup{ font-size:var(--text-caption); font-weight:700; color:var(--fg2); letter-spacing:var(--tracking-caps);
text-transform:uppercase; padding:var(--space-2) var(--space-2);
margin-top:var(--space-5); border-top:1px solid var(--border); }
.doc-nav .dgroup:first-child{ margin-top:var(--space-1); border-top:none; }
/* L2 条目 —— 缩进内嵌于分组下 */
.dnav{ display:block; padding:var(--space-2) var(--space-3) var(--space-2) var(--space-5); border-radius:var(--radius-md);
font-size:var(--text-sm); color:var(--fg2); text-decoration:none; cursor:pointer;
transition:background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out); }
.dnav:hover{ background:var(--bg-subtle); color:var(--fg1); }
.dnav.on{ background:var(--accent-subtle); color:var(--accent); font-weight:600; }
.doc-main{ flex:1; min-width:0; padding:var(--space-8) var(--space-10) var(--space-16); max-width:1080px; }
.section{ margin-bottom:var(--space-12); scroll-margin-top:76px; }
.section > h2{ margin:0 0 var(--space-1); font-family:var(--font-display); font-size:var(--text-h1);
font-weight:700; letter-spacing:var(--tracking-tight); color:var(--fg1); }
.section > .desc{ margin:0 0 var(--space-5); font-size:var(--text-sm); color:var(--fg2); line-height:var(--leading-normal); }
.section > .desc code{ font-family:var(--font-mono); font-size:0.85em; color:var(--accent);
background:var(--accent-subtle); padding:1px 6px; border-radius:var(--radius-sm); }
/* 展示卡(页面 chrome,非 atoms.card 以免混淆语义) */
.pcard{ background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-lg);
margin-bottom:var(--space-4); overflow:hidden; }
.pcard-h{ display:flex; align-items:baseline; gap:var(--space-3); padding:var(--space-3) var(--space-5);
border-bottom:1px solid var(--border); }
.pcard-h h3{ margin:0; font-family:var(--font-sans); font-size:var(--text-h3); font-weight:600; color:var(--fg1); }
.pcard-h .tk{ font-size:var(--text-caption); color:var(--fg3); font-family:var(--font-mono); }
.pcard-b{ padding:var(--space-5); display:flex; flex-wrap:wrap; gap:var(--space-4); align-items:center; }
.pcard-b.col{ display:block; }
.cap{ width:100%; font-size:var(--text-caption); color:var(--fg3); font-family:var(--font-mono);
margin:var(--space-4) 0 var(--space-2); }
.cap:first-child{ margin-top:0; }
/* 色板 */
.sw-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:var(--space-3); width:100%; }
.sw{ border:1px solid var(--border); border-radius:var(--radius-md); overflow:hidden; background:var(--surface); }
.sw .band{ display:block; width:100%; height:56px; box-shadow:inset 0 0 0 1px rgba(45,30,20,.08); }
.sw .m{ padding:var(--space-2) var(--space-3); }
.sw .m .n{ font-size:var(--text-caption); color:var(--fg1); font-weight:600; }
.sw .m .v{ font-size:11px; color:var(--fg3); font-family:var(--font-mono); }
/* 字号梯度 */
.type-row{ display:flex; align-items:baseline; gap:var(--space-5); padding:var(--space-3) 0;
border-bottom:1px solid var(--border); width:100%; }
.type-row:last-child{ border-bottom:none; }
.type-row .tk{ width:170px; font-size:var(--text-caption); color:var(--fg3);
font-family:var(--font-mono); flex:none; }
.type-row .spec{ display:flex; flex-direction:column; gap:2px; min-width:0; }
/* 圆角 / 间距 / 阴影 比例尺 */
.scale{ display:flex; flex-wrap:wrap; gap:var(--space-5); align-items:flex-end; width:100%; }
.scale .box{ display:flex; flex-direction:column; align-items:center; gap:var(--space-2);
font-size:var(--text-caption); color:var(--fg2); font-family:var(--font-mono); }
.scale .rq{ width:60px; height:60px; background:var(--accent-subtle); border:1.5px solid var(--accent); }
.scale .sq{ height:38px; background:var(--accent); border-radius:2px; }
.scale .sh{ width:72px; height:52px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-md); }
/* 图标库网格 */
.icon-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(108px,1fr)); gap:var(--space-2); width:100%; }
.icell{ display:flex; flex-direction:column; align-items:center; gap:var(--space-2);
padding:var(--space-4) var(--space-2); border:1px solid var(--border);
border-radius:var(--radius-md); background:var(--surface); color:var(--fg1); }
.icell .ic{ width:24px; height:24px; }
.icell span{ font-size:11px; color:var(--fg2); font-family:var(--font-mono); text-align:center; word-break:break-all; line-height:1.3; }
.count-pill{ font-family:var(--font-sans); }
@media (max-width:840px){
.doc-nav{ display:none; }
.nav-resize{ display:none; }
.nav-toggle{ display:none; }
.doc-main{ padding:var(--space-6) var(--space-5) var(--space-12); }
}
/* ── 品牌 / 字体 specimen 展示用(登记页 chrome,非 atoms;全走 token ── */
.brand-appicon{ display:flex; align-items:flex-end; gap:var(--space-8); flex-wrap:wrap; }
.brand-appicon .unit{ display:flex; flex-direction:column; align-items:center; gap:var(--space-2); }
.brand-appicon .unit .n{ font-family:var(--font-mono); font-size:11px; color:var(--fg3); }
.brand-appicon img{ display:block; box-shadow:var(--shadow-md); border-radius:22%; }
.lockup{ display:flex; align-items:center; gap:var(--space-3); }
.lockup img{ display:block; }
.lockup .tw{ display:flex; flex-direction:column; line-height:1; }
.lockup .cn{ font-family:var(--font-display); font-weight:700; font-size:22px; letter-spacing:var(--tracking-snug); color:var(--fg1); }
.lockup .en{ font-family:var(--font-display); font-weight:600; font-size:10px; letter-spacing:0.22em; color:var(--accent); margin-top:4px; }
.lockup-panel{ flex:1; min-width:220px; display:flex; flex-direction:column; align-items:center; gap:var(--space-3);
padding:var(--space-8); border-radius:var(--radius-lg); border:1px solid var(--border); }
.lockup-panel .plab{ font-family:var(--font-mono); font-size:10px; color:var(--fg3); }
.spec-mono-grid{ display:grid; grid-template-columns:repeat(3,1fr); gap:var(--space-5); width:100%; }
.spec-mono-grid .k{ font-family:var(--font-mono); font-size:11px; color:var(--fg3); margin-bottom:4px; }
.spec-mono-grid .v{ font-family:var(--font-mono); font-size:22px; font-weight:500; letter-spacing:var(--tracking-snug);
color:var(--fg1); font-feature-settings:'tnum' 1; }
.spec-mono-grid .v .u{ font-size:12px; color:var(--accent); font-weight:400; }
@media (max-width:560px){ .spec-mono-grid{ grid-template-columns:repeat(2,1fr); } }
</style>
</head>
<body>
<div class="ds-top">
<button class="nav-toggle" id="navToggle" aria-label="收起 / 展开侧栏" title="收起 / 展开侧栏"><svg class="ic"><use href="#i-menu"/></svg></button>
<div class="ds-brand"><span class="mk"><img src="../assets/app-icon.svg" alt="穿山甲" style="width:100%;height:100%;object-fit:contain;border-radius:inherit"></span>穿山甲 Pangolin</div>
<span class="ds-tag">设计系统登记簿 · Prototype</span>
<button class="theme-toggle" id="themeBtn" aria-label="切换主题">
<svg class="ic"><use href="#i-sun" id="themeIcon"/></svg><span id="themeLabel">浅色</span>
</button>
</div>
<div class="doc">
<nav class="doc-nav" id="docNav">
<div class="dgroup">UI Kit · 交互原型</div>
<a class="dnav" href="screens/ui-mobile.html" style="color:var(--accent);font-weight:600">↗ 移动版 App</a>
<a class="dnav" href="screens/ui-desktop.html" style="color:var(--accent);font-weight:600">↗ 桌面版</a>
<a class="dnav" href="screens/site.html" style="color:var(--accent);font-weight:600">↗ 官网 Site</a>
<div class="dgroup">品牌 Brand</div>
<a class="dnav" data-s="b-appicon">App 图标家族</a>
<a class="dnav" data-s="b-logo">Logo 锁版</a>
<div class="dgroup">色彩 Colors</div>
<a class="dnav" data-s="c-clay">clay 黏土铜色阶</a>
<a class="dnav" data-s="c-sand">sand 沙米中性阶</a>
<a class="dnav" data-s="c-hue">语义色相</a>
<a class="dnav" data-s="c-sem">语义 token</a>
<a class="dnav" data-s="c-dark">暗色主题表面</a>
<div class="dgroup">字体 Type</div>
<a class="dnav" data-s="t-body">正文字体 Manrope</a>
<a class="dnav" data-s="t-cjk">中文字体 Noto Sans SC</a>
<a class="dnav" data-s="t-display">Display 字体 Sora</a>
<a class="dnav" data-s="t-mono">等宽数据字体 JetBrains Mono</a>
<a class="dnav" data-s="type">字号梯度</a>
<div class="dgroup">尺度 Scale</div>
<a class="dnav" data-s="radius">圆角</a>
<a class="dnav" data-s="space">间距</a>
<a class="dnav" data-s="shadow">阴影</a>
<div class="dgroup">组件 Atoms</div>
<a class="dnav" data-s="a-btn">按钮 .btn</a>
<a class="dnav" data-s="a-card">卡片 .card</a>
<a class="dnav" data-s="a-viewbody">内容容器 .view-body</a>
<a class="dnav" data-s="a-input">输入 .input</a>
<a class="dnav" data-s="a-pill">胶囊 .pill / .badge</a>
<a class="dnav" data-s="a-lang">语言下拉 .langsel</a>
<a class="dnav" data-s="a-connect">核心连接按钮 .connect-btn</a>
<a class="dnav" data-s="a-server">服务器列表行 .server-row</a>
<a class="dnav" data-s="a-badge">状态徽章 .pill 场景</a>
<div class="dgroup">组件 · 线上对齐</div>
<a class="dnav" data-s="a-formctl">复合输入 · 开关 · 图标框</a>
<a class="dnav" data-s="a-quota">额度卡 · 指标卡</a>
<a class="dnav" data-s="a-rows">设备行 · 设置行</a>
<a class="dnav" data-s="a-planbn">套餐横幅 · 会员卡</a>
<a class="dnav" data-s="a-appchrome">更新条 · Tab · 侧栏项</a>
<div class="dgroup">购买 Purchase</div>
<a class="dnav" data-s="a-plan">套餐卡 .plan-card</a>
<a class="dnav" data-s="a-paym">支付方式 .pay-method</a>
<a class="dnav" data-s="a-kv">明细行 .kv-row</a>
<a class="dnav" data-s="a-result">结果态 .result</a>
<div class="dgroup">图标 Icons</div>
<a class="dnav" data-s="icons">Lucide 图标库</a>
</nav>
<div class="nav-resize" id="navResize" title="拖动调整侧栏宽度"></div>
<main class="doc-main">
<!-- ══════════ 品牌 Brand ══════════ -->
<section class="section" id="b-appicon">
<h2>App 图标家族</h2>
<p class="desc">母题=行走穿山甲(实心鳞甲剪影,朝右)置于 clay 渐变圆角方。矢量单源 <code>design/assets/app-icon.svg</code>,多尺寸直接引用同一文件(零漂移,非内联副本)。</p>
<div class="pcard"><div class="pcard-h"><h3>多尺寸</h3><span class="tk">104 · 64 · 40 · 28</span></div><div class="pcard-b"><div class="brand-appicon">
<div class="unit"><img src="../assets/app-icon.svg" width="104" height="104" alt="穿山甲 app 图标 104"><span class="n">104 · 主图标</span></div>
<div class="unit"><img src="../assets/app-icon.svg" width="64" height="64" alt="app 图标 64"><span class="n">64</span></div>
<div class="unit"><img src="../assets/app-icon.svg" width="40" height="40" alt="app 图标 40"><span class="n">40</span></div>
<div class="unit"><img src="../assets/app-icon.svg" width="28" height="28" alt="app 图标 28"><span class="n">28</span></div>
</div></div></div>
</section>
<section class="section" id="b-logo">
<h2>Logo 锁版</h2>
<p class="desc">图标 mark + 字标水平锁版。浅色背景用主锁版 <code>logo-mark.svg</code>,深色背景用反白锁版 <code>logo-mark-white.svg</code>;整体横版字标 <code>logo-wordmark.svg</code>。矢量单源 <code>design/assets/</code></p>
<div class="pcard"><div class="pcard-h"><h3>主锁版 / 反白锁版</h3><span class="tk">logo-mark.svg · logo-mark-white.svg</span></div><div class="pcard-b" style="align-items:stretch">
<div class="lockup-panel" style="background:var(--sand-50)">
<div class="lockup"><img src="../assets/logo-mark.svg" width="46" height="46" alt="穿山甲 mark"><div class="tw"><span class="cn">穿山甲</span><span class="en">PANGOLIN</span></div></div>
<span class="plab">主锁版 · 浅色背景</span>
</div>
<div class="lockup-panel" data-theme="dark" style="background:var(--sand-950)">
<div class="lockup"><img src="../assets/logo-mark-white.svg" width="46" height="46" alt="穿山甲 mark 反白"><div class="tw"><span class="cn">穿山甲</span><span class="en">PANGOLIN</span></div></div>
<span class="plab">反白锁版 · 深色背景</span>
</div>
</div></div>
<div class="pcard"><div class="pcard-h"><h3>横版字标</h3><span class="tk">logo-wordmark.svg · 240×56</span></div><div class="pcard-b" style="background:var(--sand-50)">
<img src="../assets/logo-wordmark.svg" width="240" height="56" alt="穿山甲 Pangolin 字标">
</div></div>
</section>
<!-- ══════════ 色彩 ══════════ -->
<section class="section" id="c-clay">
<h2>clay · 黏土铜色阶</h2>
<p class="desc">品牌主色阶(穿山甲鳞甲的暖大地色)。<code>--clay-500</code> 为品牌主色,浅色主题 accent 取 500、深色取 400。</p>
<div class="pcard"><div class="pcard-b"><div class="sw-grid" data-swatches="--clay-50,--clay-100,--clay-200,--clay-300,--clay-400,--clay-500,--clay-600,--clay-700,--clay-800,--clay-900"></div></div></div>
</section>
<section class="section" id="c-sand">
<h2>sand · 沙米中性阶</h2>
<p class="desc">暖中性色阶。浅色画布 <code>--sand-50</code>,深色画布暖 espresso <code>--sand-950</code>(非纯黑)。</p>
<div class="pcard"><div class="pcard-b"><div class="sw-grid" data-swatches="--sand-50,--sand-100,--sand-200,--sand-300,--sand-400,--sand-500,--sand-600,--sand-700,--sand-800,--sand-900,--sand-950"></div></div></div>
</section>
<section class="section" id="c-hue">
<h2>语义色相</h2>
<p class="desc">地色调校过的三组状态色相:绿=连接/安全,琥珀=连接中/提示,红=断开/错误。</p>
<div class="pcard"><div class="pcard-b"><div class="sw-grid" data-swatches="--green-400,--green-500,--green-600,--amber-400,--amber-500,--amber-600,--red-400,--red-500,--red-600"></div></div></div>
</section>
<section class="section" id="c-sem">
<h2>语义 token</h2>
<p class="desc">界面只引用这一层(浅/深自动切换)。切右上主题看色值实时变化。</p>
<div class="pcard"><div class="pcard-h"><h3>背景 / 表面</h3><span class="tk">--bg · --surface · --overlay</span></div><div class="pcard-b"><div class="sw-grid" data-swatches="--bg,--bg-subtle,--surface,--surface-2,--overlay"></div></div></div>
<div class="pcard"><div class="pcard-h"><h3>前景 / 文本</h3><span class="tk">--fg1/2/3 · --fg-on-accent</span></div><div class="pcard-b"><div class="sw-grid" data-swatches="--fg1,--fg2,--fg3,--fg-on-accent"></div></div></div>
<div class="pcard"><div class="pcard-h"><h3>品牌 accent</h3><span class="tk">--accent(+hover/press/subtle/border)</span></div><div class="pcard-b"><div class="sw-grid" data-swatches="--accent,--accent-hover,--accent-press,--accent-subtle,--accent-border"></div></div></div>
<div class="pcard"><div class="pcard-h"><h3>描边 / 光环</h3><span class="tk">--border · --border-strong · --ring</span></div><div class="pcard-b"><div class="sw-grid" data-swatches="--border,--border-strong,--ring"></div></div></div>
<div class="pcard"><div class="pcard-h"><h3>状态语义</h3><span class="tk">success / warning / danger (+ -subtle)</span></div><div class="pcard-b"><div class="sw-grid" data-swatches="--success,--success-subtle,--warning,--warning-subtle,--danger,--danger-subtle"></div></div></div>
</section>
<section class="section" id="c-dark">
<h2>暗色主题表面</h2>
<p class="desc">暗色画布=暖 espresso <code>--sand-950</code>(非纯黑)。表面层级 <code>--bg</code>(应用画布)→ <code>--surface</code>(卡片/面板)→ <code>--surface-2</code>(嵌套层),逐级提亮保持暖调。此卡固定演示暗色,不随右上主题切换。</p>
<div class="pcard"><div class="pcard-h"><h3>表面层级(固定暗色演示)</h3><span class="tk">--bg · --surface · --surface-2</span></div>
<div class="pcard-b" data-theme="dark" style="background:var(--sand-950); gap:var(--space-3)">
<div class="card" style="flex:1; min-width:150px; background:var(--bg)"><div class="t-h3" style="color:var(--fg1); font-size:15px">bg</div><div class="t-caption" style="color:var(--fg2); margin-top:4px">应用画布</div><div class="t-mono" style="color:var(--fg3); font-size:11px; margin-top:2px">#14110E</div></div>
<div class="card" style="flex:1; min-width:150px; background:var(--surface)"><div class="t-h3" style="color:var(--fg1); font-size:15px">surface</div><div class="t-caption" style="color:var(--fg2); margin-top:4px">卡片 / 面板</div><div class="t-mono" style="color:var(--fg3); font-size:11px; margin-top:2px">#221E19</div></div>
<div class="card" style="flex:1; min-width:150px; background:var(--surface-2)"><div class="t-h3" style="color:var(--fg1); font-size:15px">surface-2</div><div class="t-caption" style="color:var(--fg2); margin-top:4px">嵌套层</div><div class="t-mono" style="color:var(--fg3); font-size:11px; margin-top:2px">#2A251F</div><span class="pill pill-accent" style="margin-top:var(--space-3)">Accent</span></div>
</div>
</div>
</section>
<!-- ══════════ 字体 specimen ══════════ -->
<section class="section" id="t-body">
<h2>正文字体 · Manrope</h2>
<p class="desc">界面与正文主力(<code>--font-sans</code>,权重 400–700)。人文几何,中英混排稳定。示例中英分行、单句不并排。</p>
<div class="pcard"><div class="pcard-h"><h3>Body · Manrope</h3><span class="tk">--font-sans · 400 / 500 / 600 / 700</span></div><div class="pcard-b col">
<p class="t-h3" style="margin:0 0 var(--space-2)">一键连接,极速畅连</p>
<p class="t-body-lg" style="margin:0 0 var(--space-2); color:var(--fg2)">轻盈、亲和、即开即用的网络加速。</p>
<p class="t-body" style="margin:0 0 var(--space-2)">Body 16px — 全球 80+ 加速线路,智能选择最快节点,稳定不掉线。</p>
<p class="t-sm" style="margin:0; color:var(--fg2)">Small 14px — 适用于次要说明、列表副标题与表单提示文字。</p>
</div></div>
</section>
<section class="section" id="t-cjk">
<h2>中文字体 · Noto Sans SC</h2>
<p class="desc">中文专用伴随字体(<code>--font-cjk</code>,权重 400 / 500 / 700)。与 Manrope / Sora 同框时保证中文字形与字重一致。</p>
<div class="pcard"><div class="pcard-h"><h3>CJK · Noto Sans SC</h3><span class="tk">--font-cjk · 400 / 500 / 700</span></div><div class="pcard-b col" style="font-family:var(--font-cjk)">
<p style="margin:0; font-size:34px; font-weight:700; letter-spacing:var(--tracking-snug)">穿山甲 · 守护每一次连接</p>
<p style="margin:var(--space-3) 0 0; font-size:18px; font-weight:500; color:var(--fg2)">无需配置,打开即用。智能分流,海外应用秒开。</p>
<p style="margin:var(--space-2) 0 0; font-size:14px; color:var(--fg3)">隐私保护 · 我们不记录你的浏览数据 · 端到端加密</p>
</div></div>
</section>
<section class="section" id="t-display">
<h2>Display 字体 · Sora</h2>
<p class="desc">标题、营销大字、Logo 字标(<code>--font-display</code>,权重 600 / 700)。几何友好,字距收紧 <code>-0.02em</code></p>
<div class="pcard"><div class="pcard-h"><h3>Display · Sora</h3><span class="tk">--font-display · 600 / 700</span></div><div class="pcard-b col">
<p class="t-display-xl" style="margin:0 0 var(--space-3); line-height:1.05">极速畅连 Smooth</p>
<p class="t-display" style="margin:0; line-height:1.05; color:var(--accent)">极速 · 稳定 · 省心</p>
</div></div>
</section>
<section class="section" id="t-mono">
<h2>等宽数据字体 · JetBrains Mono</h2>
<p class="desc">IP / 速率 / 时长 / 密钥等数据读数(<code>--font-mono</code>,开 tabular nums 等宽对齐,数字不跳动)。</p>
<div class="pcard"><div class="pcard-h"><h3>Mono · JetBrains Mono</h3><span class="tk">--font-mono · tnum</span></div><div class="pcard-b"><div class="spec-mono-grid">
<div><div class="k">DOWNLOAD</div><div class="v">86.4<span class="u"> Mb/s</span></div></div>
<div><div class="k">PING</div><div class="v">24<span class="u"> ms</span></div></div>
<div><div class="k">UPTIME</div><div class="v">02:14:08</div></div>
<div><div class="k">EXIT IP</div><div class="v" style="font-size:16px">103.27.18.204</div></div>
<div><div class="k">PROTOCOL</div><div class="v" style="font-size:16px">REALITY</div></div>
<div><div class="k">DATA</div><div class="v">1.82<span class="u"> GB</span></div></div>
</div></div></div>
</section>
<!-- ══════════ 字号 ══════════ -->
<section class="section" id="type">
<h2>字号梯度</h2>
<p class="desc">Display 用 Sora,正文/UI 用 Manrope,中文伴随 Noto Sans SC,数据用 JetBrains Mono。示例单语显示(中英分行,非并排同句)。</p>
<div class="pcard"><div class="pcard-b col">
<div class="type-row"><span class="tk">--text-display-xl 48</span><span class="spec"><span class="t-display-xl">极速畅连</span><span class="t-display-xl">Fast &amp; Stable</span></span></div>
<div class="type-row"><span class="tk">--text-display 36</span><span class="spec"><span class="t-display">网络加速</span><span class="t-display">Network Boost</span></span></div>
<div class="type-row"><span class="tk">--text-h1 30</span><span class="spec"><span class="t-h1">一键连接</span><span class="t-h1">One-tap Connect</span></span></div>
<div class="type-row"><span class="tk">--text-h2 24</span><span class="spec"><span class="t-h2">智能选线</span><span class="t-h2">Smart Routing</span></span></div>
<div class="type-row"><span class="tk">--text-h3 20</span><span class="spec"><span class="t-h3">隐私保护</span><span class="t-h3">Privacy First</span></span></div>
<div class="type-row"><span class="tk">--text-body-lg 18</span><span class="spec"><span class="t-body-lg">稳定加速线路,即开即用。</span><span class="t-body-lg">Stable links, ready instantly.</span></span></div>
<div class="type-row"><span class="tk">--text-body 16</span><span class="spec"><span class="t-body">正文与界面主力字号,兼顾中英排版。</span><span class="t-body">Body copy for UI and long-form reading.</span></span></div>
<div class="type-row"><span class="tk">--text-sm 14</span><span class="spec"><span class="t-sm">次要说明与表单标签。</span><span class="t-sm">Secondary hints and form labels.</span></span></div>
<div class="type-row"><span class="tk">--text-caption 12</span><span class="spec"><span class="t-caption">辅助注释与胶囊文字。</span><span class="t-caption">Captions and pill text.</span></span></div>
<div class="type-row"><span class="tk">.t-overline</span><span class="spec"><span class="t-overline">连接状态</span><span class="t-overline">Connection Status</span></span></div>
<div class="type-row"><span class="tk">.t-mono 数据</span><span class="spec"><span class="t-mono">103.119.13.48 · 42 ms · 1.28 GB</span></span></div>
</div></div>
</section>
<!-- ══════════ 尺度 ══════════ -->
<section class="section" id="radius">
<h2>圆角 Radius</h2>
<p class="desc">偏大圆角传递亲和。按钮全胶囊 <code>--radius-full</code>,卡片 lgxl,输入 md。</p>
<div class="pcard"><div class="pcard-b"><div class="scale">
<div class="box"><div class="rq" style="border-radius:var(--radius-sm)"></div>sm · 6</div>
<div class="box"><div class="rq" style="border-radius:var(--radius-md)"></div>md · 10</div>
<div class="box"><div class="rq" style="border-radius:var(--radius-lg)"></div>lg · 14</div>
<div class="box"><div class="rq" style="border-radius:var(--radius-xl)"></div>xl · 20</div>
<div class="box"><div class="rq" style="border-radius:var(--radius-2xl)"></div>2xl · 28</div>
<div class="box"><div class="rq" style="border-radius:var(--radius-full)"></div>full · 999</div>
</div></div></div>
</section>
<section class="section" id="space">
<h2>间距 Spacing</h2>
<p class="desc">4px 基准网格。</p>
<div class="pcard"><div class="pcard-b"><div class="scale">
<div class="box"><div class="sq" style="width:var(--space-1)"></div>1 · 4</div>
<div class="box"><div class="sq" style="width:var(--space-2)"></div>2 · 8</div>
<div class="box"><div class="sq" style="width:var(--space-3)"></div>3 · 12</div>
<div class="box"><div class="sq" style="width:var(--space-4)"></div>4 · 16</div>
<div class="box"><div class="sq" style="width:var(--space-5)"></div>5 · 20</div>
<div class="box"><div class="sq" style="width:var(--space-6)"></div>6 · 24</div>
<div class="box"><div class="sq" style="width:var(--space-8)"></div>8 · 32</div>
<div class="box"><div class="sq" style="width:var(--space-10)"></div>10 · 40</div>
<div class="box"><div class="sq" style="width:var(--space-12)"></div>12 · 48</div>
<div class="box"><div class="sq" style="width:var(--space-16)"></div>16 · 64</div>
</div></div></div>
</section>
<section class="section" id="shadow">
<h2>阴影 Shadow</h2>
<p class="desc">柔和暖调(<code>rgba(45,30,20,…)</code>),绝不用冷灰阴影。</p>
<div class="pcard"><div class="pcard-b"><div class="scale">
<div class="box"><div class="sh" style="box-shadow:var(--shadow-sm)"></div>sm</div>
<div class="box"><div class="sh" style="box-shadow:var(--shadow-md)"></div>md</div>
<div class="box"><div class="sh" style="box-shadow:var(--shadow-lg)"></div>lg</div>
<div class="box"><div class="sh" style="box-shadow:var(--shadow-xl)"></div>xl</div>
<div class="box"><div class="sh" style="box-shadow:var(--shadow-focus)"></div>focus</div>
</div></div></div>
</section>
<!-- ══════════ 组件 ══════════ -->
<section class="section" id="a-btn">
<h2>按钮 · .btn</h2>
<p class="desc">全胶囊圆角 · hover 主色加深 · press 缩放 .97 · focus clay 光环。变体 <code>.btn-primary/-ghost/-subtle/-danger</code>,尺寸 <code>.btn-lg/-icon/-block</code></p>
<div class="pcard"><div class="pcard-h"><h3>变体</h3><span class="tk">.btn + .btn-primary/-ghost/-subtle/-danger</span></div><div class="pcard-b">
<button class="btn btn-primary"><svg class="ic"><use href="#i-power"/></svg>点击连接</button>
<button class="btn btn-ghost"><svg class="ic"><use href="#i-refresh-cw"/></svg>刷新延迟</button>
<button class="btn btn-subtle"><svg class="ic"><use href="#i-settings"/></svg>偏好设置</button>
<button class="btn btn-danger"><svg class="ic"><use href="#i-power"/></svg>断开连接</button>
</div></div>
<div class="pcard"><div class="pcard-h"><h3>尺寸 / 形态</h3><span class="tk">.btn-lg · .btn-icon · .btn-block</span></div><div class="pcard-b">
<button class="btn btn-primary btn-lg"><svg class="ic"><use href="#i-zap"/></svg>智能选择</button>
<button class="btn btn-primary btn-icon" aria-label="更多"><svg class="ic"><use href="#i-more-vertical"/></svg></button>
<button class="btn btn-subtle btn-icon" aria-label="搜索"><svg class="ic"><use href="#i-search"/></svg></button>
<div style="width:100%"><button class="btn btn-primary btn-block"><svg class="ic"><use href="#i-download"/></svg>立即下载</button></div>
</div></div>
<div class="pcard"><div class="pcard-h"><h3>禁用态</h3><span class="tk">:disabled · .is-disabled</span></div><div class="pcard-b">
<button class="btn btn-primary" disabled>已连接</button>
<button class="btn btn-subtle is-disabled">不可用</button>
<button class="btn btn-danger" disabled>断开连接</button>
</div></div>
</section>
<section class="section" id="a-card">
<h2>卡片 · .card</h2>
<p class="desc">surface 底 + border + radius-xl + shadow-sm。<code>.card-flush</code> 用于列表容器(内容自带 padding)。</p>
<div class="pcard"><div class="pcard-b">
<div class="card" style="max-width:280px">
<div class="t-overline" style="color:var(--fg3)">当前节点</div>
<div class="t-h3" style="margin:var(--space-2) 0 var(--space-1)">香港 · HK 加速线路</div>
<div class="t-sm" style="color:var(--fg2)">稳定 · 无日志 · 隐私保护</div>
</div>
<div class="card card-flush" style="max-width:280px; width:100%">
<div style="padding:var(--space-4) var(--space-5); border-bottom:1px solid var(--border)" class="t-sm">HK · 香港</div>
<div style="padding:var(--space-4) var(--space-5); border-bottom:1px solid var(--border)" class="t-sm">JP · 东京</div>
<div style="padding:var(--space-4) var(--space-5)" class="t-sm">SG · 新加坡</div>
</div>
</div></div>
</section>
<section class="section" id="a-viewbody">
<h2>内容容器 · .view-body</h2>
<p class="desc">桌面客户端内容视图统一宽度容器:默认居中 <code>600px</code>(账户/设置/联系我们/统计/订单/通知/邀请等单栏页),<code>.is-wide</code> 修饰 <code>840px</code>(购买套餐等多列网格页)。padding 固定 <code>space-5 space-6 space-6</code>。对齐 Flutter <code>PageBody</code>(<code>client/lib/widgets/page_body.dart</code>)。</p>
<div class="pcard"><div class="pcard-h"><h3>默认 · 600px</h3><span class="tk">.view-body</span></div><div class="pcard-b col">
<div style="border:1px dashed var(--border-strong); border-radius:var(--radius-md); background:var(--bg-subtle)">
<div class="view-body" style="border:1px solid var(--accent-border); background:var(--surface); border-radius:var(--radius-md)">
<div class="t-overline" style="color:var(--fg3)">.view-body</div>
<div class="t-h3" style="margin:var(--space-2) 0 var(--space-1)">单栏内容视图</div>
<div class="t-sm" style="color:var(--fg2)">max-width:600px · margin:0 auto 居中 · padding 5/6/6</div>
</div>
</div>
</div></div>
<div class="pcard"><div class="pcard-h"><h3>宽 · 840px</h3><span class="tk">.view-body.is-wide</span></div><div class="pcard-b col">
<div style="border:1px dashed var(--border-strong); border-radius:var(--radius-md); background:var(--bg-subtle)">
<div class="view-body is-wide" style="border:1px solid var(--accent-border); background:var(--surface); border-radius:var(--radius-md)">
<div class="t-overline" style="color:var(--fg3)">.view-body.is-wide</div>
<div class="t-h3" style="margin:var(--space-2) 0 var(--space-1)">多列网格页(购买套餐)</div>
<div class="t-sm" style="color:var(--fg2)">max-width:840px · padding 沿用默认 5/6/6</div>
</div>
</div>
</div></div>
</section>
<section class="section" id="a-input">
<h2>输入 · .input / .field / .flabel</h2>
<p class="desc">强描边 + radius-md + focus clay 光环。状态 <code>.is-focused</code> / <code>.is-error</code> / <code>:disabled</code></p>
<div class="pcard"><div class="pcard-b" style="align-items:flex-start">
<label class="field" style="width:220px"><span class="flabel">邮箱</span><input class="input" placeholder="me@pangolin.app"></label>
<label class="field" style="width:220px"><span class="flabel">焦点态</span><input class="input is-focused" value="已聚焦"></label>
<label class="field" style="width:220px"><span class="flabel">错误态</span><input class="input is-error" value="激活码无效"></label>
<label class="field" style="width:220px"><span class="flabel">禁用态</span><input class="input" value="不可编辑" disabled></label>
</div></div>
</section>
<section class="section" id="a-pill">
<h2>胶囊 · .pill / .badge</h2>
<p class="desc">状态用「色点 + 文字胶囊」,非 emoji。状态修饰 <code>.is-success/-warning/-danger/-neutral</code>,变体 <code>.pill-accent</code> / <code>.pill-outline</code><code>.badge</code><code>.pill</code> 语义别名。</p>
<div class="pcard"><div class="pcard-h"><h3>状态修饰</h3><span class="tk">.pill.is-*(含 .dot</span></div><div class="pcard-b">
<span class="pill is-success"><span class="dot"></span>已连接</span>
<span class="pill is-warning"><span class="dot"></span>连接中</span>
<span class="pill is-danger"><span class="dot"></span>已断开</span>
<span class="pill is-neutral"><span class="dot"></span>未连接</span>
<span class="pill"><span class="dot"></span>默认</span>
</div></div>
<div class="pcard"><div class="pcard-h"><h3>变体 / 别名</h3><span class="tk">.pill-accent · .pill-outline · .badge</span></div><div class="pcard-b">
<span class="pill pill-accent">PRO 会员</span>
<span class="pill pill-outline">流媒体</span>
<span class="pill pill-outline">P2P</span>
<span class="badge is-success"><span class="dot"></span>badge 别名</span>
</div></div>
</section>
<section class="section" id="a-lang">
<h2>语言下拉 · .langsel</h2>
<p class="desc">不依赖原生 <code>&lt;select&gt;</code>:触发药丸 <code>.langsel-trigger</code> + 自控绝对定位菜单 <code>.menu</code> / <code>.menu-item</code>(选中态 <code>.is-selected</code>)。点触发按钮可实际展开/收起。</p>
<div class="pcard" style="overflow:visible"><div class="pcard-b" style="min-height:180px; align-items:flex-start">
<div class="langsel" id="langselDemo">
<button class="langsel-trigger" id="langTrigger" aria-expanded="true" aria-haspopup="true">
简体中文 <svg class="ic"><use href="#i-chevron-down"/></svg>
</button>
<div class="menu" id="langMenu" style="left:0; right:auto">
<button class="menu-item is-selected" aria-selected="true">简体中文</button>
<button class="menu-item">English</button>
<button class="menu-item">日本語</button>
<button class="menu-item">한국어</button>
<button class="menu-item">Русский</button>
<button class="menu-item">Español</button>
</div>
</div>
<span class="t-caption" style="color:var(--fg3)">↖ 默认展开演示,可点击触发按钮收起 / 展开</span>
</div></div>
</section>
<!-- ══════════ 核心连接按钮 ══════════ -->
<section class="section" id="a-connect">
<h2>核心连接按钮 · .connect-btn</h2>
<p class="desc">产品<strong>招牌组件</strong>:圆形一键连接键,三态 <code>.is-off</code> / <code>.is-connecting</code> / <code>.is-on</code>。背景在渐变↔纯色间切换仅过渡 <code>box-shadow</code>/<code>background-color</code><strong></strong> <code>transition:all</code>,否则背景计算失效)。轨道环用内联 <code>&lt;svg&gt;</code>,圆内为图标 + 标签 / 计时。镜像 <code>client/lib/widgets/connect_button.dart</code></p>
<div class="pcard"><div class="pcard-b" style="justify-content:center; gap:var(--space-10); padding:var(--space-8) var(--space-5)">
<div style="display:flex; flex-direction:column; align-items:center; gap:var(--space-3)">
<button class="connect-btn is-off">
<svg class="cb-ring" viewBox="0 0 140 140"><circle class="cb-track" cx="70" cy="70" r="64"/></svg>
<svg class="cb-icon"><use href="#i-power"/></svg>
<span class="cb-label">点击连接</span>
<span class="cb-sub">TAP TO CONNECT</span>
</button>
<span class="t-caption" style="color:var(--fg3)">未连接 Off</span>
</div>
<div style="display:flex; flex-direction:column; align-items:center; gap:var(--space-3)">
<button class="connect-btn is-connecting">
<svg class="cb-ring cb-spin" viewBox="0 0 140 140">
<circle class="cb-arc-track" cx="70" cy="70" r="64"/>
<circle class="cb-arc" cx="70" cy="70" r="64"/>
</svg>
<svg class="cb-icon cb-spin"><use href="#i-loader-circle"/></svg>
<span class="cb-label">连接中</span>
<span class="cb-sub">CONNECTING…</span>
</button>
<span class="t-caption" style="color:var(--fg3)">建立隧道 Connecting</span>
</div>
<div style="display:flex; flex-direction:column; align-items:center; gap:var(--space-3)">
<button class="connect-btn is-on">
<svg class="cb-ring" viewBox="0 0 140 140"><circle class="cb-ring-full" cx="70" cy="70" r="64"/></svg>
<svg class="cb-icon"><use href="#i-shield-check"/></svg>
<span class="cb-timer">02:14:08</span>
<span class="cb-sub">已加密 · SECURE</span>
</button>
<span class="t-caption" style="color:var(--fg3)">已连接 Connected</span>
</div>
</div></div>
</section>
<!-- ══════════ 服务器列表行 ══════════ -->
<section class="section" id="a-server">
<h2>服务器列表行 · .server-row</h2>
<p class="desc">节点列表一行:<strong>国家码块</strong>(2 字母,绝不用 emoji 国旗)+ 名称/子名 + 属性胶囊(<code>.pill-outline</code>+ 延迟(<code>--font-mono</code>·按值变色)+ 信号条 + 选中/推荐/不可用态。镜像 <code>client/lib/widgets/server_tile.dart</code>。放进 <code>.card.card-flush</code> 列表容器。</p>
<div class="pcard"><div class="pcard-h"><h3>列表行</h3><span class="tk">.server-row · .is-selected · .is-down</span></div><div class="pcard-b col">
<div class="card card-flush" style="max-width:460px; width:100%">
<div class="server-row is-selected">
<div class="sr-cc">HK</div>
<div class="sr-body">
<div class="sr-title">香港 · 加速线路</div>
<div class="sr-tags"><span class="pill pill-outline">流媒体</span></div>
</div>
<span class="sr-latency is-good">18ms</span>
<span class="sr-check"><svg class="ic"><use href="#i-check"/></svg></span>
</div>
<div class="server-row">
<div class="sr-cc">JP</div>
<div class="sr-body">
<div class="sr-title">日本 东京</div>
<div class="sr-sub">Tokyo</div>
</div>
<span class="sr-latency is-good">32ms</span>
<span class="sr-signal"><i></i><i></i><i></i></span>
</div>
<div class="server-row">
<div class="sr-cc">SG</div>
<div class="sr-body">
<div class="sr-title">新加坡</div>
<div class="sr-tags"><span class="pill pill-outline">P2P</span></div>
</div>
<span class="sr-latency is-warn">54ms</span>
<span class="sr-signal"><i></i><i></i><i class="is-off"></i></span>
</div>
<div class="server-row is-down">
<div class="sr-cc">US</div>
<div class="sr-body">
<div class="sr-title">美国 洛杉矶</div>
<div class="sr-sub">Los Angeles</div>
</div>
<span class="sr-unavail">不可用</span>
</div>
</div>
</div></div>
<div class="pcard"><div class="pcard-h"><h3>智能选择推荐行</h3><span class="tk">.server-row.is-smart · zap + 推荐胶囊</span></div><div class="pcard-b col">
<div class="card card-flush" style="max-width:460px; width:100%">
<div class="server-row is-smart">
<div class="sr-smart-ic"><svg class="ic"><use href="#i-zap"/></svg></div>
<div class="sr-body">
<div class="sr-title">智能选择</div>
<div class="sr-sub">根据当前网络环境,自动选择最优节点</div>
</div>
<span class="pill pill-outline">推荐</span>
<span class="sr-check"><svg class="ic"><use href="#i-check"/></svg></span>
</div>
</div>
</div></div>
</section>
<!-- ══════════ 状态徽章 ══════════ -->
<section class="section" id="a-badge">
<h2>状态徽章 · .pill 场景</h2>
<p class="desc">徽章复用胶囊原子 <code>.pill</code>(见「胶囊 .pill / .badge」),此处按业务场景分组:<strong>连接态</strong>(色点 + 文字,非 emoji · 铁律 #7)· <strong>套餐</strong> · <strong>节点属性</strong>。镜像 <code>client/lib/widgets/status_pill.dart</code></p>
<div class="pcard"><div class="pcard-h"><h3>连接态</h3><span class="tk">.pill.is-success/-warning/-danger/-neutral</span></div><div class="pcard-b">
<span class="pill is-success"><span class="dot"></span>已连接</span>
<span class="pill is-warning"><span class="dot"></span>连接中</span>
<span class="pill is-danger"><span class="dot"></span>已断开</span>
<span class="pill is-neutral"><span class="dot"></span>未登录</span>
</div></div>
<div class="pcard"><div class="pcard-h"><h3>套餐</h3><span class="tk">.pill-accent · .pill.is-neutral</span></div><div class="pcard-b">
<span class="pill pill-accent">PRO 会员</span>
<span class="pill is-neutral">免费版</span>
</div></div>
<div class="pcard"><div class="pcard-h"><h3>节点属性</h3><span class="tk">.pill-outline · .pill.is-neutral(数据)</span></div><div class="pcard-b">
<span class="pill pill-outline">流媒体优化</span>
<span class="pill pill-outline">P2P</span>
<span class="pill is-neutral">延迟 24ms</span>
</div></div>
</section>
<!-- ══════════ 组件 · 线上对齐 ══════════ -->
<section class="section" id="a-formctl">
<h2>复合输入 · 开关 · 图标框 · Toast</h2>
<p class="desc">对齐线上 <code>pangolin_field.dart</code> / <code>dtoggle</code> / <code>pangolin_toast.dart</code><code>.field-box</code> 复合输入(前置图标 + 裸 input + 后置槽),<code>.toggle</code> 开关,<code>.segswitch</code> 二选一段控开关(支付渠道/币种),<code>.icon-box</code> 图标框,<code>.status-dot</code> 状态点,<code>.toast</code> 轻提示。</p>
<div class="pcard"><div class="pcard-b" style="align-items:flex-start; gap:var(--space-4)">
<label class="field-box" style="width:240px"><svg class="fb-lead"><use href="#i-search"/></svg><input class="fb-input" placeholder="搜索国家或城市"></label>
<label class="field-box" style="width:240px"><svg class="fb-lead"><use href="#i-lock"/></svg><input class="fb-input" type="password" value="123456"><button class="fb-trailing" style="border:none;background:none;cursor:pointer"><svg style="width:16px;height:16px"><use href="#i-eye"/></svg></button></label>
<label class="field-box is-plain" style="width:240px"><svg class="fb-lead"><use href="#i-search"/></svg><input class="fb-input" placeholder="无边框搜索变体"></label>
</div></div>
<div class="pcard"><div class="pcard-b">
<span class="toggle is-on"><i></i></span>
<span class="toggle"><i></i></span>
<span class="icon-box"><svg><use href="#i-smartphone"/></svg></span>
<span class="icon-box is-danger"><svg><use href="#i-trash-2"/></svg></span>
<span style="display:inline-flex;align-items:center;gap:8px"><span class="status-dot is-online"></span>在线</span>
<span style="display:inline-flex;align-items:center;gap:8px"><span class="status-dot is-offline"></span>离线</span>
<span class="toast"><svg><use href="#i-check-circle"/></svg>已复制</span>
</div></div>
<div class="pcard"><div class="pcard-b" style="flex-direction:column; align-items:stretch; gap:var(--space-3); max-width:320px">
<div class="segswitch">
<button class="segswitch-opt is-active"><svg><use href="#i-globe"/></svg>USDT</button>
<button class="segswitch-opt"><svg><use href="#i-credit-card"/></svg>人民币</button>
</div>
<div class="segswitch">
<button class="segswitch-opt">USDT · 加密货币</button>
<button class="segswitch-opt is-active">人民币 · 支付宝</button>
</div>
</div></div>
</section>
<section class="section" id="a-quota">
<h2>额度卡 · 指标卡</h2>
<p class="desc">对齐线上 <code>quota_card.dart</code>(免费版今日额度:倒计时收缩条 + 「免费版」短标签 + 三档阈值;<strong>无绿色「已解锁」态</strong>,线上以倒计时收缩条表达)与统计 <code>.metric</code> 指标瓦片。</p>
<div class="pcard"><div class="pcard-b" style="align-items:flex-start; gap:var(--space-4)">
<div class="quota-card" style="width:280px">
<div class="quota-head"><svg><use href="#i-clock"/></svg><span class="quota-label">今日剩余</span><span class="quota-val">10 分钟</span><span class="quota-tag">免费版</span></div>
<div class="quota-bar"><i style="width:100%"></i></div>
</div>
<div class="quota-card" style="width:280px">
<div class="quota-head"><svg><use href="#i-clock"/></svg><span class="quota-label">剩余</span><span class="quota-val">02:18</span><span class="quota-tag">免费版</span></div>
<div class="quota-bar is-low"><i style="width:23%"></i></div>
</div>
<div class="quota-card is-exhausted" style="width:280px">
<div class="quota-head"><svg><use href="#i-clock"/></svg><span class="quota-label">今日已用完</span><span class="quota-tag">免费版</span></div>
<div class="quota-bar is-exhausted"><i style="width:100%"></i></div>
</div>
</div></div>
<div class="pcard"><div class="pcard-b" style="gap:var(--space-3)">
<div class="metric" style="width:150px"><span class="m-ic"><svg><use href="#i-arrow-down"/></svg></span><div class="m-val">12.4G</div><div class="m-label">本周流量</div></div>
<div class="metric" style="width:150px"><span class="m-ic"><svg><use href="#i-clock"/></svg></span><div class="m-val">6.2h</div><div class="m-label">在线时长</div></div>
</div></div>
</section>
<section class="section" id="a-rows">
<h2>设备行 · 设置行</h2>
<p class="desc">对齐线上 <code>DevicesScreen</code> / <code>settings_page.dart</code><code>.device-row</code>(图标框 + 名 + 最后在线 + 本机/移除/⋯)与 <code>.setting-row</code>(图标框 + 标题 + 副标 + trailingchevron / 开关 / 值)。</p>
<div class="pcard"><div class="pcard-h"><h3>设备管理</h3><span class="tk">.device-row</span></div><div class="pcard-b col">
<div class="card card-flush" style="max-width:460px">
<div class="device-row"><span class="icon-box"><svg><use href="#i-smartphone"/></svg></span><div class="dv-body"><div class="dv-name">iPhone 15</div><div class="dv-sub"><span class="status-dot is-online"></span>当前设备 · 刚刚在线</div></div><span class="dv-trail"><span class="pill is-success"><span class="dot"></span>本机</span></span></div>
<div class="device-row"><span class="icon-box"><svg><use href="#i-laptop"/></svg></span><div class="dv-body"><div class="dv-name">MacBook Pro</div><div class="dv-sub"><span class="status-dot is-offline"></span>最后在线 2 小时前</div></div><span class="dv-trail"><button class="btn btn-icon btn-subtle" aria-label="更多"><svg class="ic" style="width:16px;height:16px"><use href="#i-more-vertical"/></svg></button></span></div>
</div>
</div></div>
<div class="pcard"><div class="pcard-h"><h3>设置</h3><span class="tk">.setting-row</span></div><div class="pcard-b col">
<div class="card card-flush" style="max-width:460px">
<div class="setting-row"><span class="icon-box"><svg><use href="#i-zap"/></svg></span><div class="st-body"><div class="st-title">智能分流</div><div class="st-sub">海外应用走加速,国内直连</div></div><span class="st-trail"><span class="toggle is-on"><i></i></span></span></div>
<div class="setting-row"><span class="icon-box"><svg><use href="#i-globe"/></svg></span><div class="st-body"><div class="st-title">语言</div></div><span class="st-trail"><span class="st-val">简体中文</span></span></div>
<div class="setting-row is-tap"><span class="icon-box"><svg><use href="#i-shield"/></svg></span><div class="st-body"><div class="st-title">协议</div></div><span class="st-trail"><span class="st-val">REALITY</span><svg><use href="#i-chevron-right"/></svg></span></div>
</div>
</div></div>
</section>
<section class="section" id="a-planbn">
<h2>套餐横幅 · 侧栏会员卡</h2>
<p class="desc">对齐线上 <code>_PlanBanner</code>(账户页)与 <code>plan_badge_card.dart</code>(桌面侧栏底部)。免费=surface 卡;<code>.is-pro</code>=clay 渐变。</p>
<div class="pcard"><div class="pcard-b" style="align-items:stretch; gap:var(--space-4)">
<div class="plan-banner" style="width:300px">
<div class="pbn-row"><span class="pbn-badge"><svg><use href="#i-gift"/></svg></span><div style="flex:1"><div class="pbn-name">免费版</div><div class="pbn-meta">注册享 7 天免费试用</div></div><button class="btn btn-primary"><svg><use href="#i-crown"/></svg>升级</button></div>
</div>
<div class="plan-banner is-pro" style="width:300px">
<div class="pbn-row"><span class="pbn-badge"><svg><use href="#i-crown"/></svg></span><div style="flex:1"><div class="pbn-name">PRO 会员</div><div class="pbn-meta">有效期至 2027-07-11</div></div><button class="btn btn-primary">续费</button></div>
</div>
</div></div>
<div class="pcard"><div class="pcard-h"><h3>侧栏会员卡</h3><span class="tk">.plan-badge</span></div><div class="pcard-b">
<div class="plan-badge is-active" style="width:200px"><span class="plb-crown"><svg><use href="#i-crown"/></svg></span><div class="plb-body"><span class="plb-name">PRO 会员</span><span class="plb-sub">至 2027-07-11</span></div><svg class="plb-chev"><use href="#i-chevron-right"/></svg></div>
</div></div>
</section>
<section class="section" id="a-appchrome">
<h2>更新条 · 底部 Tab · 侧栏项</h2>
<p class="desc">app-chrome 组件。<code>.update-banner</code>jiu 式更新顶部横条,对齐 <code>UpdateBanner</code>)、<code>.tabbar</code>/<code>.tab</code>(移动底部 4-Tab,对齐 <code>bottom_tab_bar.dart</code>)、<code>.nav-item</code>(桌面/iPad 侧栏项,对齐 <code>nav_sidebar.dart</code>)。</p>
<div class="pcard"><div class="pcard-b col" style="padding:0">
<div class="update-banner"><svg class="ub-ic"><use href="#i-zap"/></svg><span class="ub-title">发现新版本 v1.1.0,建议更新</span><button class="ub-cta">立即更新</button><button class="ub-close"><svg><use href="#i-x"/></svg></button></div>
</div></div>
<div class="pcard"><div class="pcard-b col" style="padding:0">
<div class="tabbar">
<button class="tab is-active"><svg><use href="#i-power"/></svg>连接</button>
<button class="tab"><svg><use href="#i-globe"/></svg>节点</button>
<button class="tab"><svg><use href="#i-chart-no-axes-column"/></svg>统计</button>
<button class="tab"><svg><use href="#i-user"/></svg>我的</button>
</div>
</div></div>
<div class="pcard"><div class="pcard-b col">
<div style="max-width:220px; display:flex; flex-direction:column; gap:var(--space-1)">
<div class="nav-item is-active"><svg><use href="#i-power"/></svg>连接</div>
<div class="nav-item"><svg><use href="#i-globe"/></svg>节点</div>
<div class="nav-item"><svg><use href="#i-chart-no-axes-column"/></svg>统计</div>
<div class="nav-item"><svg><use href="#i-settings"/></svg>设置</div>
<div class="nav-item"><svg><use href="#i-message-circle"/></svg>联系</div>
</div>
</div></div>
</section>
<!-- ══════════ 购买 Purchase ══════════ -->
<section class="section" id="a-plan">
<h2>套餐卡 · .plan-card</h2>
<p class="desc">购买套餐档位卡。常规档 surface 底;<code>.is-featured</code> 走 clay 渐变高亮(年付/最优惠),内含反色 CTA,顶部可挂 <code>.plan-pop</code>「最受欢迎」浮标。镜像 <code>client/lib/widgets/plan_card.dart</code>。金额仅展示,扣款以 pay 服务为准。</p>
<div class="pcard"><div class="pcard-b" style="align-items:stretch; gap:var(--space-4)">
<div class="plan-card" style="width:230px">
<div class="plan-name">按月</div>
<div class="plan-price-row"><span class="plan-price">¥29.99</span><span class="plan-per">/ 月</span></div>
<div class="plan-feats">
<div class="plan-feat"><svg><use href="#i-check"/></svg>不限时长 · 不限流量</div>
<div class="plan-feat"><svg><use href="#i-check"/></svg>80+ 全球加速线路</div>
<div class="plan-feat"><svg><use href="#i-check"/></svg>5 台设备同时在线</div>
</div>
<button class="btn btn-primary btn-block">立即购买</button>
</div>
<div class="plan-card is-featured" style="width:230px">
<span class="plan-pop">最受欢迎</span>
<div class="plan-name">按年</div>
<div class="plan-price-row"><span class="plan-price">¥199.99</span><span class="plan-per">/ 年 · ¥16.7/月</span></div>
<div class="plan-feats">
<div class="plan-feat"><svg><use href="#i-check"/></svg>不限时长 · 不限流量</div>
<div class="plan-feat"><svg><use href="#i-check"/></svg>80+ 全球加速线路</div>
<div class="plan-feat"><svg><use href="#i-check"/></svg>5 台设备同时在线</div>
</div>
<button class="btn btn-primary btn-block">立即购买</button>
</div>
</div></div>
</section>
<section class="section" id="a-paym">
<h2>支付方式 · .pay-method</h2>
<p class="desc">底部弹层选择支付渠道,一行 = leading 图标 + 标题 + trailing chevron。资金外流(拉起支付宝 / 展示加密地址),<strong>App 内无卡号录入表单</strong>(设计铁律 #10)。生产渠道:哪吒聚合(支付宝)+ 加密货币 USDT。</p>
<div class="pcard"><div class="pcard-b col">
<div class="card card-flush" style="max-width:360px; padding:var(--space-2)">
<button class="pay-method"><svg class="pm-ic"><use href="#i-credit-card"/></svg><span class="pm-title">支付宝</span><svg class="pm-chev"><use href="#i-chevron-right"/></svg></button>
<button class="pay-method"><svg class="pm-ic"><use href="#i-globe"/></svg><span class="pm-title">加密货币 · USDT (TRC20)</span><svg class="pm-chev"><use href="#i-chevron-right"/></svg></button>
</div>
</div></div>
</section>
<section class="section" id="a-kv">
<h2>明细行 · .kv-row</h2>
<p class="desc">可复制键值行,用于加密支付态展示「网络 / 收款地址 / 精确金额」。值用等宽字(<code>--font-mono</code> + tabular nums),右侧复制按钮。</p>
<div class="pcard"><div class="pcard-b col">
<div class="card" style="max-width:420px">
<div class="kv-row"><span class="kv-label">网络</span><span class="kv-val">USDT · TRC20</span><button class="kv-copy"><svg><use href="#i-copy"/></svg></button></div>
<div class="kv-row"><span class="kv-label">收款地址</span><span class="kv-val">TB1e7q1333iuLMLc2iQaoaqeuDF2U7cxan</span><button class="kv-copy"><svg><use href="#i-copy"/></svg></button></div>
<div class="kv-row"><span class="kv-label">精确金额</span><span class="kv-val">4.990001</span><button class="kv-copy"><svg><use href="#i-copy"/></svg></button></div>
</div>
</div></div>
</section>
<section class="section" id="a-result">
<h2>结果态 · .result</h2>
<p class="desc">支付终态:居中大图标 + 标题 + 说明。成功用 <code>--success</code>,失败加 <code>.is-fail</code><code>--danger</code></p>
<div class="pcard"><div class="pcard-b" style="gap:var(--space-6)">
<div class="result" style="width:280px">
<div class="result-icon"><svg><use href="#i-check-circle"/></svg></div>
<div class="result-title">支付成功</div>
<div class="result-sub">有效期至 2027-07-11</div>
</div>
<div class="result is-fail" style="width:280px">
<div class="result-icon"><svg><use href="#i-alert-triangle"/></svg></div>
<div class="result-title">支付失败</div>
<div class="result-sub">订单已超时,请重试</div>
</div>
</div></div>
</section>
<!-- ══════════ 图标 ══════════ -->
<section class="section" id="icons">
<h2>Lucide 图标库 <span class="pill pill-outline count-pill" id="iconCount"></span></h2>
<p class="desc">细线条 · 2px stroke · 圆角端点。sprite 单源 <code>icons.js</code>,用法 <code>&lt;svg class="ic"&gt;&lt;use href="#i-&lt;name&gt;"/&gt;&lt;/svg&gt;</code></p>
<div class="pcard"><div class="pcard-b"><div class="icon-grid" id="iconGrid"></div></div></div>
</section>
</main>
</div>
<script>
/* ── 主题切换(light / dark),持久化 localStorage ── */
function applyTheme(t){
if(t==='dark'){ document.documentElement.dataset.theme='dark'; }
else { delete document.documentElement.dataset.theme; }
document.getElementById('themeIcon').setAttribute('href', t==='dark' ? '#i-moon' : '#i-sun');
document.getElementById('themeLabel').textContent = t==='dark' ? '深色' : '浅色';
localStorage.setItem('pangolin-ds-theme', t);
renderSwatches();
}
document.getElementById('themeBtn').onclick = () => {
const cur = document.documentElement.dataset.theme==='dark' ? 'dark' : 'light';
applyTheme(cur==='dark' ? 'light' : 'dark');
};
/* ── 色板:读实际 CSS 变量(换主题刷新色值文本) ── */
function renderSwatches(){
const cs = getComputedStyle(document.documentElement);
document.querySelectorAll('[data-swatches]').forEach(grid=>{
grid.innerHTML = grid.dataset.swatches.split(',').map(tok=>{
const v = cs.getPropertyValue(tok).trim();
return `<div class="sw"><div class="band" style="background:var(${tok})"></div>`+
`<div class="m"><div class="n">${tok.replace('--','')}</div><div class="v">${v||'—'}</div></div></div>`;
}).join('');
});
}
/* ── 图标库:遍历 sprite 全量渲染 ── */
function renderIcons(){
const map = window.PANGOLIN_ICONS || {};
const names = Object.keys(map);
document.getElementById('iconCount').textContent = names.length + ' 个';
document.getElementById('iconGrid').innerHTML = names.map(n=>
`<div class="icell"><svg class="ic"><use href="#i-${n}"/></svg><span>${n}</span></div>`
).join('');
}
/* ── 语言下拉演示:点触发展开 / 收起 ── */
(function(){
const trigger = document.getElementById('langTrigger');
const sel = document.getElementById('langselDemo');
const menu = document.getElementById('langMenu');
sel.classList.add('is-open');
trigger.onclick = (e)=>{
e.stopPropagation();
const open = trigger.getAttribute('aria-expanded')==='true';
trigger.setAttribute('aria-expanded', String(!open));
sel.classList.toggle('is-open', !open);
menu.style.display = open ? 'none' : 'flex';
};
menu.querySelectorAll('.menu-item').forEach(mi=>{
mi.onclick = ()=>{
menu.querySelectorAll('.menu-item').forEach(x=>{ x.classList.remove('is-selected'); x.removeAttribute('aria-selected'); });
mi.classList.add('is-selected'); mi.setAttribute('aria-selected','true');
trigger.childNodes[0].nodeValue = mi.textContent + ' ';
};
});
})();
/* ── 导航 scrollspy ── */
const navLinks=[...document.querySelectorAll('.dnav')];
navLinks.forEach(a=>a.onclick=(e)=>{ if(!a.dataset.s) return; /* 外链(如屏预览)正常跳转 */ e.preventDefault(); const el=document.getElementById(a.dataset.s); if(el) el.scrollIntoView({behavior:'smooth',block:'start'}); });
const obs=new IntersectionObserver(es=>{ es.forEach(en=>{ if(en.isIntersecting){ const id=en.target.id; navLinks.forEach(a=>a.classList.toggle('on',a.dataset.s===id)); } }); },{rootMargin:'-70px 0px -75% 0px'});
document.querySelectorAll('.section').forEach(s=>obs.observe(s));
/* ── 侧栏:收起 + 拖拽改宽(持久化 localStorage ── */
(function(){
const doc = document.querySelector('.doc');
const nav = document.querySelector('.doc-nav');
const handle = document.getElementById('navResize');
const toggle = document.getElementById('navToggle');
if(!doc || !nav || !handle || !toggle) return;
const MIN = 180, MAX = 460, DEF = 238;
let curW = parseInt(localStorage.getItem('pangolin-ds-navw') || '', 10);
if (!(curW >= MIN && curW <= MAX)) curW = DEF;
let collapsed = localStorage.getItem('pangolin-ds-navcollapsed') === '1';
function apply(){
if (collapsed) { doc.classList.add('nav-collapsed'); nav.style.width = '0px'; }
else { doc.classList.remove('nav-collapsed'); nav.style.width = curW + 'px'; }
}
apply();
// 收起 / 展开
toggle.onclick = () => {
collapsed = !collapsed;
localStorage.setItem('pangolin-ds-navcollapsed', collapsed ? '1' : '0');
apply();
};
// 拖拽改宽(纯 JS 内联宽度,避免自定义 CSS 变量触发闸误报)
let dragging = false;
handle.addEventListener('mousedown', (e) => {
if (collapsed) return;
dragging = true; handle.classList.add('dragging'); document.body.classList.add('nav-dragging');
e.preventDefault();
});
window.addEventListener('mousemove', (e) => {
if (!dragging) return;
const rect = nav.getBoundingClientRect();
curW = Math.max(MIN, Math.min(MAX, e.clientX - rect.left));
nav.style.width = curW + 'px';
});
window.addEventListener('mouseup', () => {
if (!dragging) return;
dragging = false; handle.classList.remove('dragging'); document.body.classList.remove('nav-dragging');
localStorage.setItem('pangolin-ds-navw', curW);
});
})();
/* ── initsprite 注入可能在 DOMContentLoaded,稍等确保 PANGOLIN_ICONS 就绪) ── */
function boot(){
applyTheme(localStorage.getItem('pangolin-ds-theme') || 'light');
renderIcons();
}
if(document.readyState!=='loading') boot(); else document.addEventListener('DOMContentLoaded', boot);
</script>
</body>
</html>
</content>
</invoke>