diff --git a/frontend/index.html b/frontend/index.html
index 3180a5fb..c198afdc 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -4,6 +4,9 @@
+
+
+
Sub2API - AI API Gateway
diff --git a/frontend/src/assets/puro.css b/frontend/src/assets/puro.css
new file mode 100644
index 00000000..96c11980
--- /dev/null
+++ b/frontend/src/assets/puro.css
@@ -0,0 +1,726 @@
+/* ==========================================================================
+ PURO AI — Design System
+ Shared tokens + primitive styles used across every page.
+ --------------------------------------------------------------------------
+ Usage:
+ ========================================================================== */
+
+*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
+
+:root {
+ /* Surfaces */
+ --bg-0: #0a0e1a; /* page */
+ --bg-1: #0f172a; /* raised */
+ --bg-2: #111827; /* card alt */
+ --bg-code: #020617; /* code canvas */
+
+ /* Borders */
+ --border: #1e293b;
+ --border-2: #334155;
+ --border-3: #475569;
+
+ /* Text */
+ --text-0: #f8fafc; /* primary */
+ --text-1: #cbd5e1; /* body */
+ --text-2: #94a3b8; /* muted */
+ --text-3: #64748b; /* hint */
+
+ /* Accents */
+ --cyan: #22d3ee;
+ --cyan-2: #67e8f9;
+ --cyan-dim: #0891b2;
+ --purple: #a855f7;
+ --amber: #fbbf24;
+ --green: #34d399;
+ --red: #f87171;
+ --orange: #fb923c;
+
+ /* Provider brand dots */
+ --p-claude: #d97757;
+ --p-gpt: #10a37f;
+ --p-gemini: #4285f4;
+ --p-codex: #f0a030;
+
+ /* Radius */
+ --r-sm: 6px;
+ --r-md: 8px;
+ --r-lg: 12px;
+ --r-xl: 16px;
+
+ /* Shadow */
+ --shadow-lg: 0 30px 60px -30px rgba(0,0,0,0.6);
+ --shadow-xl: 0 40px 80px -40px rgba(0,0,0,0.8);
+
+ /* Typography */
+ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+ --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
+}
+
+html, body {
+ background: var(--bg-0);
+ color: var(--text-0);
+ font-family: var(--font-sans);
+ font-feature-settings: "cv11", "ss01", "ss03";
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+ line-height: 1.5;
+}
+
+body { overflow-x: hidden; }
+
+a { color: inherit; text-decoration: none; }
+button { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; }
+
+/* scrollbar — subtle */
+::-webkit-scrollbar { width: 10px; height: 10px; }
+::-webkit-scrollbar-track { background: transparent; }
+::-webkit-scrollbar-thumb { background: var(--border-2); border-radius: 6px; }
+::-webkit-scrollbar-thumb:hover { background: var(--border-3); }
+
+.mono { font-family: var(--font-mono); }
+
+/* ==========================================================================
+ BACKGROUND EFFECTS
+ ========================================================================== */
+.bg-glow {
+ position: fixed;
+ inset: 0;
+ pointer-events: none;
+ z-index: 0;
+ overflow: hidden;
+}
+.bg-glow::before,
+.bg-glow::after {
+ content: "";
+ position: absolute;
+ width: 900px;
+ height: 900px;
+ border-radius: 50%;
+ filter: blur(120px);
+ opacity: 0.35;
+}
+.bg-glow::before {
+ background: radial-gradient(circle, #22d3ee 0%, transparent 60%);
+ top: -300px;
+ left: -200px;
+}
+.bg-glow::after {
+ background: radial-gradient(circle, #a855f7 0%, transparent 60%);
+ top: 200px;
+ right: -300px;
+ opacity: 0.25;
+}
+.bg-glow.soft::before, .bg-glow.soft::after { opacity: 0.15; }
+
+.grain {
+ position: fixed;
+ inset: 0;
+ pointer-events: none;
+ z-index: 1;
+ opacity: 0.4;
+ mix-blend-mode: overlay;
+ background-image: url("data:image/svg+xml;utf8,");
+}
+
+.container {
+ max-width: 1100px;
+ margin: 0 auto;
+ padding: 0 32px;
+ position: relative;
+ z-index: 2;
+}
+.container-wide { max-width: 1280px; }
+.container-narrow { max-width: 860px; }
+
+/* ==========================================================================
+ NAV
+ ========================================================================== */
+.nav {
+ position: sticky;
+ top: 0;
+ z-index: 50;
+ backdrop-filter: blur(16px);
+ background: rgba(10, 14, 26, 0.72);
+ border-bottom: 1px solid var(--border);
+}
+.nav-inner {
+ display: flex;
+ align-items: center;
+ height: 64px;
+ gap: 48px;
+}
+.brand {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-weight: 700;
+ font-size: 15px;
+ letter-spacing: 0.02em;
+}
+.hex {
+ width: 22px;
+ height: 22px;
+ color: var(--cyan);
+}
+.nav-links {
+ display: flex;
+ gap: 28px;
+ font-size: 14px;
+ color: var(--text-2);
+}
+.nav-links a { transition: color .15s; }
+.nav-links a:hover, .nav-links a.active { color: var(--text-0); }
+.nav-links .disabled { color: var(--text-3); cursor: not-allowed; display: inline-flex; align-items: center; gap: 6px; }
+.nav-links .disabled::after {
+ content: "即将推出";
+ font-size: 10px;
+ padding: 2px 6px;
+ border: 1px solid var(--border-2);
+ border-radius: 4px;
+ color: var(--text-3);
+}
+.nav-cta {
+ margin-left: auto;
+ display: flex;
+ gap: 10px;
+ align-items: center;
+}
+
+/* ==========================================================================
+ BUTTONS
+ ========================================================================== */
+.btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 6px;
+ padding: 8px 14px;
+ font-size: 13px;
+ font-weight: 500;
+ border-radius: var(--r-md);
+ transition: all .15s;
+ white-space: nowrap;
+ border: 1px solid transparent;
+}
+.btn-primary {
+ background: var(--cyan);
+ color: #042f2e;
+ font-weight: 600;
+}
+.btn-primary:hover { background: var(--cyan-2); }
+.btn-primary:active { transform: translateY(1px); }
+.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
+
+.btn-ghost {
+ border-color: var(--border-2);
+ color: var(--text-1);
+}
+.btn-ghost:hover { border-color: var(--border-3); color: var(--text-0); background: rgba(255,255,255,0.02); }
+
+.btn-subtle {
+ background: rgba(255,255,255,0.04);
+ color: var(--text-1);
+ border-color: transparent;
+}
+.btn-subtle:hover { background: rgba(255,255,255,0.08); color: var(--text-0); }
+
+.btn-danger {
+ background: rgba(248, 113, 113, 0.1);
+ color: var(--red);
+ border-color: rgba(248, 113, 113, 0.25);
+}
+.btn-danger:hover { background: rgba(248, 113, 113, 0.15); border-color: rgba(248, 113, 113, 0.4); }
+
+.btn-lg { padding: 12px 20px; font-size: 14px; }
+.btn-sm { padding: 5px 10px; font-size: 12px; }
+.btn-icon { padding: 7px; aspect-ratio: 1; }
+
+.btn .spinner {
+ width: 14px; height: 14px;
+ border: 2px solid rgba(0,0,0,0.2);
+ border-top-color: currentColor;
+ border-radius: 50%;
+ animation: spin .7s linear infinite;
+ display: none;
+}
+.btn.loading .spinner { display: inline-block; }
+.btn.loading .label { opacity: 0.5; }
+@keyframes spin { to { transform: rotate(360deg); } }
+
+/* ==========================================================================
+ BADGES / PILLS / CHIPS
+ ========================================================================== */
+.badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 2px 8px;
+ border-radius: 100px;
+ font-size: 11px;
+ font-weight: 600;
+ letter-spacing: 0.02em;
+ background: rgba(34, 211, 238, 0.1);
+ color: var(--cyan);
+}
+.badge.amber { background: rgba(251, 191, 36, 0.12); color: var(--amber); }
+.badge.purple { background: rgba(168, 85, 247, 0.12); color: var(--purple); }
+.badge.green { background: rgba(52, 211, 153, 0.12); color: var(--green); }
+.badge.red { background: rgba(248, 113, 113, 0.12); color: var(--red); }
+.badge.muted { background: rgba(255, 255, 255, 0.04); color: var(--text-2); border: 1px solid var(--border); }
+
+.pill {
+ display: inline-block;
+ padding: 2px 8px;
+ border-radius: var(--r-sm);
+ background: rgba(255,255,255,0.04);
+ border: 1px solid var(--border);
+ font-family: var(--font-mono);
+ font-size: 12px;
+ color: var(--text-0);
+}
+
+.chip {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 4px 10px;
+ border-radius: 100px;
+ background: rgba(15, 23, 42, 0.6);
+ border: 1px solid var(--border);
+ font-size: 12px;
+ color: var(--text-1);
+ font-family: var(--font-mono);
+}
+.chip .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--green); }
+.chip.claude .dot { background: var(--p-claude); }
+.chip.gpt .dot { background: var(--p-gpt); }
+.chip.gemini .dot { background: var(--p-gemini); }
+.chip.codex .dot { background: var(--p-codex); }
+
+.dot-sep { width: 4px; height: 4px; border-radius: 50%; background: var(--text-3); display: inline-block; }
+
+/* status chip (tiny dot absolute-positioned) */
+.status-chip {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--green);
+ box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.15);
+ display: inline-block;
+}
+.status-chip.dim { background: var(--text-3); box-shadow: none; }
+.status-chip.amber { background: var(--amber); box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.15); }
+.status-chip.red { background: var(--red); box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.15); }
+
+/* ==========================================================================
+ CARDS / SURFACES
+ ========================================================================== */
+.card {
+ background: rgba(15, 23, 42, 0.6);
+ border: 1px solid var(--border);
+ border-radius: var(--r-lg);
+ padding: 24px;
+}
+.card-raised {
+ background: var(--bg-1);
+ border: 1px solid var(--border);
+ border-radius: var(--r-lg);
+}
+.card-interactive {
+ transition: all .2s;
+ cursor: pointer;
+}
+.card-interactive:hover {
+ border-color: var(--border-2);
+ background: rgba(15, 23, 42, 0.85);
+ transform: translateY(-2px);
+}
+
+.divider { height: 1px; background: var(--border); margin: 24px 0; border: 0; }
+.divider-dashed { border: 0; border-top: 1px dashed var(--border); margin: 20px 0; }
+
+/* ==========================================================================
+ FORMS
+ ========================================================================== */
+.field { margin-bottom: 18px; }
+.field-label {
+ display: block;
+ font-size: 12px;
+ font-weight: 500;
+ color: var(--text-1);
+ margin-bottom: 8px;
+}
+.field-hint {
+ font-size: 12px;
+ color: var(--text-3);
+ margin-top: 6px;
+}
+.field-error {
+ font-size: 12px;
+ color: var(--red);
+ margin-top: 6px;
+}
+
+.input-wrap { position: relative; }
+.input-wrap .icon {
+ position: absolute;
+ left: 14px;
+ top: 50%;
+ transform: translateY(-50%);
+ color: var(--text-3);
+ pointer-events: none;
+ display: inline-flex;
+}
+.input {
+ width: 100%;
+ height: 42px;
+ padding: 0 14px;
+ background: rgba(15, 23, 42, 0.6);
+ border: 1px solid var(--border-2);
+ border-radius: var(--r-md);
+ color: var(--text-0);
+ font-size: 14px;
+ font-family: inherit;
+ outline: none;
+ transition: all .15s;
+}
+.input.with-icon { padding-left: 40px; }
+.input::placeholder { color: var(--text-3); }
+.input:hover { border-color: var(--border-3); }
+.input:focus {
+ border-color: var(--cyan);
+ box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.12);
+ background: rgba(15, 23, 42, 0.9);
+}
+.input.ok { border-color: rgba(52, 211, 153, 0.4); }
+.input.ok:focus { box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.12); }
+.input.error { border-color: var(--red); }
+.input.error:focus { box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.12); }
+
+textarea.input { height: auto; padding: 12px 14px; resize: vertical; line-height: 1.5; }
+
+select.input {
+ appearance: none;
+ background-image: url("data:image/svg+xml;utf8,");
+ background-repeat: no-repeat;
+ background-position: right 14px center;
+ padding-right: 36px;
+}
+
+/* checkbox */
+.check {
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+ cursor: pointer;
+ user-select: none;
+ font-size: 13px;
+ color: var(--text-1);
+}
+.check input { display: none; }
+.check .box {
+ width: 16px; height: 16px;
+ border: 1px solid var(--border-2);
+ border-radius: 4px;
+ background: var(--bg-1);
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ transition: all .15s;
+ flex-shrink: 0;
+}
+.check input:checked + .box {
+ background: var(--cyan);
+ border-color: var(--cyan);
+}
+.check input:checked + .box::after {
+ content: "✓";
+ color: #042f2e;
+ font-size: 11px;
+ font-weight: 700;
+}
+
+/* ==========================================================================
+ SECTION HEADINGS
+ ========================================================================== */
+.section-kicker {
+ font-family: var(--font-mono);
+ font-size: 12px;
+ color: var(--cyan);
+ letter-spacing: 0.15em;
+ text-transform: uppercase;
+ margin-bottom: 12px;
+}
+.section-title {
+ font-size: clamp(28px, 3.5vw, 40px);
+ font-weight: 700;
+ letter-spacing: -0.02em;
+ line-height: 1.15;
+ margin-bottom: 16px;
+}
+.section-sub {
+ color: var(--text-2);
+ font-size: 16px;
+ line-height: 1.6;
+}
+
+/* ==========================================================================
+ TABLES
+ ========================================================================== */
+.tbl {
+ width: 100%;
+ font-size: 13px;
+ border-collapse: collapse;
+}
+.tbl th {
+ text-align: left;
+ color: var(--text-3);
+ font-weight: 500;
+ padding: 12px 14px;
+ border-bottom: 1px solid var(--border);
+ text-transform: uppercase;
+ font-size: 10px;
+ letter-spacing: 0.1em;
+}
+.tbl td {
+ padding: 14px;
+ border-bottom: 1px solid rgba(30, 41, 59, 0.5);
+ color: var(--text-1);
+}
+.tbl tr:last-child td { border-bottom: none; }
+.tbl tr:hover td { background: rgba(15, 23, 42, 0.4); }
+.tbl td.mono, .tbl th.mono { font-family: var(--font-mono); }
+
+/* ==========================================================================
+ CODE BLOCKS
+ ========================================================================== */
+.code-frame {
+ background: var(--bg-code);
+ border: 1px solid var(--border);
+ border-radius: var(--r-lg);
+ overflow: hidden;
+ box-shadow: var(--shadow-lg);
+}
+.code-head {
+ display: flex;
+ align-items: center;
+ height: 40px;
+ padding: 0 16px;
+ border-bottom: 1px solid var(--border);
+ background: rgba(15, 23, 42, 0.8);
+ gap: 10px;
+}
+.traffic {
+ display: flex;
+ gap: 6px;
+}
+.traffic span {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ background: #475569;
+}
+.code-body {
+ padding: 22px 26px;
+ font-family: var(--font-mono);
+ font-size: 13px;
+ line-height: 1.75;
+ color: var(--text-1);
+ overflow-x: auto;
+}
+.code-body .line { display: flex; gap: 20px; }
+.ln { color: var(--text-3); user-select: none; min-width: 16px; text-align: right; opacity: 0.5; }
+
+/* syntax */
+.kw { color: #c084fc; }
+.str { color: #86efac; }
+.num { color: #fbbf24; }
+.com { color: #64748b; font-style: italic; }
+.fn { color: #22d3ee; }
+.prop{ color: #f0abfc; }
+.var-v { color: #f8fafc; }
+.flag{ color: #fb923c; }
+.bash-prompt { color: var(--cyan); user-select: none; }
+
+/* ==========================================================================
+ PROVIDER-BRAND HELPERS
+ ========================================================================== */
+.provider {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ font-family: var(--font-mono);
+ font-size: 12px;
+}
+.provider .dot { width: 6px; height: 6px; border-radius: 50%; }
+.provider.claude .dot { background: var(--p-claude); }
+.provider.gpt .dot { background: var(--p-gpt); }
+.provider.gemini .dot { background: var(--p-gemini); }
+.provider.codex .dot { background: var(--p-codex); }
+
+/* ==========================================================================
+ UTILITIES
+ ========================================================================== */
+.stack-xs { display: flex; flex-direction: column; gap: 8px; }
+.stack-sm { display: flex; flex-direction: column; gap: 12px; }
+.stack-md { display: flex; flex-direction: column; gap: 20px; }
+.stack-lg { display: flex; flex-direction: column; gap: 32px; }
+
+.row { display: flex; align-items: center; gap: 12px; }
+.row-sm { gap: 8px; }
+.row-lg { gap: 20px; }
+.row-between { justify-content: space-between; }
+.row-center { justify-content: center; }
+.row-wrap { flex-wrap: wrap; }
+
+.flex-1 { flex: 1; }
+.ml-auto { margin-left: auto; }
+.mt-auto { margin-top: auto; }
+
+.text-0 { color: var(--text-0); }
+.text-1 { color: var(--text-1); }
+.text-2 { color: var(--text-2); }
+.text-3 { color: var(--text-3); }
+.text-cyan { color: var(--cyan); }
+.text-purple { color: var(--purple); }
+.text-amber { color: var(--amber); }
+.text-green { color: var(--green); }
+.text-red { color: var(--red); }
+
+.text-xs { font-size: 11px; }
+.text-sm { font-size: 13px; }
+.text-md { font-size: 14px; }
+.text-lg { font-size: 16px; }
+.text-xl { font-size: 20px; }
+.text-2xl { font-size: 28px; }
+.text-3xl { font-size: 36px; }
+
+.fw-400 { font-weight: 400; }
+.fw-500 { font-weight: 500; }
+.fw-600 { font-weight: 600; }
+.fw-700 { font-weight: 700; }
+.fw-800 { font-weight: 800; }
+
+.tabular { font-variant-numeric: tabular-nums; }
+.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+
+/* ==========================================================================
+ APP SHELL (for dashboard-style pages)
+ ========================================================================== */
+.app-shell {
+ display: grid;
+ grid-template-columns: 240px 1fr;
+ min-height: 100vh;
+ position: relative;
+ z-index: 2;
+}
+.app-side {
+ border-right: 1px solid var(--border);
+ background: rgba(2, 6, 23, 0.6);
+ padding: 20px 14px;
+ display: flex;
+ flex-direction: column;
+ gap: 28px;
+ position: sticky;
+ top: 0;
+ height: 100vh;
+ overflow-y: auto;
+}
+.app-side .brand { padding: 6px 10px 14px; }
+.side-group { display: flex; flex-direction: column; gap: 2px; }
+.side-label {
+ font-size: 10px;
+ color: var(--text-3);
+ text-transform: uppercase;
+ letter-spacing: 0.12em;
+ padding: 0 10px 8px;
+ font-family: var(--font-mono);
+}
+.side-item {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 8px 10px;
+ border-radius: var(--r-sm);
+ font-size: 13px;
+ color: var(--text-2);
+ cursor: pointer;
+ transition: all .12s;
+}
+.side-item:hover { color: var(--text-0); background: rgba(255,255,255,0.03); }
+.side-item.active { background: rgba(34, 211, 238, 0.08); color: var(--cyan); }
+.side-item .ico {
+ width: 16px; height: 16px; opacity: 0.8;
+ display: inline-flex; align-items: center; justify-content: center;
+ flex-shrink: 0;
+}
+.side-item .count {
+ margin-left: auto;
+ font-size: 11px;
+ color: var(--text-3);
+ font-family: var(--font-mono);
+}
+.side-item.active .count { color: var(--cyan); }
+
+.app-main {
+ min-width: 0; /* allow grid children to shrink */
+ display: flex;
+ flex-direction: column;
+}
+.app-topbar {
+ height: 60px;
+ border-bottom: 1px solid var(--border);
+ display: flex;
+ align-items: center;
+ padding: 0 32px;
+ gap: 16px;
+ position: sticky;
+ top: 0;
+ z-index: 10;
+ background: rgba(10, 14, 26, 0.75);
+ backdrop-filter: blur(12px);
+}
+.app-topbar h1 {
+ font-size: 18px;
+ font-weight: 600;
+ letter-spacing: -0.01em;
+}
+.app-content {
+ padding: 32px;
+ flex: 1;
+}
+
+/* user avatar pill */
+.avatar {
+ width: 28px; height: 28px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #22d3ee, #a855f7);
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ color: #042f2e;
+ font-weight: 700;
+ font-size: 12px;
+ flex-shrink: 0;
+}
+
+/* ==========================================================================
+ KBD
+ ========================================================================== */
+kbd {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 20px;
+ height: 20px;
+ padding: 0 6px;
+ font-family: var(--font-mono);
+ font-size: 11px;
+ font-weight: 500;
+ color: var(--text-1);
+ background: var(--bg-1);
+ border: 1px solid var(--border-2);
+ border-bottom-width: 2px;
+ border-radius: 4px;
+ line-height: 1;
+}
diff --git a/frontend/src/main.ts b/frontend/src/main.ts
index 68ace885..aa94e14b 100644
--- a/frontend/src/main.ts
+++ b/frontend/src/main.ts
@@ -5,6 +5,7 @@ import router from './router'
import i18n, { initI18n } from './i18n'
import { useAppStore } from '@/stores/app'
import './style.css'
+import './assets/puro.css'
function initThemeClass() {
const savedTheme = localStorage.getItem('theme')
diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js
index 70e3a7ed..ea4c2bc5 100644
--- a/frontend/tailwind.config.js
+++ b/frontend/tailwind.config.js
@@ -46,6 +46,20 @@ export default {
800: '#1e293b',
900: '#0f172a',
950: '#020617'
+ },
+ // PURO AI 设计系统色板(给新页面 Landing/Auth/Docs 用,不影响 admin)
+ puro: {
+ cyan: '#22d3ee',
+ 'cyan-2': '#67e8f9',
+ purple: '#a855f7',
+ amber: '#fbbf24',
+ green: '#34d399',
+ red: '#f87171',
+ // 平台品牌点色
+ claude: '#d97757',
+ gpt: '#10a37f',
+ gemini: '#4285f4',
+ codex: '#f0a030'
}
},
fontFamily: {