/* @ds-bundle: {"format":3,"namespace":"VPNDesignSystem_4c9564","components":[],"sourceHashes":{"ui_kits/desktop/dapp.jsx":"0261ad8c8093","ui_kits/desktop/dflows.jsx":"b52d86fc92ea","ui_kits/desktop/dparts.jsx":"e7fec2d75fc0","ui_kits/desktop/macos-window.jsx":"83e5cb33277e","ui_kits/mobile/flows.jsx":"838173b11d20","ui_kits/mobile/ios-frame.jsx":"39f3a091d97d","ui_kits/mobile/parts.jsx":"44efd184bf6a","ui_kits/mobile/screens.jsx":"cde11b0b1ad6","ui_kits/tablet/tabapp.jsx":"86e2e0f22462","ui_kits/usercenter/ucapp.jsx":"abe00336c077","ui_kits/usercenter/ucparts.jsx":"ba322907d9b7","ui_kits/website/site.js":"47ee2f38bcef"},"inlinedExternals":[],"unexposedExports":[]} */ (() => { const __ds_ns = (window.VPNDesignSystem_4c9564 = window.VPNDesignSystem_4c9564 || {}); const __ds_scope = {}; (__ds_ns.__errors = __ds_ns.__errors || []); // ui_kits/desktop/dapp.jsx try { (() => { /* dapp.jsx — 穿山甲 VPN desktop · window + views (i18n) */ const { useState, useEffect, useRef } = React; function DToggle({ on, onChange }) { return /*#__PURE__*/React.createElement("div", { onClick: onChange, style: { width: 42, height: 25, borderRadius: 999, position: 'relative', cursor: 'pointer', flexShrink: 0, background: on ? 'var(--accent)' : 'var(--border-strong)', transition: 'background 220ms var(--ease-out)' } }, /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', top: 3, left: on ? 20 : 3, width: 19, height: 19, borderRadius: '50%', background: '#fff', boxShadow: 'var(--shadow-sm)', transition: 'left 220ms var(--ease-out)' } })); } function DLangSwitch({ lang, setLang }) { return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', background: 'var(--bg-subtle)', borderRadius: 999, padding: 3, gap: 2 } }, [['zh', '中文'], ['en', 'EN']].map(([v, l]) => /*#__PURE__*/React.createElement("button", { key: v, onClick: () => setLang(v), style: { border: 'none', cursor: 'pointer', borderRadius: 999, padding: '4px 12px', fontFamily: 'var(--font-sans)', fontSize: 12, fontWeight: 700, background: lang === v ? 'var(--accent)' : 'transparent', color: lang === v ? 'var(--fg-on-accent)' : 'var(--fg3)', transition: 'all 140ms var(--ease-out)' } }, l))); } function NavItem({ icon, label, active, onClick }) { return /*#__PURE__*/React.createElement("button", { onClick: onClick, style: { display: 'flex', alignItems: 'center', gap: 11, width: '100%', textAlign: 'left', border: 'none', cursor: 'pointer', background: active ? 'var(--accent-subtle)' : 'transparent', color: active ? 'var(--accent)' : 'var(--fg2)', padding: '9px 12px', borderRadius: 'var(--radius-md)', fontFamily: 'var(--font-sans)', fontSize: 13.5, fontWeight: active ? 600 : 500, transition: 'background-color 140ms var(--ease-out), color 140ms var(--ease-out)' } }, /*#__PURE__*/React.createElement(DIcon, { name: icon, size: 18, stroke: active ? 2.3 : 2, color: active ? 'var(--accent)' : 'var(--fg3)' }), label); } function DConnect({ t, lang, status, onToggle, server, smart, free, mins, adDone, onAd, elapsed }) { const map = { off: { fill: 'var(--sand-100)', fg: 'var(--clay-500)', icon: 'power', cap: t('capOff'), sub: t('subOff'), ring: 'track' }, connecting: { fill: 'var(--accent)', fg: '#fff', icon: 'loader-circle', cap: t('capConnecting'), sub: t('subConnecting'), ring: 'spin' }, on: { fill: 'var(--success)', fg: '#fff', icon: 'shield-check', cap: t('capOn'), sub: t('subOn'), ring: 'full' } }[status]; const fmt = s => `${String(Math.floor(s / 3600)).padStart(2, '0')}:${String(Math.floor(s % 3600 / 60)).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}`; const shadow = status === 'off' ? 'inset 0 0 0 1px var(--sand-200), var(--shadow-md)' : `0 0 0 8px ${status === 'on' ? 'var(--success-subtle)' : 'var(--accent-subtle)'}, var(--shadow-lg)`; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', gap: 24, padding: '10px 40px' } }, /*#__PURE__*/React.createElement("button", { onClick: onToggle, style: { position: 'relative', width: 176, height: 176, borderRadius: '50%', border: 'none', cursor: 'pointer', background: map.fill, color: map.fg, boxShadow: shadow, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 7, transition: 'box-shadow 300ms var(--ease-out), background-color 300ms var(--ease-out)' } }, /*#__PURE__*/React.createElement("svg", { viewBox: "0 0 176 176", style: { position: 'absolute', inset: 0, width: '100%', height: '100%', transformOrigin: 'center', animation: map.ring === 'spin' ? 'pg-spin 1.4s linear infinite' : 'none' } }, map.ring === 'track' && /*#__PURE__*/React.createElement("circle", { cx: "88", cy: "88", r: "81", fill: "none", stroke: "var(--sand-200)", strokeWidth: "3", strokeDasharray: "2 8", strokeLinecap: "round" }), map.ring === 'spin' && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("circle", { cx: "88", cy: "88", r: "81", fill: "none", stroke: "rgba(255,255,255,.3)", strokeWidth: "4" }), /*#__PURE__*/React.createElement("circle", { cx: "88", cy: "88", r: "81", fill: "none", stroke: "#fff", strokeWidth: "4", strokeLinecap: "round", strokeDasharray: "130 380" })), map.ring === 'full' && /*#__PURE__*/React.createElement("circle", { cx: "88", cy: "88", r: "81", fill: "none", stroke: "rgba(255,255,255,.85)", strokeWidth: "4", strokeLinecap: "round" })), /*#__PURE__*/React.createElement(DIcon, { name: map.icon, size: 46, stroke: 1.7, style: status === 'connecting' ? { animation: 'pg-spin 1s linear infinite' } : {} }), status === 'off' && /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 13 } }, t('connectNow')), status === 'connecting' && /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontWeight: 700, fontSize: 13, letterSpacing: '0.08em' } }, "\xB7\xB7\xB7"), status === 'on' && /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontWeight: 600, fontSize: 15 } }, fmt(elapsed))), /*#__PURE__*/React.createElement("div", { style: { textAlign: 'center' } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 22, color: 'var(--fg1)' } }, map.cap), /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, color: 'var(--fg3)', marginTop: 4 } }, map.sub), /*#__PURE__*/React.createElement("div", { style: { display: 'inline-flex', alignItems: 'center', gap: 7, marginTop: 10, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-full)', padding: '6px 14px', fontSize: 12.5, fontWeight: 600, color: 'var(--fg2)' } }, smart && /*#__PURE__*/React.createElement(DIcon, { name: "zap", size: 13, stroke: 2.4, color: "var(--accent)" }), /*#__PURE__*/React.createElement("span", { style: { whiteSpace: 'nowrap' } }, smart ? `${t('smartSelect')} · ` : '', dName(server, lang), " \xB7 ", server.ping, "ms"))), free && /*#__PURE__*/React.createElement("div", { style: { width: 340, background: 'var(--surface)', borderRadius: 'var(--radius-lg)', padding: '12px 14px', boxShadow: 'var(--shadow-sm)', border: '1px solid var(--border)' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 7, marginBottom: 8 } }, /*#__PURE__*/React.createElement(DIcon, { name: "clock", size: 14, stroke: 2.2, color: "var(--accent)" }), /*#__PURE__*/React.createElement("span", { style: { fontSize: 12, fontWeight: 600, color: 'var(--fg2)' } }, t('quotaToday')), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 13.5, fontWeight: 600, color: 'var(--fg1)', whiteSpace: 'nowrap' } }, mins, " ", t('minutes')), /*#__PURE__*/React.createElement("span", { style: { marginLeft: 'auto', fontSize: 10.5, fontWeight: 600, color: 'var(--fg3)', background: 'var(--bg-subtle)', padding: '3px 9px', borderRadius: 'var(--radius-full)', whiteSpace: 'nowrap' } }, t('quotaFree'))), /*#__PURE__*/React.createElement("div", { style: { height: 6, background: 'var(--bg-subtle)', borderRadius: 3, overflow: 'hidden', marginBottom: 10 } }, /*#__PURE__*/React.createElement("div", { style: { width: `${Math.min(100, mins / 10 * 100)}%`, height: '100%', background: mins <= 3 ? 'var(--warning)' : 'var(--accent)', borderRadius: 3 } })), adDone ? /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, color: 'var(--success)', fontWeight: 700, fontSize: 13, padding: '8px' } }, /*#__PURE__*/React.createElement(DIcon, { name: "check-circle", size: 15, stroke: 2.2, color: "var(--success)" }), t('adUnlocked')) : /*#__PURE__*/React.createElement("button", { onClick: onAd, style: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, width: '100%', border: '1.5px solid var(--accent-border)', background: 'var(--accent-subtle)', color: 'var(--accent)', fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 13, padding: '8px', borderRadius: 'var(--radius-full)', cursor: 'pointer' } }, /*#__PURE__*/React.createElement(DIcon, { name: "play-circle", size: 15, stroke: 2.2 }), t('watchAd'))), status === 'on' && /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 10 } }, [['arrow-down', '86.4', 'Mb/s'], ['arrow-up', '12.1', 'Mb/s'], ['zap', String(server.ping), 'ms']].map(([ic, v, u]) => /*#__PURE__*/React.createElement("div", { key: ic, style: { display: 'flex', alignItems: 'center', gap: 7, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-md)', padding: '8px 14px', boxShadow: 'var(--shadow-sm)' } }, /*#__PURE__*/React.createElement(DIcon, { name: ic, size: 15, stroke: 2.2, color: "var(--accent)" }), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 14, color: 'var(--fg1)' } }, v, /*#__PURE__*/React.createElement("span", { style: { fontSize: 10, color: 'var(--fg3)' } }, " ", u)))))); } function DServers({ t, lang, current, onPick }) { const [q, setQ] = useState(''); const list = DSERVERS.filter(s => (s.name + s.en).toLowerCase().includes(q.toLowerCase())); const smartActive = current === 'AUTO'; return /*#__PURE__*/React.createElement("div", { style: { padding: '4px 28px 24px' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 9, background: 'var(--bg-subtle)', borderRadius: 'var(--radius-md)', padding: '9px 13px', marginBottom: 16, maxWidth: 340 } }, /*#__PURE__*/React.createElement(DIcon, { name: "search", size: 17, color: "var(--fg3)" }), /*#__PURE__*/React.createElement("input", { value: q, onChange: e => setQ(e.target.value), placeholder: t('search'), style: { border: 'none', background: 'transparent', outline: 'none', flex: 1, fontFamily: 'var(--font-sans)', fontSize: 13.5, color: 'var(--fg1)' } })), /*#__PURE__*/React.createElement("button", { onClick: () => onPick('AUTO'), style: { display: 'flex', alignItems: 'center', gap: 12, width: '100%', textAlign: 'left', cursor: 'pointer', background: 'var(--accent-subtle)', border: `1.5px solid ${smartActive ? 'var(--accent)' : 'var(--accent-border)'}`, borderRadius: 'var(--radius-xl)', padding: '14px', boxShadow: smartActive ? 'var(--shadow-md)' : 'var(--shadow-sm)', marginBottom: 10 } }, /*#__PURE__*/React.createElement("div", { style: { width: 38, height: 38, borderRadius: 'var(--radius-md)', background: 'linear-gradient(150deg,var(--clay-500),var(--clay-700))', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(DIcon, { name: "zap", size: 18, stroke: 2.2, color: "#fff" })), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 8 } }, /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-sans)', fontSize: 14.5, fontWeight: 700, color: 'var(--fg1)' } }, t('smartSelect')), /*#__PURE__*/React.createElement("span", { style: { fontSize: 10, fontWeight: 700, color: '#fff', background: 'var(--accent)', padding: '2px 8px', borderRadius: 999, letterSpacing: '0.04em' } }, t('recommended'))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11.5, color: 'var(--fg2)', marginTop: 3 } }, t('smartSub'))), smartActive && /*#__PURE__*/React.createElement(DIcon, { name: "check", size: 18, color: "var(--accent)", stroke: 2.6 })), /*#__PURE__*/React.createElement("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 } }, list.map(s => { const active = s.code === current; return /*#__PURE__*/React.createElement("button", { key: s.code, onClick: () => onPick(s.code), style: { display: 'flex', alignItems: 'center', gap: 12, textAlign: 'left', cursor: 'pointer', background: active ? 'var(--accent-subtle)' : 'var(--surface)', border: `1.5px solid ${active ? 'var(--accent-border)' : 'var(--border)'}`, borderRadius: 'var(--radius-lg)', padding: '12px 14px', boxShadow: 'var(--shadow-sm)' } }, /*#__PURE__*/React.createElement(DCC, { code: s.code, active: active }), /*#__PURE__*/React.createElement("div", { style: { flex: 1, minWidth: 0 } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-sans)', fontSize: 14, fontWeight: 600, color: 'var(--fg1)' } }, dName(s, lang)), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11.5, color: 'var(--fg3)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } }, dSub(s, lang))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 5 } }, /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 11.5, color: 'var(--fg2)' } }, s.ping, "ms"), /*#__PURE__*/React.createElement(DSignal, { ping: s.ping })), active && /*#__PURE__*/React.createElement(DIcon, { name: "check", size: 17, color: "var(--accent)" })); }))); } function DStats({ t, lang }) { const vals = [2.1, 3.4, 1.8, 4.6, 5.2, 6.1, 3.0]; const labels = t('days'); const max = 6.1; return /*#__PURE__*/React.createElement("div", { style: { padding: '8px 32px 24px' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 14, marginBottom: 22 } }, [[t('trafficMonth'), '42.6 GB'], [t('avgPing'), '29 ms'], [t('durMonth'), '86.4 h']].map(([l, v]) => /*#__PURE__*/React.createElement("div", { key: l, style: { flex: 1, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', padding: '16px 18px', boxShadow: 'var(--shadow-sm)' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)', fontWeight: 600 } }, l), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 24, fontWeight: 500, color: 'var(--fg1)', marginTop: 6 } }, v)))), /*#__PURE__*/React.createElement("div", { style: { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', padding: '18px 20px', boxShadow: 'var(--shadow-sm)' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, fontWeight: 600, color: 'var(--fg1)', marginBottom: 18 } }, t('weekTraffic')), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'flex-end', gap: 18, height: 120 } }, vals.map((v, i) => /*#__PURE__*/React.createElement("div", { key: i, style: { flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg3)' } }, v), /*#__PURE__*/React.createElement("div", { style: { width: '100%', maxWidth: 34, height: `${v / max * 86}px`, background: 'var(--accent)', borderRadius: '6px 6px 0 0', opacity: 0.85 } }), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11, color: 'var(--fg3)' } }, labels[i])))))); } function DSettings({ t, lang, setLang, dark, setDark, free, setFree, onReplayAuth, onReplayOnboarding, onRedeem }) { const [auto, setAuto] = useState(true); const [kill, setKill] = useState(true); const [boot, setBoot] = useState(true); const card = { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-sm)', overflow: 'hidden', marginBottom: 16 }; const Row = ({ title, sub, right, last, onClick }) => /*#__PURE__*/React.createElement("div", { onClick: onClick, style: { display: 'flex', alignItems: 'center', gap: 12, padding: '14px 18px', borderBottom: last ? 'none' : '1px solid var(--border)', cursor: onClick ? 'pointer' : 'default' } }, /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14, fontWeight: 500, color: 'var(--fg1)' } }, title), sub && /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)', marginTop: 2 } }, sub)), right); return /*#__PURE__*/React.createElement("div", { style: { padding: '8px 32px 24px', maxWidth: 560 } }, /*#__PURE__*/React.createElement("div", { style: card }, /*#__PURE__*/React.createElement(Row, { title: t('redeemEntry'), sub: t('proMember'), right: /*#__PURE__*/React.createElement(DIcon, { name: "chevron-right", size: 18, color: "var(--fg3)" }), last: true, onClick: onRedeem })), /*#__PURE__*/React.createElement("div", { style: card }, /*#__PURE__*/React.createElement(Row, { title: t('autostart'), sub: t('autostartSub'), right: /*#__PURE__*/React.createElement(DToggle, { on: boot, onChange: () => setBoot(!boot) }) }), /*#__PURE__*/React.createElement(Row, { title: t('smartRoute'), sub: t('smartRouteSub'), right: /*#__PURE__*/React.createElement(DToggle, { on: auto, onChange: () => setAuto(!auto) }) }), /*#__PURE__*/React.createElement(Row, { title: t('killSwitch'), sub: t('killSwitchSub'), right: /*#__PURE__*/React.createElement(DToggle, { on: kill, onChange: () => setKill(!kill) }), last: true })), /*#__PURE__*/React.createElement("div", { style: card }, /*#__PURE__*/React.createElement(Row, { title: t('language'), right: /*#__PURE__*/React.createElement(DLangSwitch, { lang: lang, setLang: setLang }) }), /*#__PURE__*/React.createElement(Row, { title: t('darkAppearance'), sub: dark ? t('stateOn') : t('followLight'), right: /*#__PURE__*/React.createElement(DToggle, { on: dark, onChange: () => setDark(!dark) }) }), /*#__PURE__*/React.createElement(Row, { title: t('protocol'), right: /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--fg3)' } }, "WireGuard") }), /*#__PURE__*/React.createElement(Row, { title: t('checkUpdate'), right: /*#__PURE__*/React.createElement(DIcon, { name: "chevron-right", size: 18, color: "var(--fg3)" }) }), /*#__PURE__*/React.createElement(Row, { title: t('version'), right: /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--fg3)' } }, "v2.4.0 (macOS)"), last: true })), /*#__PURE__*/React.createElement("div", { style: card }, /*#__PURE__*/React.createElement(Row, { title: t('replayAuth'), sub: t('replayAuthSub'), right: /*#__PURE__*/React.createElement(DIcon, { name: "chevron-right", size: 18, color: "var(--fg3)" }), onClick: onReplayAuth }), /*#__PURE__*/React.createElement(Row, { title: t('replayOnboarding'), sub: t('replayOnboardingSub'), right: /*#__PURE__*/React.createElement(DIcon, { name: "chevron-right", size: 18, color: "var(--fg3)" }), onClick: onReplayOnboarding }), /*#__PURE__*/React.createElement(Row, { title: t('freeDemo'), sub: t('freeDemoSub'), right: /*#__PURE__*/React.createElement(DToggle, { on: free, onChange: () => setFree(!free) }), last: true }))); } function DesktopApp() { const [stage, setStage] = useState('app'); // app | auth | onboarding — UI kit opens on the main app const [view, setView] = useState('connect'); const [status, setStatus] = useState('off'); const [code, setCode] = useState('AUTO'); // 'AUTO' = 智能选择(默认) const [dark, setDark] = useState(false); const [lang, setLang] = useState('zh'); const [free, setFree] = useState(true); // 演示:免费版视角(与移动端一致) const [mins, setMins] = useState(6); const [adDone, setAdDone] = useState(false); const [elapsed, setElapsed] = useState(0); const timer = useRef(null); const t = dT(lang); const smart = code === 'AUTO'; const server = smart ? DSERVERS.reduce((a, b) => a.ping < b.ping ? a : b) : DSERVERS.find(s => s.code === code); const titles = { connect: t('connect'), servers: t('servers'), stats: t('stats'), account: t('navAccount'), plans: t('choosePlan'), redeem: t('redeemTitle'), contact: t('navContact'), settings: t('settings') }; function toggle() { if (status === 'off') { setStatus('connecting'); setTimeout(() => { setStatus('on'); setElapsed(0); }, 1500); } else setStatus('off'); } function pick(c) { setCode(c); setView('connect'); if (status === 'on') { setStatus('connecting'); setTimeout(() => { setStatus('on'); setElapsed(0); }, 1200); } } useEffect(() => { if (status === 'on') timer.current = setInterval(() => setElapsed(e => e + 1), 1000); return () => clearInterval(timer.current); }, [status]); if (stage === 'auth') return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', padding: 28, boxSizing: 'border-box' } }, /*#__PURE__*/React.createElement(DAuthFlow, { t: t, lang: lang, dark: dark, onDone: () => setStage('onboarding') })); if (stage === 'onboarding') return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', padding: 28, boxSizing: 'border-box' } }, /*#__PURE__*/React.createElement(DOnboarding, { t: t, lang: lang, dark: dark, onDone: () => setStage('app') })); let main; if (view === 'connect') main = /*#__PURE__*/React.createElement(DConnect, { t: t, lang: lang, status: status, onToggle: toggle, server: server, smart: smart, free: free, mins: mins, adDone: adDone, onAd: () => setAdDone(true), elapsed: elapsed });else if (view === 'servers') main = /*#__PURE__*/React.createElement(DServers, { t: t, lang: lang, current: code, onPick: pick });else if (view === 'stats') main = /*#__PURE__*/React.createElement(DStats, { t: t, lang: lang });else if (view === 'account') main = /*#__PURE__*/React.createElement(DAccountView, { t: t, lang: lang, free: free, onUpgrade: () => setView('plans'), onSignOut: () => setStage('auth') });else if (view === 'plans') main = /*#__PURE__*/React.createElement(DPlansView, { t: t, lang: lang, onChoose: () => setView('redeem') });else if (view === 'redeem') main = /*#__PURE__*/React.createElement(DRedeemView, { t: t, lang: lang });else if (view === 'contact') main = /*#__PURE__*/React.createElement(DContactView, { t: t, lang: lang });else main = /*#__PURE__*/React.createElement(DSettings, { t: t, lang: lang, setLang: setLang, dark: dark, setDark: setDark, free: free, setFree: setFree, onReplayAuth: () => setStage('auth'), onReplayOnboarding: () => setStage('onboarding'), onRedeem: () => setView('redeem') }); return /*#__PURE__*/React.createElement("div", { "data-theme": dark ? 'dark' : 'light', style: { width: 920, height: 600, borderRadius: 16, overflow: 'hidden', display: 'flex', background: 'var(--bg)', boxShadow: '0 0 0 1px rgba(0,0,0,0.12), 0 28px 70px rgba(0,0,0,0.4)', fontFamily: 'var(--font-sans)' } }, /*#__PURE__*/React.createElement("div", { style: { width: 204, flexShrink: 0, background: 'var(--bg-subtle)', borderRight: '1px solid var(--border)', display: 'flex', flexDirection: 'column', padding: '14px 12px' } }, /*#__PURE__*/React.createElement("div", { style: { padding: '2px 4px 16px' } }, /*#__PURE__*/React.createElement(MacTrafficLights, null)), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 9, padding: '0 6px 16px' } }, /*#__PURE__*/React.createElement(DMark, { size: 28 }), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 16, color: 'var(--fg1)', lineHeight: 1 } }, lang === 'zh' ? '穿山甲' : 'Pangolin'), /*#__PURE__*/React.createElement("div", { style: { fontSize: 9, fontWeight: 600, letterSpacing: '0.18em', color: 'var(--accent)', marginTop: 3 } }, "PANGOLIN"))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 3 } }, /*#__PURE__*/React.createElement(NavItem, { icon: "power", label: t('navConnect'), active: view === 'connect', onClick: () => setView('connect') }), /*#__PURE__*/React.createElement(NavItem, { icon: "globe", label: t('navServers'), active: view === 'servers', onClick: () => setView('servers') }), /*#__PURE__*/React.createElement(NavItem, { icon: "chart-no-axes-column", label: t('navStats'), active: view === 'stats', onClick: () => setView('stats') }), /*#__PURE__*/React.createElement(NavItem, { icon: "user", label: t('navAccount'), active: view === 'account' || view === 'plans' || view === 'redeem', onClick: () => setView('account') }), /*#__PURE__*/React.createElement(NavItem, { icon: "message-circle", label: t('navContact'), active: view === 'contact', onClick: () => setView('contact') }), /*#__PURE__*/React.createElement(NavItem, { icon: "settings", label: t('navSettings'), active: view === 'settings', onClick: () => setView('settings') })), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 10, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-md)', padding: '9px 11px' } }, /*#__PURE__*/React.createElement("div", { style: { width: 30, height: 30, borderRadius: '50%', background: 'linear-gradient(150deg,var(--clay-500),var(--clay-700))', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(DIcon, { name: "crown", size: 15, color: "#fff" })), /*#__PURE__*/React.createElement("div", { style: { minWidth: 0 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, fontWeight: 600, color: 'var(--fg1)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } }, free ? t('freePlanName') : t('proMember')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 10.5, color: 'var(--fg3)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } }, free ? t('quotaFree') : t('until'))))), /*#__PURE__*/React.createElement("div", { style: { flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 } }, /*#__PURE__*/React.createElement("div", { style: { height: 52, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 24px', borderBottom: '1px solid var(--border)' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 10 } }, (view === 'redeem' || view === 'plans') && /*#__PURE__*/React.createElement("button", { onClick: () => setView('account'), style: { border: 'none', background: 'transparent', cursor: 'pointer', padding: 4, display: 'flex' } }, /*#__PURE__*/React.createElement(DIcon, { name: "arrow-left", size: 20, color: "var(--fg1)" })), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 17, color: 'var(--fg1)' } }, titles[view])), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 12 } }, /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 12, fontWeight: 600, whiteSpace: 'nowrap', color: status === 'on' ? 'var(--success)' : 'var(--fg3)' } }, status === 'on' ? '● ' + t('connected') + ' ' + server.code : '○ ' + t('notConnected')), /*#__PURE__*/React.createElement("button", { onClick: () => setDark(!dark), style: { border: 'none', background: 'transparent', cursor: 'pointer', padding: 6, borderRadius: 'var(--radius-sm)', display: 'flex' } }, /*#__PURE__*/React.createElement(DIcon, { name: dark ? 'sun' : 'moon', size: 18, color: "var(--fg2)" })))), /*#__PURE__*/React.createElement("div", { style: { flex: 1, overflow: 'auto', minHeight: 0 } }, main))); } Object.assign(window, { DesktopApp }); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/desktop/dapp.jsx", error: String((e && e.message) || e) }); } // ui_kits/desktop/dflows.jsx try { (() => { /* dflows.jsx — 穿山甲 VPN desktop · auth + account management (integrated dashboard) + redeem */ const { useState: useStateD } = React; const dCard = { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-xl)', boxShadow: 'var(--shadow-sm)' }; const dInput = { border: '1.5px solid var(--border-strong)', borderRadius: 'var(--radius-md)', padding: '11px 13px', fontFamily: 'var(--font-sans)', fontSize: 14, color: 'var(--fg1)', background: 'var(--bg)', outline: 'none', width: '100%', boxSizing: 'border-box' }; function DField({ label, children }) { return /*#__PURE__*/React.createElement("label", { style: { display: 'block' } }, /*#__PURE__*/React.createElement("span", { style: { display: 'block', fontSize: 12.5, fontWeight: 600, color: 'var(--fg2)', marginBottom: 6 } }, label), children); } /* ───────── AUTH — split panel, brand left / form right ───────── */ function DAuthFlow({ t, lang, dark, onDone }) { const [mode, setMode] = useStateD('login'); const [step, setStep] = useStateD(0); const [email, setEmail] = useStateD(''); const [code, setCode] = useStateD(''); const [pw, setPw] = useStateD(''); const [sent, setSent] = useStateD(false); const [totp, setTotp] = useStateD(false); // 2FA step after login (PRO) const [otp, setOtp] = useStateD(''); const valid = /\S+@\S+\.\S+/.test(email); const tab = (id, label) => /*#__PURE__*/React.createElement("button", { onClick: () => { setMode(id); setStep(0); setSent(false); }, style: { flex: 1, border: 'none', cursor: 'pointer', background: 'transparent', padding: '10px 0', fontFamily: 'var(--font-sans)', fontSize: 15, fontWeight: mode === id ? 700 : 500, color: mode === id ? 'var(--fg1)' : 'var(--fg3)', borderBottom: mode === id ? '2px solid var(--accent)' : '2px solid transparent' } }, label); const primary = (label, onClick, enabled) => /*#__PURE__*/React.createElement("button", { onClick: enabled ? onClick : undefined, disabled: !enabled, style: { width: '100%', border: 'none', borderRadius: 'var(--radius-full)', padding: '13px', fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 15, cursor: enabled ? 'pointer' : 'not-allowed', background: 'var(--accent)', color: 'var(--fg-on-accent)', opacity: enabled ? 1 : 0.45, marginTop: 4 } }, label); return /*#__PURE__*/React.createElement("div", { "data-theme": dark ? 'dark' : 'light', style: { width: 880, height: 560, borderRadius: 16, overflow: 'hidden', display: 'flex', boxShadow: '0 0 0 1px rgba(0,0,0,0.12), 0 28px 70px rgba(0,0,0,0.4)', fontFamily: 'var(--font-sans)' } }, /*#__PURE__*/React.createElement("div", { style: { width: 340, flexShrink: 0, background: 'linear-gradient(165deg,var(--clay-500),var(--clay-800))', color: '#fff', padding: '48px 40px', display: 'flex', flexDirection: 'column' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 11 } }, /*#__PURE__*/React.createElement(DMark, { size: 34, color: "#fff" }), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 20 } }, lang === 'zh' ? '穿山甲' : 'Pangolin')), /*#__PURE__*/React.createElement("div", { style: { flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center' } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 28, lineHeight: 1.3 } }, t('authSidePitch'))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, opacity: .8, letterSpacing: '0.04em' } }, t('authTagline'))), /*#__PURE__*/React.createElement("div", { style: { flex: 1, background: 'var(--bg)', padding: '44px 46px', display: 'flex', flexDirection: 'column' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', borderBottom: '1px solid var(--border)', marginBottom: 26 } }, tab('login', t('tabLogin')), tab('register', t('tabRegister'))), /*#__PURE__*/React.createElement("div", { style: { flex: 1, display: 'flex', flexDirection: 'column', gap: 16 } }, mode === 'login' && !totp && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(DField, { label: t('emailLabel') }, /*#__PURE__*/React.createElement("input", { style: dInput, value: email, onChange: e => setEmail(e.target.value), placeholder: t('emailPh') })), /*#__PURE__*/React.createElement(DField, { label: t('pwLabel') }, /*#__PURE__*/React.createElement("input", { style: dInput, type: "password", value: pw, onChange: e => setPw(e.target.value), placeholder: t('pwPh') })), /*#__PURE__*/React.createElement("div", { style: { textAlign: 'right', marginTop: -6 } }, /*#__PURE__*/React.createElement("span", { style: { fontSize: 13, color: 'var(--accent)', fontWeight: 600, cursor: 'pointer' } }, t('forgotPw'))), primary(t('doLogin'), () => setTotp(true), valid && pw.length > 0)), mode === 'login' && totp && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 8 } }, /*#__PURE__*/React.createElement(DIcon, { name: "shield-check", size: 18, color: "var(--accent)" }), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 17, color: 'var(--fg1)' } }, t('twoFATitle')), /*#__PURE__*/React.createElement("span", { style: { fontSize: 10, fontWeight: 700, color: 'var(--accent)', background: 'var(--accent-subtle)', border: '1px solid var(--accent-border)', padding: '2px 8px', borderRadius: 999 } }, "PRO")), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, color: 'var(--fg3)', lineHeight: 1.6 } }, t('twoFAHint')), /*#__PURE__*/React.createElement("input", { value: otp, onChange: e => setOtp(e.target.value.replace(/\D/g, '').slice(0, 6)), placeholder: "\xB7\xB7\xB7\xB7\xB7\xB7", style: { ...dInput, fontFamily: 'var(--font-mono)', fontSize: 20, letterSpacing: '0.5em', textAlign: 'center' } }), primary(t('twoFAConfirm'), onDone, otp.length === 6), /*#__PURE__*/React.createElement("div", { onClick: () => setTotp(false), style: { textAlign: 'center', fontSize: 12.5, color: 'var(--fg3)', cursor: 'pointer' } }, t('twoFABack'))), mode === 'register' && step === 0 && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(DField, { label: t('emailLabel') }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 8 } }, /*#__PURE__*/React.createElement("input", { style: dInput, value: email, onChange: e => setEmail(e.target.value), placeholder: t('emailPh') }), /*#__PURE__*/React.createElement("button", { onClick: () => valid && setSent(true), style: { border: '1.5px solid var(--border-strong)', background: 'transparent', borderRadius: 'var(--radius-md)', padding: '0 16px', cursor: valid ? 'pointer' : 'default', color: valid ? 'var(--accent)' : 'var(--fg3)', fontWeight: 700, fontSize: 13, whiteSpace: 'nowrap', flexShrink: 0 } }, sent ? t('resend') : t('sendCode')))), sent && /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--success)', marginTop: -8, display: 'flex', alignItems: 'center', gap: 6 } }, /*#__PURE__*/React.createElement(DIcon, { name: "check-circle", size: 14, color: "var(--success)" }), t('codeSentTo'), " ", email), /*#__PURE__*/React.createElement(DField, { label: t('codeLabel') }, /*#__PURE__*/React.createElement("input", { style: { ...dInput, fontFamily: 'var(--font-mono)', letterSpacing: '0.3em' }, value: code, onChange: e => setCode(e.target.value.replace(/\D/g, '').slice(0, 6)), placeholder: "\xB7\xB7\xB7\xB7\xB7\xB7" })), primary(t('doNext'), () => setStep(1), sent && code.length === 6)), mode === 'register' && step === 1 && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, color: 'var(--fg2)', display: 'flex', alignItems: 'center', gap: 7 } }, /*#__PURE__*/React.createElement(DIcon, { name: "check-circle", size: 15, color: "var(--success)" }), email), /*#__PURE__*/React.createElement(DField, { label: t('pwLabel') }, /*#__PURE__*/React.createElement("input", { style: dInput, type: "password", value: pw, onChange: e => setPw(e.target.value), placeholder: t('setPwPh') })), primary(t('doCreate'), onDone, pw.length >= 6))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11, color: 'var(--fg3)', textAlign: 'center', lineHeight: 1.5, paddingTop: 18 } }, t('tos')))); } /* ───────── ACCOUNT (integrated: plan + account info + devices) ───────── */ function DAccountView({ t, lang, free, onUpgrade, onSignOut }) { const [twoFA, setTwoFA] = useStateD(true); const [devices, setDevices] = useStateD([{ id: 1, icon: 'laptop', name: 'MacBook Pro', os: 'macOS 26', active: t('thisDevice'), me: true }, { id: 2, icon: 'smartphone', name: 'iPhone 17', os: 'iOS 26', active: '2 min', me: false }, { id: 3, icon: 'monitor-smartphone', name: 'iPad Air', os: 'iPadOS 26', active: lang === 'zh' ? '3 小时前' : '3h ago', me: false }]); const infoRow = (label, value, action, last) => /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 12, padding: '14px 18px', borderBottom: last ? 'none' : '1px solid var(--border)' } }, /*#__PURE__*/React.createElement("div", { style: { width: 96, fontSize: 13, fontWeight: 600, color: 'var(--fg2)' } }, label), /*#__PURE__*/React.createElement("div", { style: { flex: 1, fontSize: 14, color: 'var(--fg1)' } }, value), action); const smallBtn = { border: '1.5px solid var(--border-strong)', background: 'transparent', color: 'var(--fg2)', fontSize: 13, fontWeight: 600, padding: '7px 14px', borderRadius: 'var(--radius-full)', cursor: 'pointer' }; return /*#__PURE__*/React.createElement("div", { style: { padding: '8px 32px 28px', display: 'flex', flexDirection: 'column', gap: 22, maxWidth: 760 } }, /*#__PURE__*/React.createElement("div", { style: { ...dCard, background: 'linear-gradient(150deg,var(--clay-600),var(--clay-800))', border: 'none', color: '#fff', padding: '20px 24px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 15 } }, /*#__PURE__*/React.createElement("div", { style: { width: 48, height: 48, borderRadius: '50%', background: 'rgba(255,255,255,.18)', display: 'flex', alignItems: 'center', justifyContent: 'center' } }, /*#__PURE__*/React.createElement(DIcon, { name: "crown", size: 24, color: "#fff" })), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, opacity: .8 } }, t('curPlan')), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 20, fontWeight: 700, marginTop: 2 } }, free ? t('freePlanName') : t('proMember')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11.5, opacity: .8, marginTop: 3, fontFamily: 'var(--font-mono)', whiteSpace: 'nowrap' } }, free ? t('quotaFree') : `${t('expires')} 2026-12-31 · ${t('accUsage')} 42.6 GB`))), /*#__PURE__*/React.createElement("button", { onClick: onUpgrade, style: { border: 'none', background: '#fff', color: 'var(--clay-700)', fontWeight: 700, fontSize: 14, padding: '11px 20px', borderRadius: 'var(--radius-full)', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 8 } }, /*#__PURE__*/React.createElement(DIcon, { name: "ticket", size: 16, color: "var(--clay-700)" }), t('renew'))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 17, fontWeight: 700, color: 'var(--fg1)', marginBottom: 14 } }, t('accInfoTitle')), /*#__PURE__*/React.createElement("div", { style: { ...dCard, overflow: 'hidden' } }, infoRow(t('accEmail'), 'me@pangolin.vpn', /*#__PURE__*/React.createElement("button", { style: smallBtn }, t('accChange'))), infoRow(t('accPassword'), '••••••••••', /*#__PURE__*/React.createElement("button", { style: smallBtn }, t('accChange'))), infoRow(t('twoFA'), t('twoFASub'), /*#__PURE__*/React.createElement(DToggle, { on: twoFA, onChange: () => setTwoFA(!twoFA) })), infoRow(t('ucEntry'), t('ucEntrySub'), /*#__PURE__*/React.createElement("button", { onClick: () => window.open('../usercenter/index.html', '_blank'), style: { ...smallBtn, display: 'inline-flex', alignItems: 'center', gap: 6 } }, /*#__PURE__*/React.createElement(DIcon, { name: "external-link", size: 14, color: "var(--fg2)" }), t('ucOpen'))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 12, padding: '14px 18px' } }, /*#__PURE__*/React.createElement("div", { style: { width: 96, fontSize: 13, fontWeight: 600, color: 'var(--danger)' } }, t('accSignOut')), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }), /*#__PURE__*/React.createElement("button", { onClick: onSignOut, style: { ...smallBtn, color: 'var(--danger)', borderColor: 'var(--danger-subtle)', background: 'var(--danger-subtle)', display: 'inline-flex', alignItems: 'center', gap: 7 } }, /*#__PURE__*/React.createElement(DIcon, { name: "log-out", size: 15, color: "var(--danger)" }), t('accSignOut'))))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 17, fontWeight: 700, color: 'var(--fg1)' } }, t('myDevices')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, color: 'var(--fg3)', margin: '3px 0 14px' } }, t('devicesSub')), /*#__PURE__*/React.createElement("div", { style: { ...dCard, overflow: 'hidden' } }, devices.map((d, i) => /*#__PURE__*/React.createElement("div", { key: d.id, style: { display: 'flex', alignItems: 'center', gap: 14, padding: '14px 18px', borderBottom: i < devices.length - 1 ? '1px solid var(--border)' : 'none' } }, /*#__PURE__*/React.createElement("div", { style: { width: 40, height: 40, borderRadius: 'var(--radius-md)', background: 'var(--accent-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(DIcon, { name: d.icon, size: 20, color: "var(--accent)" })), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14.5, fontWeight: 600, color: 'var(--fg1)', display: 'flex', alignItems: 'center', gap: 8 } }, d.name, d.me && /*#__PURE__*/React.createElement("span", { style: { fontSize: 11, fontWeight: 600, color: 'var(--success)', background: 'var(--success-subtle)', padding: '2px 8px', borderRadius: 999 } }, d.active)), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)', marginTop: 2 } }, d.os, !d.me && ` · ${t('lastActive')} ${d.active}`)), !d.me && /*#__PURE__*/React.createElement("button", { onClick: () => setDevices(devices.filter(x => x.id !== d.id)), style: { border: '1.5px solid var(--border-strong)', background: 'transparent', color: 'var(--fg2)', fontSize: 13, fontWeight: 600, padding: '7px 14px', borderRadius: 'var(--radius-full)', cursor: 'pointer' } }, t('remove'))))))); } /* ───────── PLANS (shown on renew / upgrade) ───────── */ function DPlansView({ t, lang, onChoose }) { const plans = [{ id: 'free', name: t('free'), price: '¥0', feats: t('feFree'), cta: t('current'), variant: 'cur' }, { id: 'pro', name: t('proPlan'), price: '¥25', feats: t('fePro'), cta: t('upgrade'), variant: 'pro' }, { id: 'team', name: t('team'), price: '¥99', feats: t('feTeam'), cta: t('choose'), variant: 'plain' }]; return /*#__PURE__*/React.createElement("div", { style: { padding: '8px 32px 28px' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 16, alignItems: 'start', maxWidth: 760 } }, plans.map(p => { const isPro = p.variant === 'pro'; return /*#__PURE__*/React.createElement("div", { key: p.id, style: { ...dCard, position: 'relative', padding: '22px 20px', ...(isPro ? { background: 'linear-gradient(160deg,var(--clay-600),var(--clay-800))', border: 'none', color: '#fff', boxShadow: 'var(--shadow-md)' } : {}) } }, isPro && /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', top: -10, left: '50%', transform: 'translateX(-50%)', background: '#fff', color: 'var(--clay-700)', fontSize: 11, fontWeight: 700, padding: '3px 11px', borderRadius: 999, boxShadow: 'var(--shadow-sm)' } }, t('mostPopular')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 13.5, fontWeight: 600, color: isPro ? '#fff' : 'var(--fg2)', opacity: isPro ? .85 : 1 } }, p.name), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 30, fontWeight: 700, marginTop: 6, color: isPro ? '#fff' : 'var(--fg1)' } }, p.price, /*#__PURE__*/React.createElement("span", { style: { fontSize: 13, fontWeight: 500, opacity: .7 } }, t('perMonth'))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 9, margin: '16px 0 18px' } }, p.feats.map((f, i) => /*#__PURE__*/React.createElement("div", { key: i, style: { display: 'flex', alignItems: 'center', gap: 9, fontSize: 13, color: isPro ? 'rgba(255,255,255,.92)' : 'var(--fg2)' } }, /*#__PURE__*/React.createElement(DIcon, { name: "check", size: 15, color: isPro ? '#fff' : 'var(--success)', stroke: 2.4 }), f))), /*#__PURE__*/React.createElement("button", { onClick: p.variant !== 'cur' ? onChoose : undefined, style: { width: '100%', border: p.variant === 'cur' ? '1.5px solid var(--border-strong)' : 'none', cursor: p.variant === 'cur' ? 'default' : 'pointer', borderRadius: 'var(--radius-full)', padding: '11px', fontWeight: 600, fontSize: 14, background: isPro ? '#fff' : p.variant === 'cur' ? 'transparent' : 'var(--accent)', color: isPro ? 'var(--clay-700)' : p.variant === 'cur' ? 'var(--fg2)' : '#fff' } }, p.cta)); }))); } /* ───────── REDEEM & BUY ───────── */ function DRedeemView({ t, lang }) { const [code, setCode] = useStateD(''); const [ok, setOk] = useStateD(false); const channels = [{ icon: 'shopping-bag', name: t('chStore'), sub: t('chStoreSub'), accent: true }, { icon: 'credit-card', name: 'USDT (TRC20)', sub: t('chUsdtSub'), mono: false }, { icon: 'send', name: 'Telegram', sub: t('chTgSub'), mono: true }, { icon: 'message-circle', name: 'LINE', sub: t('chLineSub'), mono: true }, { icon: 'mail', name: t('chEmail'), sub: t('chEmailSub'), mono: true }]; return /*#__PURE__*/React.createElement("div", { style: { padding: '8px 32px 28px', maxWidth: 680 } }, /*#__PURE__*/React.createElement("div", { style: { ...dCard, padding: '20px 22px', marginBottom: 24 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14.5, fontWeight: 700, color: 'var(--fg1)', marginBottom: 12 } }, t('redeemCodeTitle')), ok ? /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 9, color: 'var(--success)', fontWeight: 600, fontSize: 15, padding: '6px 0' } }, /*#__PURE__*/React.createElement(DIcon, { name: "check-circle", size: 20, color: "var(--success)" }), t('redeemOk')) : /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 10 } }, /*#__PURE__*/React.createElement("input", { value: code, onChange: e => setCode(e.target.value.toUpperCase()), placeholder: t('redeemPh'), style: { ...dInput, fontFamily: 'var(--font-mono)', letterSpacing: '0.08em' } }), /*#__PURE__*/React.createElement("button", { onClick: () => code.length >= 4 && setOk(true), style: { border: 'none', borderRadius: 'var(--radius-md)', padding: '0 22px', background: 'var(--accent)', color: '#fff', fontWeight: 700, fontSize: 14, cursor: 'pointer', flexShrink: 0 } }, t('redeemBtn')))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 14.5, fontWeight: 700, color: 'var(--fg1)', marginBottom: 6 } }, t('buyTitle')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, color: 'var(--fg3)', lineHeight: 1.5, marginBottom: 14 } }, t('buySub')), /*#__PURE__*/React.createElement("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 } }, channels.map(c => /*#__PURE__*/React.createElement("button", { key: c.name, style: { display: 'flex', alignItems: 'center', gap: 13, textAlign: 'left', cursor: 'pointer', background: c.accent ? 'var(--accent-subtle)' : 'var(--surface)', border: `1px solid ${c.accent ? 'var(--accent-border)' : 'var(--border)'}`, borderRadius: 'var(--radius-lg)', padding: '14px 16px', boxShadow: 'var(--shadow-sm)' } }, /*#__PURE__*/React.createElement("div", { style: { width: 40, height: 40, borderRadius: 'var(--radius-md)', background: c.accent ? 'var(--accent)' : 'var(--bg-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(DIcon, { name: c.icon, size: 20, color: c.accent ? '#fff' : 'var(--accent)' })), /*#__PURE__*/React.createElement("div", { style: { flex: 1, minWidth: 0 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14.5, fontWeight: 600, color: 'var(--fg1)' } }, c.name), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)', fontFamily: c.mono ? 'var(--font-mono)' : 'var(--font-sans)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } }, c.sub)), /*#__PURE__*/React.createElement(DIcon, { name: "external-link", size: 16, color: "var(--fg3)" }))))); } /* ───────── ONBOARDING — window card, 3 screens ───────── */ function DOnboarding({ t, lang, dark, onDone }) { const [i, setI] = useStateD(0); const steps = [{ icon: 'globe', title: t('ob1Title'), sub: t('ob1Sub'), cta: t('obNext') }, { icon: 'lock', title: t('ob2Title'), sub: t('ob2Sub'), cta: t('obAllow') }, { icon: 'shield-check', title: t('ob3Title'), sub: t('ob3Sub'), cta: t('obStart') }]; const s = steps[i]; const last = i === steps.length - 1; return /*#__PURE__*/React.createElement("div", { "data-theme": dark ? 'dark' : 'light', style: { width: 560, height: 520, borderRadius: 16, overflow: 'hidden', display: 'flex', flexDirection: 'column', background: 'var(--bg)', boxShadow: '0 0 0 1px rgba(0,0,0,0.12), 0 28px 70px rgba(0,0,0,0.4)', fontFamily: 'var(--font-sans)' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '18px 22px' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 9 } }, /*#__PURE__*/React.createElement(DMark, { size: 24 }), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 15, color: 'var(--fg1)' } }, lang === 'zh' ? '穿山甲' : 'Pangolin')), !last && /*#__PURE__*/React.createElement("button", { onClick: onDone, style: { border: 'none', background: 'transparent', cursor: 'pointer', fontSize: 13, fontWeight: 600, color: 'var(--fg3)' } }, t('obSkip'))), /*#__PURE__*/React.createElement("div", { style: { flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', textAlign: 'center', padding: '0 56px', gap: 22 } }, /*#__PURE__*/React.createElement("div", { style: { width: 108, height: 108, borderRadius: '50%', background: 'var(--accent-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center' } }, /*#__PURE__*/React.createElement(DIcon, { name: s.icon, size: 52, stroke: 1.6, color: "var(--accent)" })), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 26, fontWeight: 700, color: 'var(--fg1)' } }, s.title), /*#__PURE__*/React.createElement("div", { style: { fontSize: 15, color: 'var(--fg2)', lineHeight: 1.6, marginTop: 10, maxWidth: 380 } }, s.sub))), /*#__PURE__*/React.createElement("div", { style: { padding: '0 40px 36px', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 20 } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 8 } }, steps.map((_, k) => /*#__PURE__*/React.createElement("div", { key: k, style: { width: k === i ? 22 : 8, height: 8, borderRadius: 999, background: k === i ? 'var(--accent)' : 'var(--border-strong)', transition: 'all 220ms var(--ease-out)' } }))), /*#__PURE__*/React.createElement("button", { onClick: () => last ? onDone() : setI(i + 1), style: { width: '100%', maxWidth: 360, border: 'none', borderRadius: 'var(--radius-full)', padding: '13px', fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 15, cursor: 'pointer', background: 'var(--accent)', color: 'var(--fg-on-accent)' } }, s.cta))); } /* ───────── CONTACT US ───────── */ function DContactView({ t, lang }) { const channels = [{ icon: 'send', name: t('contactTg'), sub: '@PangolinVPN_bot', accent: true }, { icon: 'message-circle', name: t('contactLine'), sub: '@pangolinvpn' }, { icon: 'mail', name: t('contactEmail'), sub: 'support@pangolin.vpn' }, { icon: 'shopping-bag', name: t('contactStore'), sub: 'shop.pangolin.vpn' }]; return /*#__PURE__*/React.createElement("div", { style: { padding: '8px 32px 28px', maxWidth: 680 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 13.5, color: 'var(--fg2)', lineHeight: 1.6, marginBottom: 18 } }, t('contactIntro')), /*#__PURE__*/React.createElement("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 22 } }, channels.map(c => /*#__PURE__*/React.createElement("button", { key: c.name, style: { display: 'flex', alignItems: 'center', gap: 13, textAlign: 'left', cursor: 'pointer', background: c.accent ? 'var(--accent-subtle)' : 'var(--surface)', border: `1px solid ${c.accent ? 'var(--accent-border)' : 'var(--border)'}`, borderRadius: 'var(--radius-lg)', padding: '14px 16px', boxShadow: 'var(--shadow-sm)' } }, /*#__PURE__*/React.createElement("div", { style: { width: 40, height: 40, borderRadius: 'var(--radius-md)', background: c.accent ? 'var(--accent)' : 'var(--bg-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(DIcon, { name: c.icon, size: 20, color: c.accent ? '#fff' : 'var(--accent)' })), /*#__PURE__*/React.createElement("div", { style: { flex: 1, minWidth: 0 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14.5, fontWeight: 600, color: 'var(--fg1)' } }, c.name), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)', fontFamily: 'var(--font-mono)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } }, c.sub)), /*#__PURE__*/React.createElement(DIcon, { name: "external-link", size: 16, color: "var(--fg3)" })))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 14 } }, /*#__PURE__*/React.createElement("div", { style: { ...dCard, flex: 1, padding: '16px 18px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, fontWeight: 600, color: 'var(--fg3)' } }, t('contactHoursTitle')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 15, fontWeight: 600, color: 'var(--fg1)', marginTop: 6, fontFamily: 'var(--font-mono)' } }, t('contactHours'))), /*#__PURE__*/React.createElement("div", { style: { ...dCard, flex: 2, padding: '16px 18px', display: 'flex', alignItems: 'center', gap: 14 } }, /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, fontWeight: 600, color: 'var(--fg3)' } }, t('contactFaqTitle')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, color: 'var(--fg2)', marginTop: 5, lineHeight: 1.5 } }, t('contactFaq'))), /*#__PURE__*/React.createElement("button", { style: { border: '1.5px solid var(--border-strong)', background: 'transparent', color: 'var(--fg1)', fontSize: 13, fontWeight: 600, padding: '9px 15px', borderRadius: 'var(--radius-full)', cursor: 'pointer', whiteSpace: 'nowrap', flexShrink: 0 } }, t('contactFaqBtn'))))); } Object.assign(window, { DAuthFlow, DOnboarding, DAccountView, DPlansView, DRedeemView, DContactView }); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/desktop/dflows.jsx", error: String((e && e.message) || e) }); } // ui_kits/desktop/dparts.jsx try { (() => { /* dparts.jsx — 穿山甲 VPN desktop · atoms (inline Lucide paths) */ const DLUCIDE = { power: '', 'shield-check': '', globe: '', 'loader-circle': '', 'chart-no-axes-column': '', settings: '', check: '', zap: '', 'arrow-down': '', 'arrow-up': '', search: '', moon: '', sun: '', crown: '', mail: '', lock: '', 'check-circle': '', 'arrow-left': '', 'chevron-right': '', send: '', 'message-circle': '', 'external-link': '', 'shopping-bag': '', laptop: '', smartphone: '', 'monitor-smartphone': '', 'log-out': '', ticket: '', clock: '', 'play-circle': '', compass: '', 'refresh-cw': '', 'credit-card': '', user: '' }; function DIcon({ name, size = 20, stroke = 2, color = 'currentColor', style = {} }) { return /*#__PURE__*/React.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round", style: { display: 'block', flexShrink: 0, ...style }, dangerouslySetInnerHTML: { __html: DLUCIDE[name] || '' } }); } function DMark({ size = 28, color = 'var(--accent)' }) { return /*#__PURE__*/React.createElement("svg", { width: size, height: size, viewBox: "0 0 96 96", fill: "none", style: { display: 'block' } }, /*#__PURE__*/React.createElement("g", { transform: "translate(96,0) scale(-1,1)" }, /*#__PURE__*/React.createElement("path", { d: "M16 59 Q17 51 26 50 Q34 31 45 30 Q55 30 62 37 Q69 41 75 45 Q85 49 89 44 Q92 50 84 52 Q75 53 67 53 Q66 62 60 62 L56 62 Q54 55 49 55 Q47 62 37 62 L33 62 Q31 56 26 56 Q20 59 16 59 Z", fill: color }), /*#__PURE__*/React.createElement("g", { stroke: "#fff", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", fill: "none", opacity: "0.5" }, /*#__PURE__*/React.createElement("path", { d: "M26 50 Q34 43 42 50" }), /*#__PURE__*/React.createElement("path", { d: "M36 48 Q44 41 52 48" }), /*#__PURE__*/React.createElement("path", { d: "M46 48 Q54 41 62 49" })), /*#__PURE__*/React.createElement("circle", { cx: "23", cy: "55", r: "2.2", fill: "#fff", opacity: "0.85" }))); } function DCC({ code, active, size = 34 }) { return /*#__PURE__*/React.createElement("div", { style: { width: size, height: size, borderRadius: 'var(--radius-md)', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--font-mono)', fontSize: size * 0.31, fontWeight: 600, background: active ? 'var(--accent)' : 'var(--bg-subtle)', color: active ? '#fff' : 'var(--fg2)' } }, code); } function DSignal({ ping }) { const lvl = ping < 40 ? 3 : ping < 90 ? 2 : 1; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 2, alignItems: 'flex-end', height: 13 } }, [4, 8, 13].map((h, i) => /*#__PURE__*/React.createElement("div", { key: i, style: { width: 3, height: h, borderRadius: 1, background: i < lvl ? 'var(--success)' : 'var(--border-strong)' } }))); } const DSTRINGS = { connect: { zh: '连接', en: 'Connect' }, servers: { zh: '选择节点', en: 'Choose server' }, stats: { zh: '统计', en: 'Stats' }, settings: { zh: '设置', en: 'Settings' }, navConnect: { zh: '连接', en: 'Connect' }, navServers: { zh: '节点', en: 'Servers' }, navStats: { zh: '统计', en: 'Stats' }, navSettings: { zh: '设置', en: 'Settings' }, proMember: { zh: 'PRO 会员', en: 'PRO member' }, until: { zh: '至 2026-12-31', en: 'until 2026-12-31' }, connected: { zh: '已连接', en: 'Connected' }, notConnected: { zh: '未连接', en: 'Not connected' }, capOff: { zh: '未连接', en: 'Not connected' }, subOff: { zh: '点击下方按钮开始保护', en: 'Tap the button below to start' }, capConnecting: { zh: '连接中…', en: 'Connecting…' }, subConnecting: { zh: '正在建立加密隧道', en: 'Establishing encrypted tunnel' }, capOn: { zh: '已连接', en: 'Connected' }, subOn: { zh: '你的网络已加密保护', en: 'Your network is encrypted' }, connectNow: { zh: '点击连接', en: 'CONNECT' }, search: { zh: '搜索国家 / 城市', en: 'Search country / city' }, trafficMonth: { zh: '本月流量', en: 'Traffic' }, avgPing: { zh: '平均延迟', en: 'Avg ping' }, durMonth: { zh: '本月时长', en: 'Time' }, weekTraffic: { zh: '本周流量 (GB)', en: 'This week (GB)' }, autostart: { zh: '开机自启动', en: 'Launch at login' }, autostartSub: { zh: '登录系统时自动启动穿山甲', en: 'Start Pangolin when you log in' }, smartRoute: { zh: '智能分流', en: 'Smart routing' }, smartRouteSub: { zh: '海外应用加速,本地直连', en: 'Accelerate overseas apps, keep local direct' }, killSwitch: { zh: 'Kill Switch', en: 'Kill Switch' }, killSwitchSub: { zh: '断线时阻断网络,防止 IP 泄露', en: 'Block traffic if the VPN drops' }, language: { zh: '语言', en: 'Language' }, darkAppearance: { zh: '深色外观', en: 'Dark appearance' }, stateOn: { zh: '已开启', en: 'On' }, followLight: { zh: '跟随浅色', en: 'Off' }, protocol: { zh: '协议', en: 'Protocol' }, version: { zh: '版本', en: 'Version' }, days: { zh: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], en: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, /* auth */ authTagline: { zh: '极速 · 稳定 · 省心', en: 'Fast · Stable · Effortless' }, tabLogin: { zh: '登录', en: 'Log in' }, tabRegister: { zh: '注册', en: 'Sign up' }, emailLabel: { zh: '邮箱', en: 'Email' }, emailPh: { zh: '你的邮箱地址', en: 'your@email.com' }, pwLabel: { zh: '密码', en: 'Password' }, pwPh: { zh: '输入密码', en: 'Enter password' }, setPwPh: { zh: '设置登录密码(用于多端登录)', en: 'Set a password (for multi-device login)' }, codeLabel: { zh: '邮箱验证码', en: 'Verification code' }, codeSentTo: { zh: '验证码已发送至', en: 'Code sent to' }, sendCode: { zh: '发送验证码', en: 'Send code' }, resend: { zh: '重新发送', en: 'Resend' }, doLogin: { zh: '登录', en: 'Log in' }, doNext: { zh: '下一步', en: 'Next' }, doCreate: { zh: '创建账户', en: 'Create account' }, forgotPw: { zh: '忘记密码?', en: 'Forgot password?' }, tos: { zh: '继续即代表同意《服务条款》与《隐私政策》', en: 'By continuing you agree to our Terms & Privacy Policy' }, authSidePitch: { zh: '一个账户,全平台同步。守护你的每一次连接。', en: 'One account, every device. Protecting every connection.' }, /* redeem & buy */ redeemEntry: { zh: '兑换 & 购买', en: 'Redeem & buy' }, redeemTitle: { zh: '兑换 & 购买', en: 'Redeem & buy' }, redeemCodeTitle: { zh: '兑换激活码', en: 'Redeem a code' }, redeemPh: { zh: '输入激活码', en: 'Enter activation code' }, redeemBtn: { zh: '激活', en: 'Redeem' }, redeemOk: { zh: '激活成功 · PRO 已开通', en: 'Activated · PRO unlocked' }, buyTitle: { zh: '购买渠道', en: 'Where to buy' }, buySub: { zh: '客户端内不支持直接支付。请通过以下渠道获取激活码:', en: 'In-app payment is unavailable. Get an activation code via:' }, chStore: { zh: '自助发卡商店', en: 'Self-serve store' }, chStoreSub: { zh: '支付宝 / 微信 · 自动发码', en: 'Alipay / WeChat · instant code' }, chUsdtSub: { zh: '链上转账 · 最隐私 · 自动发码', en: 'On-chain · most private · instant code' }, smartSelect: { zh: '智能选择', en: 'Smart select' }, smartSub: { zh: '根据当前网络环境,自动选择最优节点', en: 'Picks the best node for your network' }, recommended: { zh: '推荐', en: 'Recommended' }, twoFA: { zh: '双重认证', en: 'Two-factor auth' }, twoFASub: { zh: 'PRO 专享 · 登录需身份验证器动态码', en: 'PRO only · TOTP code at login' }, ucEntry: { zh: 'Web 用户中心', en: 'Web account center' }, ucEntrySub: { zh: '订阅导入 · 邀请返利', en: 'Subscription import · referral' }, ucOpen: { zh: '打开', en: 'Open' }, /* quota + free (口径见 CLAUDE.md §7,与移动端一致) */ quotaToday: { zh: '今日剩余', en: 'Left today' }, minutes: { zh: '分钟', en: 'min' }, quotaFree: { zh: '免费版 · 每日 10 分钟', en: 'Free · 10 min/day' }, watchAd: { zh: '看广告开始使用', en: 'Watch ad to start' }, adUnlocked: { zh: '已解锁 · 今日可用', en: 'Unlocked for today' }, freePlanName: { zh: '免费版', en: 'Free' }, freeDemo: { zh: '演示:免费版视角', en: 'Demo: free-tier view' }, freeDemoSub: { zh: '切换连接页的额度展示与套餐横幅', en: 'Toggles quota UI & plan banner' }, checkUpdate: { zh: '检查更新', en: 'Check for updates' }, replayOnboarding: { zh: '查看首次引导', en: 'View onboarding' }, replayOnboardingSub: { zh: '演示用 · 重看 3 屏引导', en: 'Demo · replay the 3 intro screens' }, /* 2FA login step (与用户中心一致) */ twoFATitle: { zh: '双重认证', en: 'Two-factor auth' }, twoFAHint: { zh: '你的账户已开启双重认证。请输入身份验证器 App 中的 6 位动态码。', en: 'Two-factor auth is on for this account. Enter the 6-digit code from your authenticator app.' }, twoFAConfirm: { zh: '验证并登录', en: 'Verify & log in' }, twoFABack: { zh: '返回上一步', en: 'Back' }, chTgSub: { zh: '@PangolinVPN_bot', en: '@PangolinVPN_bot' }, chLineSub: { zh: '@pangolinvpn', en: '@pangolinvpn' }, chEmail: { zh: '邮箱客服', en: 'Email support' }, chEmailSub: { zh: 'buy@pangolin.vpn', en: 'buy@pangolin.vpn' }, /* account management (integrated dashboard) */ navAccount: { zh: '账户', en: 'Account' }, curPlan: { zh: '当前套餐', en: 'Current plan' }, renew: { zh: '续费 / 升级', en: 'Renew / Upgrade' }, myDevices: { zh: '我的设备', en: 'My devices' }, devicesSub: { zh: 'PRO 套餐最多 5 台设备同时在线', en: 'Up to 5 devices on PRO' }, thisDevice: { zh: '当前设备', en: 'This device' }, lastActive: { zh: '最近活跃', en: 'Last active' }, remove: { zh: '移除', en: 'Remove' }, choosePlan: { zh: '选择套餐', en: 'Choose your plan' }, free: { zh: '免费版', en: 'Free' }, proPlan: { zh: '专业版', en: 'Pro' }, team: { zh: '团队版', en: 'Team' }, perMonth: { zh: '/月', en: '/mo' }, current: { zh: '当前', en: 'Current' }, upgrade: { zh: '立即升级', en: 'Upgrade' }, choose: { zh: '选择', en: 'Choose' }, mostPopular: { zh: '最受欢迎', en: 'Popular' }, feFree: { zh: ['仅 1 个基础节点', '每日 10 分钟时长', '使用前观看广告', '注册享 7 天免费试用'], en: ['1 basic node only', '10 min per day', 'Watch an ad to start', '7-day free trial on sign-up'] }, fePro: { zh: ['80+ 全球节点', '无限流量 · 极速', '5 台设备同时在线', '流媒体优化'], en: ['80+ locations', 'Unlimited · fast', '5 devices', 'Streaming optimized'] }, feTeam: { zh: ['Pro 全部功能', '10 个成员席位', '集中计费与管理', '优先客服'], en: ['Everything in Pro', '10 seats', 'Central billing', 'Priority support'] }, /* account info */ accInfoTitle: { zh: '账户信息', en: 'Account info' }, accEmail: { zh: '邮箱', en: 'Email' }, accPassword: { zh: '密码', en: 'Password' }, accChange: { zh: '修改', en: 'Change' }, accUsage: { zh: '本月用量', en: 'Used this month' }, accSignOut: { zh: '退出登录', en: 'Sign out' }, backToAccount: { zh: '返回账户', en: 'Back to account' }, /* demo replay */ replayAuth: { zh: '查看登录 / 注册流程', en: 'View login / sign-up' }, replayAuthSub: { zh: '演示用 · 退出到登录页', en: 'Demo · back to login' }, replayOnboarding: { zh: '查看首次引导', en: 'View onboarding' }, replayOnboardingSub: { zh: '演示用 · 重看引导页', en: 'Demo · replay intro' }, /* onboarding */ obSkip: { zh: '跳过', en: 'Skip' }, obNext: { zh: '下一步', en: 'Next' }, obAllow: { zh: '允许并继续', en: 'Allow & continue' }, obStart: { zh: '开始使用', en: 'Get started' }, ob1Title: { zh: '一键连接全球', en: 'Connect worldwide' }, ob1Sub: { zh: '80+ 节点,智能选择最快线路,稳定不掉线。', en: '80+ locations, auto-fastest routing, rock-solid.' }, ob2Title: { zh: '授权网络配置', en: 'Allow network setup' }, ob2Sub: { zh: '系统会请求添加一个网络配置,用于建立加密隧道。', en: 'Your system will ask to add a network profile to build the encrypted tunnel.' }, ob3Title: { zh: '安全 · 无日志', en: 'Private by design' }, ob3Sub: { zh: '端到端加密,我们不记录你的任何浏览数据。', en: 'End-to-end encrypted. We keep zero browsing logs.' }, /* contact us */ navContact: { zh: '联系我们', en: 'Contact us' }, contactIntro: { zh: '遇到问题?通过以下任一渠道联系我们,通常数分钟内回复。', en: 'Need help? Reach us through any channel below — we usually reply within minutes.' }, contactTg: { zh: 'Telegram 客服', en: 'Telegram support' }, contactLine: { zh: 'LINE 客服', en: 'LINE support' }, contactEmail: { zh: '邮箱客服', en: 'Email support' }, contactStore: { zh: '自助发卡商店', en: 'Self-serve store' }, contactHoursTitle: { zh: '服务时间', en: 'Support hours' }, contactHours: { zh: '每日 9:00 – 24:00 (GMT+8)', en: 'Daily 9:00 – 24:00 (GMT+8)' }, contactFaqTitle: { zh: '常见问题', en: 'FAQ' }, contactFaq: { zh: '连不上 / 兑换码无效 / 多设备登录,先查阅帮助中心。', en: 'Connection issues, invalid codes, multi-device — check the Help Center first.' }, contactFaqBtn: { zh: '打开帮助中心', en: 'Open Help Center' } }; function dT(lang) { return k => { const v = DSTRINGS[k]; return v ? v[lang] || k : k; }; } function dName(s, lang) { return lang === 'zh' ? s.name : s.en; } function dSub(s, lang) { if (lang === 'zh') return s.tag || s.en; return s.tag === '流媒体优化' ? 'Streaming' : s.tag === 'P2P' ? 'P2P' : s.name; } Object.assign(window, { DIcon, DMark, DCC, DSignal, DSTRINGS, dT, dName, dSub, DSERVERS: [{ code: 'HK', name: '香港 · 流媒体', en: 'Hong Kong', ping: 18, tag: '流媒体优化' }, { code: 'JP', name: '日本 东京', en: 'Tokyo', ping: 32, tag: 'P2P' }, { code: 'TW', name: '台湾 台北', en: 'Taipei', ping: 28, tag: '' }, { code: 'SG', name: '新加坡', en: 'Singapore', ping: 54, tag: 'P2P' }, { code: 'KR', name: '韩国 首尔', en: 'Seoul', ping: 41, tag: '' }, { code: 'US', name: '美国 洛杉矶', en: 'Los Angeles', ping: 146, tag: '流媒体优化' }, { code: 'DE', name: '德国 法兰克福', en: 'Frankfurt', ping: 198, tag: '' }, { code: 'UK', name: '英国 伦敦', en: 'London', ping: 210, tag: '' }] }); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/desktop/dparts.jsx", error: String((e && e.message) || e) }); } // ui_kits/desktop/macos-window.jsx try { (() => { /* BEGIN USAGE */ // MacOS.jsx — Simplified macOS Tahoe (Liquid Glass) window // Based on the macOS Tahoe UI Kit. No image assets, no dependencies. // Exports (to window): MacWindow, MacSidebar, MacSidebarItem, MacSidebarHeader, MacToolbar, MacGlass, MacTrafficLights // // Usage — wrap your app content in to get the window chrome // (traffic lights + titlebar). Props: width, height, title, sidebar (pass a // element); compose MacToolbar/MacGlass inside as needed: // // }> // ...your app content... // /* END USAGE */ const MAC_FONT = '-apple-system, BlinkMacSystemFont, "SF Pro", "Helvetica Neue", sans-serif'; // ───────────────────────────────────────────────────────────── // Liquid glass primitive — blur + white tint + inset highlight // ───────────────────────────────────────────────────────────── function MacGlass({ children, radius = 296, dark = false, style = {} }) { return /*#__PURE__*/React.createElement("div", { style: { position: 'relative', borderRadius: radius, ...style } }, /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', inset: 0, borderRadius: radius, background: dark ? 'rgba(255,255,255,0.08)' : 'rgba(255,255,255,0.35)', backdropFilter: 'blur(40px) saturate(180%)', WebkitBackdropFilter: 'blur(40px) saturate(180%)', border: dark ? '0.5px solid rgba(255,255,255,0.12)' : '0.5px solid rgba(255,255,255,0.6)', boxShadow: dark ? '0 8px 40px rgba(0,0,0,0.2)' : '0 8px 40px rgba(0,0,0,0.08), inset 0 1px 0 rgba(255,255,255,0.4)' } }), /*#__PURE__*/React.createElement("div", { style: { position: 'relative', zIndex: 1 } }, children)); } // ───────────────────────────────────────────────────────────── // Traffic lights (14px, Tahoe colors) // ───────────────────────────────────────────────────────────── function MacTrafficLights({ style = {} }) { const dot = bg => /*#__PURE__*/React.createElement("div", { style: { width: 14, height: 14, borderRadius: '50%', background: bg, border: '0.5px solid rgba(0,0,0,0.1)' } }); return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 9, alignItems: 'center', padding: 1, ...style } }, dot('#ff736a'), dot('#febc2e'), dot('#19c332')); } // ───────────────────────────────────────────────────────────── // Toolbar — title + single glass pill icon // ───────────────────────────────────────────────────────────── function MacToolbar({ title = 'Folder' }) { return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 8, alignItems: 'center', padding: 8, flexShrink: 0 } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: MAC_FONT, fontSize: 15, fontWeight: 700, color: 'rgba(0,0,0,0.85)', whiteSpace: 'nowrap', paddingLeft: 8 } }, title), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }), /*#__PURE__*/React.createElement(MacGlass, null, /*#__PURE__*/React.createElement("div", { style: { width: 36, height: 36, display: 'flex', alignItems: 'center', justifyContent: 'center' } }, /*#__PURE__*/React.createElement("div", { style: { width: 14, height: 14, borderRadius: '50%', background: '#4c4c4c', opacity: 0.4 } }))), /*#__PURE__*/React.createElement(MacGlass, null, /*#__PURE__*/React.createElement("div", { style: { width: 140, height: 36, display: 'flex', alignItems: 'center', gap: 6, padding: '0 12px' } }, /*#__PURE__*/React.createElement("svg", { width: "13", height: "13", viewBox: "0 0 13 13", fill: "none" }, /*#__PURE__*/React.createElement("circle", { cx: "5.5", cy: "5.5", r: "4", stroke: "#727272", strokeWidth: "1.5" }), /*#__PURE__*/React.createElement("path", { d: "M8.5 8.5l3 3", stroke: "#727272", strokeWidth: "1.5", strokeLinecap: "round" })), /*#__PURE__*/React.createElement("span", { style: { fontFamily: MAC_FONT, fontSize: 13, fontWeight: 500, color: '#727272' } }, "Search")))); } // ───────────────────────────────────────────────────────────── // Sidebar — frosted glass panel floating inside the window // ───────────────────────────────────────────────────────────── function MacSidebarItem({ label, selected = false }) { return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 6, height: 24, padding: '4px 10px 4px 6px', margin: '0 10px', borderRadius: 8, position: 'relative', fontFamily: MAC_FONT, fontSize: 11, fontWeight: 500 } }, selected && /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', inset: 0, borderRadius: 8, background: 'rgba(0,0,0,0.11)', mixBlendMode: 'multiply' } }), /*#__PURE__*/React.createElement("div", { style: { width: 14, height: 14, borderRadius: '50%', background: selected ? '#007aff' : 'rgba(0,0,0,0.4)', opacity: selected ? 1 : 0.5, flexShrink: 0, position: 'relative' } }), /*#__PURE__*/React.createElement("span", { style: { color: 'rgba(0,0,0,0.85)', position: 'relative' } }, label)); } function MacSidebar({ children }) { return /*#__PURE__*/React.createElement("div", { style: { width: 220, height: '100%', padding: 8, flexShrink: 0, position: 'relative', display: 'flex', flexDirection: 'column' } }, /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', inset: 8, borderRadius: 18, background: 'rgba(210,225,245,0.45)', backdropFilter: 'blur(50px) saturate(200%)', WebkitBackdropFilter: 'blur(50px) saturate(200%)', border: '0.5px solid rgba(255,255,255,0.5)', boxShadow: '0 8px 40px rgba(0,0,0,0.10), inset 0 1px 0 rgba(255,255,255,0.35)' } }), /*#__PURE__*/React.createElement("div", { style: { position: 'relative', zIndex: 1, padding: '10px 0', display: 'flex', flexDirection: 'column', gap: 2 } }, /*#__PURE__*/React.createElement("div", { style: { height: 32, display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 10px', marginBottom: 4 } }, /*#__PURE__*/React.createElement(MacTrafficLights, null)), children)); } function MacSidebarHeader({ title }) { return /*#__PURE__*/React.createElement("div", { style: { padding: '14px 18px 5px', fontFamily: MAC_FONT, fontSize: 11, fontWeight: 700, color: 'rgba(0,0,0,0.5)' } }, title); } // ───────────────────────────────────────────────────────────── // Window — r:26, big shadow, sidebar + toolbar + content // ───────────────────────────────────────────────────────────── function MacWindow({ width = 900, height = 600, title = 'Folder', sidebar, children }) { return /*#__PURE__*/React.createElement("div", { style: { width, height, borderRadius: 26, overflow: 'hidden', background: '#fff', boxShadow: '0 0 0 1px rgba(0,0,0,0.23), 0 16px 48px rgba(0,0,0,0.35)', display: 'flex', position: 'relative', fontFamily: MAC_FONT } }, /*#__PURE__*/React.createElement(MacSidebar, null, sidebar), /*#__PURE__*/React.createElement("div", { style: { flex: 1, display: 'flex', flexDirection: 'column' } }, /*#__PURE__*/React.createElement(MacToolbar, { title: title }), /*#__PURE__*/React.createElement("div", { style: { flex: 1, overflow: 'auto', padding: '4px 8px' } }, children))); } Object.assign(window, { MacWindow, MacSidebar, MacSidebarItem, MacSidebarHeader, MacToolbar, MacGlass, MacTrafficLights }); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/desktop/macos-window.jsx", error: String((e && e.message) || e) }); } // ui_kits/mobile/flows.jsx try { (() => { /* flows.jsx — 穿山甲 VPN mobile · auth, onboarding, redeem/buy */ const { useState: useStateF } = React; /* shared field */ function Field({ icon, label, children }) { return /*#__PURE__*/React.createElement("label", { style: { display: 'block' } }, /*#__PURE__*/React.createElement("span", { style: { display: 'block', fontSize: 12, fontWeight: 600, color: 'var(--fg2)', marginBottom: 7 } }, label), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 10, background: 'var(--surface)', border: '1.5px solid var(--border-strong)', borderRadius: 'var(--radius-md)', padding: '12px 14px' } }, icon && /*#__PURE__*/React.createElement(Icon, { name: icon, size: 18, color: "var(--fg3)" }), children)); } const inputStyle = { border: 'none', background: 'transparent', outline: 'none', flex: 1, fontFamily: 'var(--font-sans)', fontSize: 15, color: 'var(--fg1)', minWidth: 0 }; /* ───────── AUTH (login + email-code register) ───────── */ function AuthFlow({ t, lang, onDone }) { const [mode, setMode] = useStateF('login'); // login | register const [step, setStep] = useStateF(0); // register: 0 email+code, 1 set password const [email, setEmail] = useStateF(''); const [code, setCode] = useStateF(''); const [pw, setPw] = useStateF(''); const [sent, setSent] = useStateF(false); const [totp, setTotp] = useStateF(false); // 2FA step after login (PRO) const [otp, setOtp] = useStateF(''); const valid = /\S+@\S+\.\S+/.test(email); const tab = (id, label) => /*#__PURE__*/React.createElement("button", { onClick: () => { setMode(id); setStep(0); setSent(false); }, style: { flex: 1, border: 'none', cursor: 'pointer', background: 'transparent', padding: '10px 0', fontFamily: 'var(--font-sans)', fontSize: 15, fontWeight: mode === id ? 700 : 500, color: mode === id ? 'var(--fg1)' : 'var(--fg3)', borderBottom: mode === id ? '2px solid var(--accent)' : '2px solid transparent' } }, label); const primaryBtn = (label, onClick, enabled) => /*#__PURE__*/React.createElement("button", { onClick: enabled ? onClick : undefined, disabled: !enabled, style: { width: '100%', border: 'none', borderRadius: 'var(--radius-full)', padding: '14px', fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 15, cursor: enabled ? 'pointer' : 'not-allowed', background: 'var(--accent)', color: 'var(--fg-on-accent)', opacity: enabled ? 1 : 0.45, marginTop: 4 } }, label); return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', padding: '0 28px', background: 'var(--bg)' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12, paddingTop: 18, paddingBottom: 28 } }, /*#__PURE__*/React.createElement(Mark, { size: 56 }), /*#__PURE__*/React.createElement("div", { style: { textAlign: 'center' } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 24, color: 'var(--fg1)' } }, t('brand')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, color: 'var(--accent)', fontWeight: 600, letterSpacing: '0.04em', marginTop: 4 } }, t('authTagline')))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', borderBottom: '1px solid var(--border)', marginBottom: 22 } }, tab('login', t('tabLogin')), tab('register', t('tabRegister'))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 16, flex: 1 } }, mode === 'login' && !totp && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Field, { icon: "mail", label: t('emailLabel') }, /*#__PURE__*/React.createElement("input", { style: inputStyle, value: email, onChange: e => setEmail(e.target.value), placeholder: t('emailPh') })), /*#__PURE__*/React.createElement(Field, { icon: "lock", label: t('pwLabel') }, /*#__PURE__*/React.createElement("input", { style: inputStyle, type: "password", value: pw, onChange: e => setPw(e.target.value), placeholder: t('pwPh') })), /*#__PURE__*/React.createElement("div", { style: { textAlign: 'right', marginTop: -6 } }, /*#__PURE__*/React.createElement("span", { style: { fontSize: 13, color: 'var(--accent)', fontWeight: 600 } }, t('forgotPw'))), primaryBtn(t('doLogin'), () => setTotp(true), valid && pw.length > 0)), mode === 'login' && totp && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 8 } }, /*#__PURE__*/React.createElement(Icon, { name: "shield-check", size: 19, color: "var(--accent)" }), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 18, color: 'var(--fg1)' } }, t('twoFATitle')), /*#__PURE__*/React.createElement("span", { style: { fontSize: 10, fontWeight: 700, color: 'var(--accent)', background: 'var(--accent-subtle)', border: '1px solid var(--accent-border)', padding: '2px 8px', borderRadius: 999 } }, "PRO")), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, color: 'var(--fg3)', lineHeight: 1.6, marginTop: -6 } }, t('twoFAHint')), /*#__PURE__*/React.createElement(Field, { icon: "shield-check", label: t('twoFATitle') }, /*#__PURE__*/React.createElement("input", { style: { ...inputStyle, fontFamily: 'var(--font-mono)', fontSize: 20, letterSpacing: '0.5em', textAlign: 'center' }, value: otp, onChange: e => setOtp(e.target.value.replace(/\D/g, '').slice(0, 6)), placeholder: "\xB7\xB7\xB7\xB7\xB7\xB7" })), primaryBtn(t('twoFAConfirm'), onDone, otp.length === 6), /*#__PURE__*/React.createElement("div", { onClick: () => setTotp(false), style: { textAlign: 'center', fontSize: 12.5, color: 'var(--fg3)', cursor: 'pointer' } }, t('twoFABack'))), mode === 'register' && step === 0 && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Field, { icon: "mail", label: t('emailLabel') }, /*#__PURE__*/React.createElement("input", { style: inputStyle, value: email, onChange: e => setEmail(e.target.value), placeholder: t('emailPh') }), /*#__PURE__*/React.createElement("button", { onClick: () => valid && setSent(true), style: { border: 'none', background: 'transparent', cursor: valid ? 'pointer' : 'default', color: valid ? 'var(--accent)' : 'var(--fg3)', fontWeight: 700, fontSize: 13, whiteSpace: 'nowrap', flexShrink: 0 } }, sent ? t('resend') : t('sendCode'))), sent && /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--success)', marginTop: -8, display: 'flex', alignItems: 'center', gap: 6 } }, /*#__PURE__*/React.createElement(Icon, { name: "check-circle", size: 14, color: "var(--success)" }), t('codeSentTo'), " ", email), /*#__PURE__*/React.createElement(Field, { icon: "shield-check", label: t('codeLabel') }, /*#__PURE__*/React.createElement("input", { style: { ...inputStyle, fontFamily: 'var(--font-mono)', letterSpacing: '0.3em' }, value: code, onChange: e => setCode(e.target.value.replace(/\D/g, '').slice(0, 6)), placeholder: "\xB7\xB7\xB7\xB7\xB7\xB7" })), primaryBtn(t('doNext'), () => setStep(1), sent && code.length === 6)), mode === 'register' && step === 1 && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, color: 'var(--fg2)', display: 'flex', alignItems: 'center', gap: 7, marginBottom: -4 } }, /*#__PURE__*/React.createElement(Icon, { name: "check-circle", size: 15, color: "var(--success)" }), email), /*#__PURE__*/React.createElement(Field, { icon: "lock", label: t('pwLabel') }, /*#__PURE__*/React.createElement("input", { style: inputStyle, type: "password", value: pw, onChange: e => setPw(e.target.value), placeholder: t('setPwPh') })), primaryBtn(t('doCreate'), onDone, pw.length >= 6))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11, color: 'var(--fg3)', textAlign: 'center', lineHeight: 1.5, padding: '18px 8px 24px' } }, t('tos'))); } /* ───────── ONBOARDING (3 screens) ───────── */ function Onboarding({ t, lang, onDone }) { const [i, setI] = useStateF(0); const slides = [{ icon: 'globe', tint: 'var(--accent)', bg: 'var(--accent-subtle)', title: t('ob1Title'), sub: t('ob1Sub'), cta: t('obNext') }, { icon: 'shield', tint: 'var(--accent)', bg: 'var(--accent-subtle)', title: t('ob2Title'), sub: t('ob2Sub'), cta: t('obAllow') }, { icon: 'shield-check', tint: 'var(--success)', bg: 'var(--success-subtle)', title: t('ob3Title'), sub: t('ob3Sub'), cta: t('obStart') }]; const s = slides[i]; const next = () => i < 2 ? setI(i + 1) : onDone(); return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', padding: '0 28px', background: 'var(--bg)' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', justifyContent: 'flex-end', paddingTop: 10 } }, /*#__PURE__*/React.createElement("button", { onClick: onDone, style: { border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--fg3)', fontSize: 14, fontWeight: 600, padding: 8 } }, t('obSkip'))), /*#__PURE__*/React.createElement("div", { style: { flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 28, textAlign: 'center' } }, /*#__PURE__*/React.createElement("div", { style: { width: 120, height: 120, borderRadius: '50%', background: s.bg, display: 'flex', alignItems: 'center', justifyContent: 'center' } }, /*#__PURE__*/React.createElement(Icon, { name: s.icon, size: 52, stroke: 1.6, color: s.tint })), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 26, color: 'var(--fg1)' } }, s.title), /*#__PURE__*/React.createElement("div", { style: { fontSize: 15, color: 'var(--fg2)', lineHeight: 1.6, marginTop: 12, maxWidth: 280 } }, s.sub))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', justifyContent: 'center', gap: 8, marginBottom: 22 } }, slides.map((_, k) => /*#__PURE__*/React.createElement("div", { key: k, style: { width: k === i ? 22 : 7, height: 7, borderRadius: 999, background: k === i ? 'var(--accent)' : 'var(--border-strong)', transition: 'all 220ms var(--ease-out)' } }))), /*#__PURE__*/React.createElement("button", { onClick: next, style: { width: '100%', border: 'none', borderRadius: 'var(--radius-full)', padding: '15px', fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 15, cursor: 'pointer', background: 'var(--accent)', color: 'var(--fg-on-accent)', marginBottom: 26 } }, s.cta)); } /* ───────── REDEEM & BUY ───────── */ function RedeemScreen({ t, lang, onBack }) { const [code, setCode] = useStateF(''); const [ok, setOk] = useStateF(false); const channels = [{ icon: 'shopping-bag', name: t('chStore'), sub: t('chStoreSub'), accent: true }, { icon: 'credit-card', name: 'USDT (TRC20)', sub: t('chUsdtSub') }, { icon: 'send', name: 'Telegram', sub: t('chTgSub') }, { icon: 'message-circle', name: 'LINE', sub: t('chLineSub') }, { icon: 'mail', name: t('chEmail'), sub: t('chEmailSub') }]; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '6px 16px 14px' } }, /*#__PURE__*/React.createElement("button", { onClick: onBack, style: { border: 'none', background: 'transparent', cursor: 'pointer', padding: 6, display: 'flex' } }, /*#__PURE__*/React.createElement(Icon, { name: "arrow-left", size: 22, color: "var(--fg1)" })), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 18, color: 'var(--fg1)', whiteSpace: 'nowrap' } }, t('redeemTitle'))), /*#__PURE__*/React.createElement("div", { style: { flex: 1, overflow: 'auto', padding: '0 20px 20px' } }, /*#__PURE__*/React.createElement("div", { style: { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-sm)', padding: 18, marginBottom: 22 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14, fontWeight: 700, color: 'var(--fg1)', marginBottom: 12 } }, t('redeemCodeTitle')), ok ? /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 9, color: 'var(--success)', fontWeight: 600, fontSize: 15, padding: '6px 0' } }, /*#__PURE__*/React.createElement(Icon, { name: "check-circle", size: 20, color: "var(--success)" }), t('redeemOk')) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 10 } }, /*#__PURE__*/React.createElement("input", { value: code, onChange: e => setCode(e.target.value.toUpperCase()), placeholder: t('redeemPh'), style: { flex: 1, minWidth: 0, border: '1.5px solid var(--border-strong)', borderRadius: 'var(--radius-md)', padding: '12px 14px', fontFamily: 'var(--font-mono)', fontSize: 14, letterSpacing: '0.08em', color: 'var(--fg1)', background: 'var(--bg)', outline: 'none' } }), /*#__PURE__*/React.createElement("button", { onClick: () => code.length >= 4 && setOk(true), style: { border: 'none', borderRadius: 'var(--radius-md)', padding: '0 20px', background: 'var(--accent)', color: '#fff', fontWeight: 700, fontSize: 14, cursor: 'pointer', flexShrink: 0 } }, t('redeemBtn'))))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 14, fontWeight: 700, color: 'var(--fg1)', marginBottom: 6 } }, t('buyTitle')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, color: 'var(--fg3)', lineHeight: 1.5, marginBottom: 14 } }, t('buySub')), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 10 } }, channels.map(c => /*#__PURE__*/React.createElement("button", { key: c.name, style: { display: 'flex', alignItems: 'center', gap: 13, width: '100%', textAlign: 'left', cursor: 'pointer', background: c.accent ? 'var(--accent-subtle)' : 'var(--surface)', border: `1px solid ${c.accent ? 'var(--accent-border)' : 'var(--border)'}`, borderRadius: 'var(--radius-lg)', padding: '14px 16px', boxShadow: 'var(--shadow-sm)' } }, /*#__PURE__*/React.createElement("div", { style: { width: 40, height: 40, borderRadius: 'var(--radius-md)', background: c.accent ? 'var(--accent)' : 'var(--bg-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(Icon, { name: c.icon, size: 20, color: c.accent ? '#fff' : 'var(--accent)' })), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 15, fontWeight: 600, color: 'var(--fg1)' } }, c.name), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, color: 'var(--fg3)', fontFamily: c.icon === 'send' || c.icon === 'mail' || c.icon === 'message-circle' ? 'var(--font-mono)' : 'var(--font-sans)' } }, c.sub)), /*#__PURE__*/React.createElement(Icon, { name: "external-link", size: 17, color: "var(--fg3)" })))))); } /* ───────── PLANS (shown on upgrade) ───────── */ function PlansScreen({ t, lang, onBack, onChoose }) { const plans = [{ id: 'free', name: t('free'), price: '¥0', feats: t('feFree'), cta: t('current'), variant: 'cur' }, { id: 'pro', name: t('proPlan'), price: '¥25', feats: t('fePro'), cta: t('upgrade'), variant: 'pro' }, { id: 'team', name: t('team'), price: '¥99', feats: t('feTeam'), cta: t('choose'), variant: 'plain' }]; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '6px 16px 14px' } }, /*#__PURE__*/React.createElement("button", { onClick: onBack, style: { border: 'none', background: 'transparent', cursor: 'pointer', padding: 6, display: 'flex' } }, /*#__PURE__*/React.createElement(Icon, { name: "arrow-left", size: 22, color: "var(--fg1)" })), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 18, color: 'var(--fg1)', whiteSpace: 'nowrap' } }, t('choosePlan'))), /*#__PURE__*/React.createElement("div", { style: { flex: 1, overflow: 'auto', padding: '4px 20px 20px', display: 'flex', flexDirection: 'column', gap: 14 } }, plans.map(p => { const isPro = p.variant === 'pro'; return /*#__PURE__*/React.createElement("div", { key: p.id, style: { position: 'relative', borderRadius: 'var(--radius-xl)', padding: '18px 20px', ...(isPro ? { background: 'linear-gradient(155deg,var(--clay-600),var(--clay-800))', color: '#fff', boxShadow: 'var(--shadow-md)' } : { background: 'var(--surface)', border: '1px solid var(--border)', boxShadow: 'var(--shadow-sm)' }) } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14, fontWeight: 600, color: isPro ? '#fff' : 'var(--fg2)', opacity: isPro ? 0.9 : 1 } }, p.name, isPro && /*#__PURE__*/React.createElement("span", { style: { marginLeft: 8, fontSize: 10.5, fontWeight: 700, background: '#fff', color: 'var(--clay-700)', padding: '2px 8px', borderRadius: 999 } }, t('mostPopular'))), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 26, fontWeight: 700, color: isPro ? '#fff' : 'var(--fg1)' } }, p.price, /*#__PURE__*/React.createElement("span", { style: { fontSize: 12, fontWeight: 500, opacity: 0.7 } }, t('perMonth')))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexWrap: 'wrap', gap: '7px 16px', margin: '14px 0 16px' } }, p.feats.map((f, i) => /*#__PURE__*/React.createElement("div", { key: i, style: { display: 'flex', alignItems: 'center', gap: 7, fontSize: 12.5, color: isPro ? 'rgba(255,255,255,.92)' : 'var(--fg2)' } }, /*#__PURE__*/React.createElement(Icon, { name: "check", size: 14, color: isPro ? '#fff' : 'var(--success)', stroke: 2.4 }), f))), /*#__PURE__*/React.createElement("button", { onClick: p.variant !== 'cur' ? onChoose : undefined, style: { width: '100%', border: p.variant === 'cur' ? '1.5px solid var(--border-strong)' : 'none', cursor: p.variant === 'cur' ? 'default' : 'pointer', borderRadius: 'var(--radius-full)', padding: '12px', fontWeight: 700, fontSize: 14, background: isPro ? '#fff' : p.variant === 'cur' ? 'transparent' : 'var(--accent)', color: isPro ? 'var(--clay-700)' : p.variant === 'cur' ? 'var(--fg2)' : '#fff' } }, p.cta)); }))); } /* ───────── CONTACT US ───────── */ function ContactScreen({ t, lang, onBack }) { const channels = [{ icon: 'send', name: 'Telegram', sub: '@PangolinVPN_bot', accent: true }, { icon: 'message-circle', name: 'LINE', sub: '@pangolinvpn' }, { icon: 'mail', name: t('contactEmail'), sub: 'support@pangolin.vpn' }, { icon: 'shopping-bag', name: t('contactStore'), sub: 'shop.pangolin.vpn' }]; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 8, padding: '6px 16px 14px' } }, /*#__PURE__*/React.createElement("button", { onClick: onBack, style: { border: 'none', background: 'transparent', cursor: 'pointer', padding: 6, display: 'flex' } }, /*#__PURE__*/React.createElement(Icon, { name: "arrow-left", size: 22, color: "var(--fg1)" })), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 18, color: 'var(--fg1)', whiteSpace: 'nowrap' } }, t('contactTitle'))), /*#__PURE__*/React.createElement("div", { style: { flex: 1, overflow: 'auto', padding: '0 20px 20px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, color: 'var(--fg2)', lineHeight: 1.6, marginBottom: 16 } }, t('contactIntro')), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 18 } }, channels.map(c => /*#__PURE__*/React.createElement("button", { key: c.name, style: { display: 'flex', alignItems: 'center', gap: 13, width: '100%', textAlign: 'left', cursor: 'pointer', background: c.accent ? 'var(--accent-subtle)' : 'var(--surface)', border: `1px solid ${c.accent ? 'var(--accent-border)' : 'var(--border)'}`, borderRadius: 'var(--radius-lg)', padding: '14px 16px', boxShadow: 'var(--shadow-sm)' } }, /*#__PURE__*/React.createElement("div", { style: { width: 40, height: 40, borderRadius: 'var(--radius-md)', background: c.accent ? 'var(--accent)' : 'var(--bg-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(Icon, { name: c.icon, size: 20, color: c.accent ? '#fff' : 'var(--accent)' })), /*#__PURE__*/React.createElement("div", { style: { flex: 1, minWidth: 0 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 15, fontWeight: 600, color: 'var(--fg1)' } }, c.name), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, color: 'var(--fg3)', fontFamily: 'var(--font-mono)' } }, c.sub)), /*#__PURE__*/React.createElement(Icon, { name: "external-link", size: 17, color: "var(--fg3)" })))), /*#__PURE__*/React.createElement("div", { style: { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-sm)', padding: '14px 16px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, fontWeight: 600, color: 'var(--fg3)' } }, t('contactHoursTitle')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 14, fontWeight: 600, color: 'var(--fg1)', marginTop: 5, fontFamily: 'var(--font-mono)' } }, t('contactHours'))))); } Object.assign(window, { AuthFlow, Onboarding, RedeemScreen, PlansScreen, ContactScreen }); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/mobile/flows.jsx", error: String((e && e.message) || e) }); } // ui_kits/mobile/ios-frame.jsx try { (() => { /* BEGIN USAGE */ // iOS.jsx — Simplified iOS 26 (Liquid Glass) device frame // Based on the iOS 26 UI Kit + Figma status bar spec. No assets, no deps. // Exports (to window): IOSDevice, IOSStatusBar, IOSNavBar, IOSGlassPill, IOSList, IOSListRow, IOSKeyboard // // Usage — wrap your screen content in to get the bezel, status bar // and home indicator (props: title, dark, keyboard): // // // ...your screen content... // // /* END USAGE */ // ───────────────────────────────────────────────────────────── // Status bar // ───────────────────────────────────────────────────────────── function IOSStatusBar({ dark = false, time = '9:41' }) { const c = dark ? '#fff' : '#000'; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 154, alignItems: 'center', justifyContent: 'center', padding: '21px 24px 19px', boxSizing: 'border-box', position: 'relative', zIndex: 20, width: '100%' } }, /*#__PURE__*/React.createElement("div", { style: { flex: 1, height: 22, display: 'flex', alignItems: 'center', justifyContent: 'center', paddingTop: 1.5 } }, /*#__PURE__*/React.createElement("span", { style: { fontFamily: '-apple-system, "SF Pro", system-ui', fontWeight: 590, fontSize: 17, lineHeight: '22px', color: c } }, time)), /*#__PURE__*/React.createElement("div", { style: { flex: 1, height: 22, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, paddingTop: 1, paddingRight: 1 } }, /*#__PURE__*/React.createElement("svg", { width: "19", height: "12", viewBox: "0 0 19 12" }, /*#__PURE__*/React.createElement("rect", { x: "0", y: "7.5", width: "3.2", height: "4.5", rx: "0.7", fill: c }), /*#__PURE__*/React.createElement("rect", { x: "4.8", y: "5", width: "3.2", height: "7", rx: "0.7", fill: c }), /*#__PURE__*/React.createElement("rect", { x: "9.6", y: "2.5", width: "3.2", height: "9.5", rx: "0.7", fill: c }), /*#__PURE__*/React.createElement("rect", { x: "14.4", y: "0", width: "3.2", height: "12", rx: "0.7", fill: c })), /*#__PURE__*/React.createElement("svg", { width: "17", height: "12", viewBox: "0 0 17 12" }, /*#__PURE__*/React.createElement("path", { d: "M8.5 3.2C10.8 3.2 12.9 4.1 14.4 5.6L15.5 4.5C13.7 2.7 11.2 1.5 8.5 1.5C5.8 1.5 3.3 2.7 1.5 4.5L2.6 5.6C4.1 4.1 6.2 3.2 8.5 3.2Z", fill: c }), /*#__PURE__*/React.createElement("path", { d: "M8.5 6.8C9.9 6.8 11.1 7.3 12 8.2L13.1 7.1C11.8 5.9 10.2 5.1 8.5 5.1C6.8 5.1 5.2 5.9 3.9 7.1L5 8.2C5.9 7.3 7.1 6.8 8.5 6.8Z", fill: c }), /*#__PURE__*/React.createElement("circle", { cx: "8.5", cy: "10.5", r: "1.5", fill: c })), /*#__PURE__*/React.createElement("svg", { width: "27", height: "13", viewBox: "0 0 27 13" }, /*#__PURE__*/React.createElement("rect", { x: "0.5", y: "0.5", width: "23", height: "12", rx: "3.5", stroke: c, strokeOpacity: "0.35", fill: "none" }), /*#__PURE__*/React.createElement("rect", { x: "2", y: "2", width: "20", height: "9", rx: "2", fill: c }), /*#__PURE__*/React.createElement("path", { d: "M25 4.5V8.5C25.8 8.2 26.5 7.2 26.5 6.5C26.5 5.8 25.8 4.8 25 4.5Z", fill: c, fillOpacity: "0.4" })))); } // ───────────────────────────────────────────────────────────── // Liquid glass pill — blur + tint + shine // ───────────────────────────────────────────────────────────── function IOSGlassPill({ children, dark = false, style = {} }) { return /*#__PURE__*/React.createElement("div", { style: { height: 44, minWidth: 44, borderRadius: 9999, position: 'relative', overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: dark ? '0 2px 6px rgba(0,0,0,0.35), 0 6px 16px rgba(0,0,0,0.2)' : '0 1px 3px rgba(0,0,0,0.07), 0 3px 10px rgba(0,0,0,0.06)', ...style } }, /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', inset: 0, borderRadius: 9999, backdropFilter: 'blur(12px) saturate(180%)', WebkitBackdropFilter: 'blur(12px) saturate(180%)', background: dark ? 'rgba(120,120,128,0.28)' : 'rgba(255,255,255,0.5)' } }), /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', inset: 0, borderRadius: 9999, boxShadow: dark ? 'inset 1.5px 1.5px 1px rgba(255,255,255,0.15), inset -1px -1px 1px rgba(255,255,255,0.08)' : 'inset 1.5px 1.5px 1px rgba(255,255,255,0.7), inset -1px -1px 1px rgba(255,255,255,0.4)', border: dark ? '0.5px solid rgba(255,255,255,0.15)' : '0.5px solid rgba(0,0,0,0.06)' } }), /*#__PURE__*/React.createElement("div", { style: { position: 'relative', zIndex: 1, display: 'flex', alignItems: 'center', padding: '0 4px' } }, children)); } // ───────────────────────────────────────────────────────────── // Navigation bar — glass pills + large title // ───────────────────────────────────────────────────────────── function IOSNavBar({ title = 'Title', dark = false, trailingIcon = true }) { const muted = dark ? 'rgba(255,255,255,0.6)' : '#404040'; const text = dark ? '#fff' : '#000'; const pillIcon = content => /*#__PURE__*/React.createElement(IOSGlassPill, { dark: dark }, /*#__PURE__*/React.createElement("div", { style: { width: 36, height: 36, display: 'flex', alignItems: 'center', justifyContent: 'center' } }, content)); return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 10, paddingTop: 62, paddingBottom: 10, position: 'relative', zIndex: 5 } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 16px' } }, pillIcon(/*#__PURE__*/React.createElement("svg", { width: "12", height: "20", viewBox: "0 0 12 20", fill: "none", style: { marginLeft: -1 } }, /*#__PURE__*/React.createElement("path", { d: "M10 2L2 10l8 8", stroke: muted, strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }))), trailingIcon && pillIcon(/*#__PURE__*/React.createElement("svg", { width: "22", height: "6", viewBox: "0 0 22 6" }, /*#__PURE__*/React.createElement("circle", { cx: "3", cy: "3", r: "2.5", fill: muted }), /*#__PURE__*/React.createElement("circle", { cx: "11", cy: "3", r: "2.5", fill: muted }), /*#__PURE__*/React.createElement("circle", { cx: "19", cy: "3", r: "2.5", fill: muted })))), /*#__PURE__*/React.createElement("div", { style: { padding: '0 16px', fontFamily: '-apple-system, system-ui', fontSize: 34, fontWeight: 700, lineHeight: '41px', color: text, letterSpacing: 0.4 } }, title)); } // ───────────────────────────────────────────────────────────── // Grouped list (inset card, r:26) + row (52px) // ───────────────────────────────────────────────────────────── function IOSListRow({ title, detail, icon, chevron = true, isLast = false, dark = false }) { const text = dark ? '#fff' : '#000'; const sec = dark ? 'rgba(235,235,245,0.6)' : 'rgba(60,60,67,0.6)'; const ter = dark ? 'rgba(235,235,245,0.3)' : 'rgba(60,60,67,0.3)'; const sep = dark ? 'rgba(84,84,88,0.65)' : 'rgba(60,60,67,0.12)'; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', minHeight: 52, padding: '0 16px', position: 'relative', fontFamily: '-apple-system, system-ui', fontSize: 17, letterSpacing: -0.43 } }, icon && /*#__PURE__*/React.createElement("div", { style: { width: 30, height: 30, borderRadius: 7, background: icon, marginRight: 12, flexShrink: 0 } }), /*#__PURE__*/React.createElement("div", { style: { flex: 1, color: text } }, title), detail && /*#__PURE__*/React.createElement("span", { style: { color: sec, marginRight: 6 } }, detail), chevron && /*#__PURE__*/React.createElement("svg", { width: "8", height: "14", viewBox: "0 0 8 14", style: { flexShrink: 0 } }, /*#__PURE__*/React.createElement("path", { d: "M1 1l6 6-6 6", stroke: ter, strokeWidth: "2", fill: "none", strokeLinecap: "round", strokeLinejoin: "round" })), !isLast && /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', bottom: 0, right: 0, left: icon ? 58 : 16, height: 0.5, background: sep } })); } function IOSList({ header, children, dark = false }) { const hc = dark ? 'rgba(235,235,245,0.6)' : 'rgba(60,60,67,0.6)'; const bg = dark ? '#1C1C1E' : '#fff'; return /*#__PURE__*/React.createElement("div", null, header && /*#__PURE__*/React.createElement("div", { style: { fontFamily: '-apple-system, system-ui', fontSize: 13, color: hc, textTransform: 'uppercase', padding: '8px 36px 6px', letterSpacing: -0.08 } }, header), /*#__PURE__*/React.createElement("div", { style: { background: bg, borderRadius: 26, margin: '0 16px', overflow: 'hidden' } }, children)); } // ───────────────────────────────────────────────────────────── // Device frame // ───────────────────────────────────────────────────────────── function IOSDevice({ children, width = 402, height = 874, dark = false, title, keyboard = false }) { return /*#__PURE__*/React.createElement("div", { style: { width, height, borderRadius: 48, overflow: 'hidden', position: 'relative', background: dark ? '#000' : '#F2F2F7', boxShadow: '0 40px 80px rgba(0,0,0,0.18), 0 0 0 1px rgba(0,0,0,0.12)', fontFamily: '-apple-system, system-ui, sans-serif', WebkitFontSmoothing: 'antialiased' } }, /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', top: 11, left: '50%', transform: 'translateX(-50%)', width: 126, height: 37, borderRadius: 24, background: '#000', zIndex: 50 } }), /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', top: 0, left: 0, right: 0, zIndex: 10 } }, /*#__PURE__*/React.createElement(IOSStatusBar, { dark: dark })), /*#__PURE__*/React.createElement("div", { style: { height: '100%', display: 'flex', flexDirection: 'column' } }, title !== undefined && /*#__PURE__*/React.createElement(IOSNavBar, { title: title, dark: dark }), /*#__PURE__*/React.createElement("div", { style: { flex: 1, overflow: 'auto' } }, children), keyboard && /*#__PURE__*/React.createElement(IOSKeyboard, { dark: dark })), /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', bottom: 0, left: 0, right: 0, zIndex: 60, height: 34, display: 'flex', justifyContent: 'center', alignItems: 'flex-end', paddingBottom: 8, pointerEvents: 'none' } }, /*#__PURE__*/React.createElement("div", { style: { width: 139, height: 5, borderRadius: 100, background: dark ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.25)' } }))); } // ───────────────────────────────────────────────────────────── // Keyboard — iOS 26 liquid glass // ───────────────────────────────────────────────────────────── function IOSKeyboard({ dark = false }) { const glyph = dark ? 'rgba(255,255,255,0.7)' : '#595959'; const sugg = dark ? 'rgba(255,255,255,0.6)' : '#333'; const keyBg = dark ? 'rgba(255,255,255,0.22)' : 'rgba(255,255,255,0.85)'; // special-key icons const icons = { shift: /*#__PURE__*/React.createElement("svg", { width: "19", height: "17", viewBox: "0 0 19 17" }, /*#__PURE__*/React.createElement("path", { d: "M9.5 1L1 9.5h4.5V16h8V9.5H18L9.5 1z", fill: glyph })), del: /*#__PURE__*/React.createElement("svg", { width: "23", height: "17", viewBox: "0 0 23 17" }, /*#__PURE__*/React.createElement("path", { d: "M7 1h13a2 2 0 012 2v11a2 2 0 01-2 2H7l-6-7.5L7 1z", fill: "none", stroke: glyph, strokeWidth: "1.6", strokeLinejoin: "round" }), /*#__PURE__*/React.createElement("path", { d: "M10 5l7 7M17 5l-7 7", stroke: glyph, strokeWidth: "1.6", strokeLinecap: "round" })), ret: /*#__PURE__*/React.createElement("svg", { width: "20", height: "14", viewBox: "0 0 20 14" }, /*#__PURE__*/React.createElement("path", { d: "M18 1v6H4m0 0l4-4M4 7l4 4", fill: "none", stroke: "#fff", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" })) }; const key = (content, { w, flex, ret, fs = 25, k } = {}) => /*#__PURE__*/React.createElement("div", { key: k, style: { height: 42, borderRadius: 8.5, flex: flex ? 1 : undefined, width: w, minWidth: 0, background: ret ? '#08f' : keyBg, boxShadow: '0 1px 0 rgba(0,0,0,0.075)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: '-apple-system, "SF Compact", system-ui', fontSize: fs, fontWeight: 458, color: ret ? '#fff' : glyph } }, content); const row = (keys, pad = 0) => /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 6.5, justifyContent: 'center', padding: `0 ${pad}px` } }, keys.map(l => key(l, { flex: true, k: l }))); return /*#__PURE__*/React.createElement("div", { style: { position: 'relative', zIndex: 15, borderRadius: 27, overflow: 'hidden', padding: '11px 0 2px', display: 'flex', flexDirection: 'column', alignItems: 'center', boxShadow: dark ? '0 -2px 20px rgba(0,0,0,0.09)' : '0 -1px 6px rgba(0,0,0,0.018), 0 -3px 20px rgba(0,0,0,0.012)' } }, /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', inset: 0, borderRadius: 27, backdropFilter: 'blur(12px) saturate(180%)', WebkitBackdropFilter: 'blur(12px) saturate(180%)', background: dark ? 'rgba(120,120,128,0.14)' : 'rgba(255,255,255,0.25)' } }), /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', inset: 0, borderRadius: 27, boxShadow: dark ? 'inset 1.5px 1.5px 1px rgba(255,255,255,0.15)' : 'inset 1.5px 1.5px 1px rgba(255,255,255,0.7), inset -1px -1px 1px rgba(255,255,255,0.4)', border: dark ? '0.5px solid rgba(255,255,255,0.15)' : '0.5px solid rgba(0,0,0,0.06)', pointerEvents: 'none' } }), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 20, alignItems: 'center', padding: '8px 22px 13px', width: '100%', boxSizing: 'border-box', position: 'relative' } }, ['"The"', 'the', 'to'].map((w, i) => /*#__PURE__*/React.createElement(React.Fragment, { key: i }, i > 0 && /*#__PURE__*/React.createElement("div", { style: { width: 1, height: 25, background: '#ccc', opacity: 0.3 } }), /*#__PURE__*/React.createElement("div", { style: { flex: 1, textAlign: 'center', fontFamily: '-apple-system, system-ui', fontSize: 17, color: sugg, letterSpacing: -0.43, lineHeight: '22px' } }, w)))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 13, padding: '0 6.5px', width: '100%', boxSizing: 'border-box', position: 'relative' } }, row(['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p']), row(['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'], 20), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 14.25, alignItems: 'center' } }, key(icons.shift, { w: 45, k: 'shift' }), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 6.5, flex: 1 } }, ['z', 'x', 'c', 'v', 'b', 'n', 'm'].map(l => key(l, { flex: true, k: l }))), key(icons.del, { w: 45, k: 'del' })), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 6, alignItems: 'center' } }, key('ABC', { w: 92.25, fs: 18, k: 'abc' }), key('', { flex: true, k: 'space' }), key(icons.ret, { w: 92.25, ret: true, k: 'ret' }))), /*#__PURE__*/React.createElement("div", { style: { height: 56, width: '100%', position: 'relative' } })); } Object.assign(window, { IOSDevice, IOSStatusBar, IOSNavBar, IOSGlassPill, IOSList, IOSListRow, IOSKeyboard }); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/mobile/ios-frame.jsx", error: String((e && e.message) || e) }); } // ui_kits/mobile/parts.jsx try { (() => { /* parts.jsx — 穿山甲 VPN mobile · shared atoms Icon uses inline Lucide path data (lucide.dev) for reliability in React. */ const LUCIDE = { power: '', 'shield-check': '', globe: '', settings: '', 'chevron-right': '', 'chevron-down': '', check: '', zap: '', 'loader-circle': '', user: '', x: '', crown: '', 'map-pin': '', 'arrow-down': '', 'arrow-up': '', search: '', moon: '', sun: '', shield: '', 'refresh-cw': '', chart: '', wifi: '', mail: '', lock: '', 'arrow-left': '', 'shopping-bag': '', send: '', 'message-circle': '', 'external-link': '', 'check-circle': '', 'log-out': '', compass: '', laptop: '', smartphone: '', 'monitor-smartphone': '', ticket: '', clock: '', 'credit-card': '', 'play-circle': '' }; function Icon({ name, size = 24, stroke = 2, color = 'currentColor', style = {} }) { return /*#__PURE__*/React.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round", style: { display: 'block', flexShrink: 0, ...style }, dangerouslySetInnerHTML: { __html: LUCIDE[name] || '' } }); } /* Brand mark — walking pangolin (matches app icon), facing right */ function Mark({ size = 40, color = 'var(--accent)' }) { return /*#__PURE__*/React.createElement("svg", { width: size, height: size, viewBox: "0 0 96 96", fill: "none", style: { display: 'block' } }, /*#__PURE__*/React.createElement("g", { transform: "translate(96,0) scale(-1,1)" }, /*#__PURE__*/React.createElement("path", { d: "M16 59 Q17 51 26 50 Q34 31 45 30 Q55 30 62 37 Q69 41 75 45 Q85 49 89 44 Q92 50 84 52 Q75 53 67 53 Q66 62 60 62 L56 62 Q54 55 49 55 Q47 62 37 62 L33 62 Q31 56 26 56 Q20 59 16 59 Z", fill: color }), /*#__PURE__*/React.createElement("g", { stroke: "#fff", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", fill: "none", opacity: "0.5" }, /*#__PURE__*/React.createElement("path", { d: "M26 50 Q34 43 42 50" }), /*#__PURE__*/React.createElement("path", { d: "M36 48 Q44 41 52 48" }), /*#__PURE__*/React.createElement("path", { d: "M46 48 Q54 41 62 49" })), /*#__PURE__*/React.createElement("circle", { cx: "23", cy: "55", r: "2.2", fill: "#fff", opacity: "0.85" }))); } /* Country code tile */ function CC({ code, active }) { return /*#__PURE__*/React.createElement("div", { style: { width: 38, height: 38, borderRadius: 'var(--radius-md)', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--font-mono)', fontSize: 12, fontWeight: 600, background: active ? 'var(--accent)' : 'var(--bg-subtle)', color: active ? '#fff' : 'var(--fg2)' } }, code); } /* Signal bars from ping */ function Signal({ ping }) { const lvl = ping < 40 ? 3 : ping < 90 ? 2 : 1; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 2, alignItems: 'flex-end', height: 14 } }, [5, 9, 14].map((h, i) => /*#__PURE__*/React.createElement("div", { key: i, style: { width: 3, height: h, borderRadius: 1, background: i < lvl ? 'var(--success)' : 'var(--border-strong)' } }))); } /* Pill button */ function Pill({ children, variant = 'primary', onClick, style = {}, disabled }) { const v = { primary: { background: 'var(--accent)', color: 'var(--fg-on-accent)' }, secondary: { background: 'var(--surface)', color: 'var(--fg1)', border: '1.5px solid var(--border-strong)' }, ghost: { background: 'transparent', color: 'var(--accent)' }, danger: { background: 'var(--danger-subtle)', color: 'var(--danger)' } }[variant]; return /*#__PURE__*/React.createElement("button", { onClick: onClick, disabled: disabled, style: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8, fontFamily: 'var(--font-sans)', fontWeight: 600, fontSize: 15, border: 'none', borderRadius: 'var(--radius-full)', padding: '13px 22px', cursor: disabled ? 'not-allowed' : 'pointer', transition: 'all 140ms var(--ease-out)', opacity: disabled ? 0.5 : 1, ...v, ...style } }, children); } /* ───────── i18n ───────── Real product shows ONE language at a time (toggle in settings). Bilingual specimens only live in the design-system preview cards. */ const STRINGS = { brand: { zh: '穿山甲', en: 'Pangolin' }, online: { zh: '● 在线', en: '● Online' }, offline: { zh: '○ 离线', en: '○ Offline' }, capOff: { zh: '未连接 · 轻点连接', en: 'Tap to connect' }, capConnecting: { zh: '连接中…', en: 'Connecting…' }, capOn: { zh: '已连接 · 网络已加密', en: 'Connected · Encrypted' }, centerOff: { zh: 'TAP', en: 'TAP' }, download: { zh: '下载', en: 'Down' }, upload: { zh: '上传', en: 'Up' }, latency: { zh: '延迟', en: 'Ping' }, chooseNode: { zh: '选择节点', en: 'Choose server' }, search: { zh: '搜索国家 / 城市', en: 'Search country / city' }, tabConnect: { zh: '连接', en: 'Connect' }, tabServers: { zh: '节点', en: 'Servers' }, tabStats: { zh: '统计', en: 'Stats' }, tabMe: { zh: '我的', en: 'Account' }, connectNow: { zh: '点击连接', en: 'CONNECT' }, secure: { zh: '已加密', en: 'SECURE' }, statsTitle: { zh: '使用统计', en: 'Statistics' }, trafficMonth: { zh: '本月流量', en: 'Traffic' }, avgPing: { zh: '平均延迟', en: 'Avg ping' }, durMonth: { zh: '本月时长', en: 'Time' }, weekTraffic: { zh: '本周流量 (GB)', en: 'This week (GB)' }, days7: { zh: ['一', '二', '三', '四', '五', '六', '日'], en: ['M', 'T', 'W', 'T', 'F', 'S', 'S'] }, proMember: { zh: 'PRO 会员', en: 'PRO member' }, expires: { zh: '有效期至', en: 'Expires' }, usage: { zh: '本月用量', en: 'Used this month' }, smartRoute: { zh: '智能分流', en: 'Smart routing' }, smartRouteSub: { zh: '海外应用加速,本地直连', en: 'Accelerate overseas apps, keep local direct' }, killSwitch: { zh: 'Kill Switch', en: 'Kill Switch' }, killSwitchSub: { zh: '断线时阻断网络,防止泄露', en: 'Block traffic if the VPN drops' }, darkAppearance: { zh: '深色外观', en: 'Dark appearance' }, stateOn: { zh: '已开启', en: 'On' }, followLight: { zh: '跟随浅色', en: 'Off' }, protocol: { zh: '协议', en: 'Protocol' }, checkUpdate: { zh: '检查更新', en: 'Check for updates' }, language: { zh: '语言', en: 'Language' }, /* auth */ authTagline: { zh: '极速 · 稳定 · 省心', en: 'Fast · Stable · Effortless' }, tabLogin: { zh: '登录', en: 'Log in' }, tabRegister: { zh: '注册', en: 'Sign up' }, emailLabel: { zh: '邮箱', en: 'Email' }, emailPh: { zh: '你的邮箱地址', en: 'your@email.com' }, pwLabel: { zh: '密码', en: 'Password' }, pwPh: { zh: '输入密码', en: 'Enter password' }, setPwPh: { zh: '设置登录密码(用于多端登录)', en: 'Set a password (for multi-device login)' }, codeLabel: { zh: '邮箱验证码', en: 'Verification code' }, codeSentTo: { zh: '验证码已发送至', en: 'Code sent to' }, sendCode: { zh: '发送验证码', en: 'Send code' }, resend: { zh: '重新发送', en: 'Resend' }, doLogin: { zh: '登录', en: 'Log in' }, doNext: { zh: '下一步', en: 'Next' }, doCreate: { zh: '创建账户', en: 'Create account' }, forgotPw: { zh: '忘记密码?', en: 'Forgot password?' }, tos: { zh: '继续即代表同意《服务条款》与《隐私政策》', en: 'By continuing you agree to our Terms & Privacy Policy' }, stepEmail: { zh: '验证邮箱', en: 'Verify email' }, stepPw: { zh: '设置密码', en: 'Set password' }, /* onboarding */ obSkip: { zh: '跳过', en: 'Skip' }, obNext: { zh: '下一步', en: 'Next' }, obAllow: { zh: '允许并继续', en: 'Allow & continue' }, obStart: { zh: '开始使用', en: 'Get started' }, ob1Title: { zh: '一键连接全球', en: 'Connect worldwide' }, ob1Sub: { zh: '80+ 节点,智能选择最快线路,稳定不掉线。', en: '80+ locations, auto-fastest routing, rock-solid.' }, ob2Title: { zh: '授权网络配置', en: 'Allow network setup' }, ob2Sub: { zh: '系统会请求添加一个网络配置,用于建立加密隧道。', en: 'iOS will ask to add a network profile to build the encrypted tunnel.' }, ob3Title: { zh: '安全 · 无日志', en: 'Private by design' }, ob3Sub: { zh: '端到端加密,我们不记录你的任何浏览数据。', en: 'End-to-end encrypted. We keep zero browsing logs.' }, /* redeem & buy */ redeemEntry: { zh: '兑换 & 购买', en: 'Redeem & buy' }, redeemTitle: { zh: '兑换 & 购买', en: 'Redeem & buy' }, redeemCodeTitle: { zh: '兑换激活码', en: 'Redeem a code' }, redeemPh: { zh: '输入激活码', en: 'Enter activation code' }, redeemBtn: { zh: '激活', en: 'Activate' }, redeemOk: { zh: '激活成功 · PRO 已开通', en: 'Activated · PRO unlocked' }, buyTitle: { zh: '购买渠道', en: 'Where to buy' }, buySub: { zh: 'App 内不支持直接支付。请通过以下渠道获取激活码:', en: 'In-app payment is unavailable. Get an activation code via:' }, chStore: { zh: '自助发卡商店', en: 'Self-serve store' }, chStoreSub: { zh: '支付宝 / 微信 · 自动发码', en: 'Alipay / WeChat · instant code' }, chUsdtSub: { zh: '链上转账 · 最隐私 · 自动发码', en: 'On-chain · most private · instant code' }, chTgSub: { zh: '@PangolinVPN_bot', en: '@PangolinVPN_bot' }, chLineSub: { zh: '@pangolinvpn', en: '@pangolinvpn' }, chEmail: { zh: '邮箱', en: 'Email' }, chEmailSub: { zh: 'buy@pangolin.vpn', en: 'buy@pangolin.vpn' }, back: { zh: '返回', en: 'Back' }, replayAuth: { zh: '查看登录 / 注册流程', en: 'View login / sign-up' }, twoFA: { zh: '双重认证', en: 'Two-factor auth' }, twoFASub: { zh: 'PRO 专享 · 登录需身份验证器动态码', en: 'PRO only · TOTP code at login' }, twoFATitle: { zh: '双重认证', en: 'Two-factor auth' }, twoFAHint: { zh: '你的账户已开启双重认证。请输入身份验证器 App 中的 6 位动态码。', en: 'Two-factor auth is on for this account. Enter the 6-digit code from your authenticator app.' }, twoFAConfirm: { zh: '验证并登录', en: 'Verify & log in' }, twoFABack: { zh: '返回上一步', en: 'Back' }, ucEntry: { zh: 'Web 用户中心', en: 'Web account center' }, ucEntrySub: { zh: '订阅导入 · 邀请返利', en: 'Subscription import · referral' }, replayAuthSub: { zh: '演示用 · 退出到登录页', en: 'Demo · back to login' }, replayOnboarding: { zh: '查看首次引导', en: 'View onboarding' }, replayOnboardingSub: { zh: '演示用 · 重看 3 屏引导', en: 'Demo · replay the 3 intro screens' }, /* account management (integrated) */ meTitle: { zh: '我的', en: 'Account' }, curPlan: { zh: '当前套餐', en: 'Current plan' }, expires: { zh: '有效期至', en: 'Expires' }, upgradeBtn: { zh: '续费 / 升级', en: 'Renew / Upgrade' }, accInfoTitle: { zh: '账户信息', en: 'Account info' }, accEmail: { zh: '邮箱', en: 'Email' }, accPassword: { zh: '密码', en: 'Password' }, accChange: { zh: '修改', en: 'Change' }, accSignOut: { zh: '退出登录', en: 'Sign out' }, myDevices: { zh: '我的设备', en: 'My devices' }, devicesSub: { zh: 'PRO 套餐最多 5 台设备同时在线', en: 'Up to 5 devices on PRO' }, thisDevice: { zh: '当前设备', en: 'This device' }, lastActive: { zh: '最近活跃', en: 'Last active' }, remove: { zh: '移除', en: 'Remove' }, choosePlan: { zh: '选择套餐', en: 'Choose plan' }, free: { zh: '免费版', en: 'Free' }, proPlan: { zh: '专业版', en: 'Pro' }, team: { zh: '团队版', en: 'Team' }, perMonth: { zh: '/月', en: '/mo' }, current: { zh: '当前', en: 'Current' }, upgrade: { zh: '立即升级', en: 'Upgrade' }, choose: { zh: '选择', en: 'Choose' }, mostPopular: { zh: '最受欢迎', en: 'Popular' }, feFree: { zh: ['仅 1 个基础节点', '每日 10 分钟时长', '使用前观看广告', '注册享 7 天免费试用'], en: ['1 basic node only', '10 min per day', 'Watch an ad to start', '7-day free trial on sign-up'] }, fePro: { zh: ['80+ 全球节点', '无限流量 · 极速', '5 台设备同时在线', '流媒体优化'], en: ['80+ locations', 'Unlimited · fast', '5 devices', 'Streaming optimized'] }, feTeam: { zh: ['Pro 全部功能', '10 个成员席位', '集中计费与管理', '优先客服'], en: ['Everything in Pro', '10 seats', 'Central billing', 'Priority support'] }, /* contact */ contactEntry: { zh: '联系我们', en: 'Contact us' }, contactTitle: { zh: '联系我们', en: 'Contact us' }, contactIntro: { zh: '遇到问题?通过以下任一渠道联系我们,通常数分钟内回复。', en: 'Need help? Reach us via any channel below — usually replies in minutes.' }, contactEmail: { zh: '邮箱客服', en: 'Email support' }, contactStore: { zh: '自助发卡商店', en: 'Self-serve store' }, contactHoursTitle: { zh: '服务时间', en: 'Support hours' }, contactHours: { zh: '每日 9:00 – 24:00 (GMT+8)', en: 'Daily 9:00 – 24:00 (GMT+8)' }, devicesCount: { zh: '台设备', en: 'devices' }, /* smart select + quota (口径见 CLAUDE.md §7) */ smartSelect: { zh: '智能选择', en: 'Smart select' }, smartSub: { zh: '根据当前网络环境,自动选择最优节点', en: 'Picks the best node for your network' }, recommended: { zh: '推荐', en: 'Recommended' }, quotaToday: { zh: '今日剩余', en: 'Left today' }, minutes: { zh: '分钟', en: 'min' }, quotaFree: { zh: '免费版 · 每日 10 分钟', en: 'Free · 10 min/day' }, quotaTrial: { zh: '体验期 · 7 天免费使用', en: 'Trial · 7 days free' }, watchAd: { zh: '看广告开始使用', en: 'Watch ad to start' }, adUnlocked: { zh: '已解锁 · 今日可用', en: 'Unlocked for today' }, freePlanName: { zh: '免费版', en: 'Free' }, upgradeNow: { zh: '升级 PRO', en: 'Go PRO' }, freeDemo: { zh: '演示:免费版视角', en: 'Demo: free-tier view' }, freeDemoSub: { zh: '切换连接页的额度展示与套餐横幅', en: 'Toggles quota UI & plan banner' } }; function makeT(lang) { return k => STRINGS[k] && STRINGS[k][lang] || k; } /* localized server label */ function srvName(s, lang) { return lang === 'zh' ? s.name : s.en; } function srvSub(s, lang) { const tag = s.tags && s.tags[0]; if (lang === 'zh') return tag ? tag : s.en; return tag === '流媒体优化' ? 'Streaming' : tag === 'P2P' ? 'P2P' : s.name; } Object.assign(window, { Icon, Mark, CC, Signal, Pill, STRINGS, makeT, srvName, srvSub, SERVERS: [{ code: 'HK', name: '香港 · 流媒体', en: 'Hong Kong', ping: 18, tags: ['流媒体优化'] }, { code: 'JP', name: '日本 东京', en: 'Tokyo', ping: 32, tags: ['P2P'] }, { code: 'SG', name: '新加坡', en: 'Singapore', ping: 54, tags: ['P2P'] }, { code: 'TW', name: '台湾 台北', en: 'Taipei', ping: 28, tags: [] }, { code: 'US', name: '美国 洛杉矶', en: 'Los Angeles', ping: 146, tags: ['流媒体优化'] }, { code: 'DE', name: '德国 法兰克福', en: 'Frankfurt', ping: 198, tags: [] }, { code: 'UK', name: '英国 伦敦', en: 'London', ping: 210, tags: [] }, { code: 'KR', name: '韩国 首尔', en: 'Seoul', ping: 41, tags: [] }] }); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/mobile/parts.jsx", error: String((e && e.message) || e) }); } // ui_kits/mobile/screens.jsx try { (() => { /* screens.jsx — 穿山甲 VPN mobile · screens + bottom tab (i18n) */ const { useState, useEffect, useRef } = React; /* ───────── Top brand bar ───────── */ function TopBar({ t, lang, right }) { return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '6px 20px 14px' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 9 } }, /*#__PURE__*/React.createElement(Mark, { size: 28 }), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 18, color: 'var(--fg1)', letterSpacing: '-0.01em' } }, t('brand'))), right); } /* ───────── CONNECT screen ───────── */ function ConnectScreen({ t, lang, status, onToggle, server, smart, free, mins, adDone, onAd, goServers, elapsed }) { const map = { off: { fill: 'var(--sand-100)', fg: 'var(--clay-500)', icon: 'power', cap: t('capOff'), ring: 'track' }, connecting: { fill: 'var(--accent)', fg: '#fff', icon: 'loader-circle', cap: t('capConnecting'), ring: 'spin' }, on: { fill: 'var(--success)', fg: '#fff', icon: 'shield-check', cap: t('capOn'), ring: 'full' } }[status]; const fmt = s => `${String(Math.floor(s / 3600)).padStart(2, '0')}:${String(Math.floor(s % 3600 / 60)).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}`; const shadow = status === 'off' ? 'inset 0 0 0 1px var(--sand-200), var(--shadow-md)' : `0 0 0 9px ${status === 'on' ? 'var(--success-subtle)' : 'var(--accent-subtle)'}, var(--shadow-lg)`; // in-circle center block const center = status === 'off' ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 14 } }, t('connectNow'))) : status === 'connecting' ? /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontWeight: 700, fontSize: 14, letterSpacing: '0.08em' } }, "\xB7\xB7\xB7") : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontWeight: 600, fontSize: 18 } }, fmt(elapsed)), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 10, letterSpacing: '0.1em', opacity: .9 } }, t('secure'))); return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' } }, /*#__PURE__*/React.createElement(TopBar, { t: t, lang: lang, right: /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 12, whiteSpace: 'nowrap', color: status === 'on' ? 'var(--success)' : 'var(--fg3)', fontWeight: 600 } }, status === 'on' ? t('online') : t('offline')) }), /*#__PURE__*/React.createElement("div", { style: { flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 26, padding: '0 24px' } }, /*#__PURE__*/React.createElement("button", { onClick: onToggle, style: { position: 'relative', width: 208, height: 208, borderRadius: '50%', border: 'none', cursor: 'pointer', background: map.fill, color: map.fg, boxShadow: shadow, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 6, transition: 'box-shadow 300ms var(--ease-out), background-color 300ms var(--ease-out)' } }, /*#__PURE__*/React.createElement("svg", { viewBox: "0 0 208 208", style: { position: 'absolute', inset: 0, width: '100%', height: '100%', transformOrigin: 'center', animation: map.ring === 'spin' ? 'pg-spin 1.4s linear infinite' : 'none' } }, map.ring === 'track' && /*#__PURE__*/React.createElement("circle", { cx: "104", cy: "104", r: "96", fill: "none", stroke: "var(--sand-200)", strokeWidth: "3", strokeDasharray: "2 8", strokeLinecap: "round" }), map.ring === 'spin' && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("circle", { cx: "104", cy: "104", r: "96", fill: "none", stroke: "rgba(255,255,255,.3)", strokeWidth: "4" }), /*#__PURE__*/React.createElement("circle", { cx: "104", cy: "104", r: "96", fill: "none", stroke: "#fff", strokeWidth: "4", strokeLinecap: "round", strokeDasharray: "150 453" })), map.ring === 'full' && /*#__PURE__*/React.createElement("circle", { cx: "104", cy: "104", r: "96", fill: "none", stroke: "rgba(255,255,255,.85)", strokeWidth: "4", strokeLinecap: "round" })), /*#__PURE__*/React.createElement(Icon, { name: map.icon, size: 50, stroke: 1.7, style: status === 'connecting' ? { animation: 'pg-spin 1s linear infinite' } : {} }), center), /*#__PURE__*/React.createElement("div", { style: { textAlign: 'center' } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-sans)', fontSize: 15, fontWeight: 600, color: 'var(--fg2)', whiteSpace: 'nowrap' } }, map.cap))), /*#__PURE__*/React.createElement("div", { style: { padding: '0 20px 18px', display: 'flex', flexDirection: 'column', gap: 12 } }, free && /*#__PURE__*/React.createElement("div", { style: { background: 'var(--surface)', borderRadius: 'var(--radius-lg)', padding: '12px 14px', boxShadow: 'var(--shadow-sm)', border: '1px solid var(--border)' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 7, marginBottom: 8 } }, /*#__PURE__*/React.createElement(Icon, { name: "clock", size: 15, stroke: 2.2, color: "var(--accent)" }), /*#__PURE__*/React.createElement("span", { style: { fontSize: 12, fontWeight: 600, color: 'var(--fg2)' } }, t('quotaToday')), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 14, fontWeight: 600, color: 'var(--fg1)', whiteSpace: 'nowrap' } }, mins, " ", t('minutes')), /*#__PURE__*/React.createElement("span", { style: { marginLeft: 'auto', fontSize: 10.5, fontWeight: 600, color: 'var(--fg3)', background: 'var(--bg-subtle)', padding: '3px 9px', borderRadius: 'var(--radius-full)', whiteSpace: 'nowrap' } }, t('quotaFree'))), /*#__PURE__*/React.createElement("div", { style: { height: 6, background: 'var(--bg-subtle)', borderRadius: 3, overflow: 'hidden', marginBottom: 10 } }, /*#__PURE__*/React.createElement("div", { style: { width: `${Math.min(100, mins / 10 * 100)}%`, height: '100%', background: mins <= 3 ? 'var(--warning)' : 'var(--accent)', borderRadius: 3, transition: 'width 300ms var(--ease-out)' } })), adDone ? /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, color: 'var(--success)', fontWeight: 700, fontSize: 13, padding: '9px' } }, /*#__PURE__*/React.createElement(Icon, { name: "check-circle", size: 16, stroke: 2.2, color: "var(--success)" }), t('adUnlocked')) : /*#__PURE__*/React.createElement("button", { onClick: onAd, style: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, width: '100%', border: '1.5px solid var(--accent-border)', background: 'var(--accent-subtle)', color: 'var(--accent)', fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 13, padding: '9px', borderRadius: 'var(--radius-full)', cursor: 'pointer' } }, /*#__PURE__*/React.createElement(Icon, { name: "play-circle", size: 16, stroke: 2.2 }), t('watchAd'))), status === 'on' && /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 12 } }, [['arrow-down', t('download'), '86.4', 'Mb/s'], ['arrow-up', t('upload'), '12.1', 'Mb/s'], ['zap', t('latency'), String(server.ping), 'ms']].map(([ic, l, v, u]) => /*#__PURE__*/React.createElement("div", { key: l, style: { flex: 1, background: 'var(--surface)', borderRadius: 'var(--radius-lg)', padding: '12px 14px', boxShadow: 'var(--shadow-sm)', border: '1px solid var(--border)' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 5, color: 'var(--fg3)', fontSize: 11, fontWeight: 600, marginBottom: 4 } }, /*#__PURE__*/React.createElement(Icon, { name: ic, size: 13, stroke: 2.2, color: "var(--accent)" }), l), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 17, fontWeight: 500, color: 'var(--fg1)' } }, v, /*#__PURE__*/React.createElement("span", { style: { fontSize: 11, color: 'var(--fg3)' } }, " ", u))))), /*#__PURE__*/React.createElement("button", { onClick: goServers, style: { display: 'flex', alignItems: 'center', gap: 12, width: '100%', textAlign: 'left', background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', padding: '12px 14px', cursor: 'pointer', boxShadow: 'var(--shadow-sm)' } }, /*#__PURE__*/React.createElement(CC, { code: server.code, active: true }), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-sans)', fontSize: 15, fontWeight: 600, color: 'var(--fg1)', display: 'flex', alignItems: 'center', gap: 7 } }, smart ? t('smartSelect') : srvName(server, lang), smart && /*#__PURE__*/React.createElement(Icon, { name: "zap", size: 13, stroke: 2.4, color: "var(--accent)" })), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)' } }, smart ? `${srvName(server, lang)} · ${server.ping}ms` : `${srvSub(server, lang)} · ${server.ping}ms`)), /*#__PURE__*/React.createElement(Icon, { name: "chevron-right", size: 20, color: "var(--fg3)" })))); } /* ───────── SERVERS screen ───────── */ function ServersScreen({ t, lang, current, onPick, q, setQ }) { const list = SERVERS.filter(s => (s.name + s.en).toLowerCase().includes(q.toLowerCase())); return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' } }, /*#__PURE__*/React.createElement(TopBar, { t: t, lang: lang }), /*#__PURE__*/React.createElement("div", { style: { padding: '0 20px 12px' } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 24, fontWeight: 700, color: 'var(--fg1)', marginBottom: 12 } }, t('chooseNode')), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 10, background: 'var(--bg-subtle)', borderRadius: 'var(--radius-md)', padding: '10px 14px' } }, /*#__PURE__*/React.createElement(Icon, { name: "search", size: 18, color: "var(--fg3)" }), /*#__PURE__*/React.createElement("input", { value: q, onChange: e => setQ(e.target.value), placeholder: t('search'), style: { border: 'none', background: 'transparent', outline: 'none', flex: 1, fontFamily: 'var(--font-sans)', fontSize: 15, color: 'var(--fg1)' } }))), /*#__PURE__*/React.createElement("div", { style: { flex: 1, overflow: 'auto', padding: '0 20px 20px' } }, /*#__PURE__*/React.createElement("button", { onClick: () => onPick('AUTO'), style: { display: 'flex', alignItems: 'center', gap: 13, width: '100%', textAlign: 'left', padding: '15px 14px', border: `1.5px solid ${current === 'AUTO' ? 'var(--accent)' : 'var(--accent-border)'}`, cursor: 'pointer', background: 'var(--accent-subtle)', borderRadius: 'var(--radius-xl)', boxShadow: current === 'AUTO' ? 'var(--shadow-md)' : 'var(--shadow-sm)', marginBottom: 12 } }, /*#__PURE__*/React.createElement("div", { style: { width: 42, height: 42, borderRadius: 'var(--radius-md)', background: 'linear-gradient(150deg,var(--clay-500),var(--clay-700))', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(Icon, { name: "zap", size: 21, stroke: 2.2, color: "#fff" })), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 8 } }, /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-sans)', fontSize: 15.5, fontWeight: 700, color: 'var(--fg1)' } }, t('smartSelect')), /*#__PURE__*/React.createElement("span", { style: { fontSize: 10, fontWeight: 700, color: '#fff', background: 'var(--accent)', padding: '2px 8px', borderRadius: 999, letterSpacing: '0.04em' } }, t('recommended'))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg2)', marginTop: 3, lineHeight: 1.5 } }, t('smartSub'))), current === 'AUTO' && /*#__PURE__*/React.createElement(Icon, { name: "check", size: 19, color: "var(--accent)", stroke: 2.6 })), /*#__PURE__*/React.createElement("div", { style: { background: 'var(--surface)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-sm)', overflow: 'hidden', border: '1px solid var(--border)' } }, list.map((s, i) => { const active = s.code === current; return /*#__PURE__*/React.createElement("button", { key: s.code, onClick: () => onPick(s.code), style: { display: 'flex', alignItems: 'center', gap: 13, width: '100%', textAlign: 'left', padding: '12px 14px', border: 'none', cursor: 'pointer', borderBottom: i < list.length - 1 ? '1px solid var(--border)' : 'none', background: active ? 'var(--accent-subtle)' : 'transparent' } }, /*#__PURE__*/React.createElement(CC, { code: s.code, active: active }), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-sans)', fontSize: 15, fontWeight: 600, color: 'var(--fg1)' } }, srvName(s, lang)), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)' } }, srvSub(s, lang))), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--fg2)' } }, s.ping, "ms"), /*#__PURE__*/React.createElement(Signal, { ping: s.ping }), active && /*#__PURE__*/React.createElement(Icon, { name: "check", size: 18, color: "var(--accent)" })); })))); } /* ───────── SETTINGS screen ───────── */ function Toggle({ on, onChange }) { return /*#__PURE__*/React.createElement("div", { onClick: onChange, style: { width: 46, height: 28, borderRadius: 999, position: 'relative', cursor: 'pointer', flexShrink: 0, background: on ? 'var(--accent)' : 'var(--border-strong)', transition: 'background 220ms var(--ease-out)' } }, /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', top: 3, left: on ? 21 : 3, width: 22, height: 22, borderRadius: '50%', background: '#fff', boxShadow: 'var(--shadow-sm)', transition: 'left 220ms var(--ease-out)' } })); } /* segmented language switch 中 / EN */ function LangSwitch({ lang, setLang }) { return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', background: 'var(--bg-subtle)', borderRadius: 'var(--radius-full)', padding: 3, gap: 2 } }, [['zh', '中文'], ['en', 'EN']].map(([v, l]) => /*#__PURE__*/React.createElement("button", { key: v, onClick: () => setLang(v), style: { border: 'none', cursor: 'pointer', borderRadius: 'var(--radius-full)', padding: '5px 13px', fontFamily: 'var(--font-sans)', fontSize: 12.5, fontWeight: 700, background: lang === v ? 'var(--accent)' : 'transparent', color: lang === v ? 'var(--fg-on-accent)' : 'var(--fg3)', transition: 'all 140ms var(--ease-out)' } }, l))); } function Row({ icon, title, sub, right, last, onClick }) { return /*#__PURE__*/React.createElement("div", { onClick: onClick, style: { display: 'flex', alignItems: 'center', gap: 13, padding: '13px 16px', borderBottom: last ? 'none' : '1px solid var(--border)', cursor: onClick ? 'pointer' : 'default' } }, icon && /*#__PURE__*/React.createElement("div", { style: { width: 32, height: 32, borderRadius: 'var(--radius-sm)', background: 'var(--accent-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(Icon, { name: icon, size: 17, color: "var(--accent)", stroke: 2.2 })), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-sans)', fontSize: 15, fontWeight: 500, color: 'var(--fg1)' } }, title), sub && /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)' } }, sub)), right); } function SettingsScreen({ t, lang, setLang, dark, setDark, free, setFree, onRedeem, onUpgrade, onContact, onSignOut, onReplayAuth, onReplayOnboarding }) { const [autostart, setAuto] = useState(true); const [kill, setKill] = useState(true); const [twoFA, setTwoFA] = useState(true); const [devices, setDevices] = useState([{ id: 1, icon: 'laptop', name: 'MacBook Pro', os: 'macOS 26', active: t('thisDevice'), me: true }, { id: 2, icon: 'smartphone', name: 'iPhone 17', os: 'iOS 26', active: '2 min', me: false }, { id: 3, icon: 'monitor-smartphone', name: 'iPad Air', os: 'iPadOS 26', active: lang === 'zh' ? '3 小时前' : '3h ago', me: false }]); const card = { background: 'var(--surface)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-sm)', border: '1px solid var(--border)', overflow: 'hidden', marginBottom: 18 }; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' } }, /*#__PURE__*/React.createElement(TopBar, { t: t, lang: lang }), /*#__PURE__*/React.createElement("div", { style: { flex: 1, overflow: 'auto', padding: '0 20px 20px' } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 24, fontWeight: 700, color: 'var(--fg1)', marginBottom: 14 } }, t('meTitle')), /*#__PURE__*/React.createElement("div", { style: { background: 'linear-gradient(155deg,var(--clay-600),var(--clay-800))', borderRadius: 'var(--radius-xl)', padding: 18, color: '#fff', marginBottom: 18, boxShadow: 'var(--shadow-md)' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 11 } }, /*#__PURE__*/React.createElement("div", { style: { width: 44, height: 44, borderRadius: '50%', background: 'rgba(255,255,255,0.18)', display: 'flex', alignItems: 'center', justifyContent: 'center' } }, /*#__PURE__*/React.createElement(Icon, { name: "crown", size: 22, color: "#fff" })), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { fontWeight: 700, fontSize: 16 } }, "me@pangolin.vpn"), /*#__PURE__*/React.createElement("div", { style: { display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 11, fontWeight: 600, background: 'rgba(255,255,255,0.2)', padding: '2px 8px', borderRadius: 999, marginTop: 4 } }, free ? t('freePlanName') : t('proMember')))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginTop: 16, paddingTop: 14, borderTop: '1px solid rgba(255,255,255,0.18)', fontSize: 12 } }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { opacity: 0.7 } }, free ? t('quotaToday') : t('expires')), /*#__PURE__*/React.createElement("div", { style: { fontWeight: 600, marginTop: 2, fontFamily: 'var(--font-mono)', whiteSpace: 'nowrap' } }, free ? t('quotaFree') : '2026-12-31 · 42.6 GB')), /*#__PURE__*/React.createElement("button", { onClick: onUpgrade, style: { border: 'none', background: '#fff', color: 'var(--clay-700)', fontWeight: 700, fontSize: 13, padding: '9px 16px', borderRadius: 'var(--radius-full)', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 6 } }, /*#__PURE__*/React.createElement(Icon, { name: "ticket", size: 15, color: "var(--clay-700)" }), t('upgradeBtn')))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, fontWeight: 700, color: 'var(--fg2)', margin: '4px 4px 10px' } }, t('accInfoTitle')), /*#__PURE__*/React.createElement("div", { style: card }, /*#__PURE__*/React.createElement(Row, { icon: "mail", title: t('accEmail'), sub: "me@pangolin.vpn", right: /*#__PURE__*/React.createElement("span", { style: { fontSize: 13, color: 'var(--accent)', fontWeight: 600 } }, t('accChange')) }), /*#__PURE__*/React.createElement(Row, { icon: "lock", title: t('accPassword'), sub: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", right: /*#__PURE__*/React.createElement("span", { style: { fontSize: 13, color: 'var(--accent)', fontWeight: 600 } }, t('accChange')) }), /*#__PURE__*/React.createElement(Row, { icon: "shield", title: t('twoFA'), sub: t('twoFASub'), right: /*#__PURE__*/React.createElement(Toggle, { on: twoFA, onChange: () => setTwoFA(!twoFA) }), last: true })), /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, fontWeight: 700, color: 'var(--fg2)', margin: '4px 4px 4px' } }, t('myDevices')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11.5, color: 'var(--fg3)', margin: '0 4px 10px' } }, t('devicesSub')), /*#__PURE__*/React.createElement("div", { style: card }, devices.map((d, i) => /*#__PURE__*/React.createElement("div", { key: d.id, style: { display: 'flex', alignItems: 'center', gap: 12, padding: '12px 16px', borderBottom: i < devices.length - 1 ? '1px solid var(--border)' : 'none' } }, /*#__PURE__*/React.createElement("div", { style: { width: 34, height: 34, borderRadius: 'var(--radius-md)', background: 'var(--accent-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(Icon, { name: d.icon, size: 18, color: "var(--accent)" })), /*#__PURE__*/React.createElement("div", { style: { flex: 1, minWidth: 0 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14, fontWeight: 600, color: 'var(--fg1)', display: 'flex', alignItems: 'center', gap: 7 } }, d.name, d.me && /*#__PURE__*/React.createElement("span", { style: { fontSize: 10.5, fontWeight: 600, color: 'var(--success)', background: 'var(--success-subtle)', padding: '1px 7px', borderRadius: 999 } }, d.active)), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11.5, color: 'var(--fg3)', marginTop: 1 } }, d.os, !d.me && ` · ${d.active}`)), !d.me && /*#__PURE__*/React.createElement("button", { onClick: () => setDevices(devices.filter(x => x.id !== d.id)), style: { border: '1.5px solid var(--border-strong)', background: 'transparent', color: 'var(--fg2)', fontSize: 12.5, fontWeight: 600, padding: '6px 12px', borderRadius: 'var(--radius-full)', cursor: 'pointer' } }, t('remove'))))), /*#__PURE__*/React.createElement("div", { style: card }, /*#__PURE__*/React.createElement(Row, { icon: "shopping-bag", title: t('redeemEntry'), right: /*#__PURE__*/React.createElement(Icon, { name: "chevron-right", size: 18, color: "var(--fg3)" }), onClick: onRedeem }), /*#__PURE__*/React.createElement(Row, { icon: "external-link", title: t('ucEntry'), sub: t('ucEntrySub'), right: /*#__PURE__*/React.createElement(Icon, { name: "chevron-right", size: 18, color: "var(--fg3)" }), onClick: () => window.open('../usercenter/index.html', '_blank') }), /*#__PURE__*/React.createElement(Row, { icon: "message-circle", title: t('contactEntry'), right: /*#__PURE__*/React.createElement(Icon, { name: "chevron-right", size: 18, color: "var(--fg3)" }), last: true, onClick: onContact })), /*#__PURE__*/React.createElement("div", { style: card }, /*#__PURE__*/React.createElement(Row, { icon: "zap", title: t('smartRoute'), sub: t('smartRouteSub'), right: /*#__PURE__*/React.createElement(Toggle, { on: autostart, onChange: () => setAuto(!autostart) }) }), /*#__PURE__*/React.createElement(Row, { icon: "shield", title: t('killSwitch'), sub: t('killSwitchSub'), right: /*#__PURE__*/React.createElement(Toggle, { on: kill, onChange: () => setKill(!kill) }), last: true })), /*#__PURE__*/React.createElement("div", { style: card }, /*#__PURE__*/React.createElement(Row, { icon: "globe", title: t('language'), right: /*#__PURE__*/React.createElement(LangSwitch, { lang: lang, setLang: setLang }) }), /*#__PURE__*/React.createElement(Row, { icon: dark ? 'moon' : 'sun', title: t('darkAppearance'), sub: dark ? t('stateOn') : t('followLight'), right: /*#__PURE__*/React.createElement(Toggle, { on: dark, onChange: () => setDark(!dark) }) }), /*#__PURE__*/React.createElement(Row, { icon: "shield", title: t('protocol'), right: /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--fg3)' } }, "WireGuard") }), /*#__PURE__*/React.createElement(Row, { icon: "refresh-cw", title: t('checkUpdate'), right: /*#__PURE__*/React.createElement(Icon, { name: "chevron-right", size: 18, color: "var(--fg3)" }), last: true })), /*#__PURE__*/React.createElement("div", { style: card }, /*#__PURE__*/React.createElement(Row, { icon: "log-out", title: t('replayAuth'), sub: t('replayAuthSub'), right: /*#__PURE__*/React.createElement(Icon, { name: "chevron-right", size: 18, color: "var(--fg3)" }), onClick: onReplayAuth }), /*#__PURE__*/React.createElement(Row, { icon: "compass", title: t('replayOnboarding'), sub: t('replayOnboardingSub'), right: /*#__PURE__*/React.createElement(Icon, { name: "chevron-right", size: 18, color: "var(--fg3)" }), onClick: onReplayOnboarding }), /*#__PURE__*/React.createElement(Row, { icon: "clock", title: t('freeDemo'), sub: t('freeDemoSub'), right: /*#__PURE__*/React.createElement(Toggle, { on: free, onChange: () => setFree(!free) }), last: true })), /*#__PURE__*/React.createElement("div", { style: { textAlign: 'center', fontSize: 12, color: 'var(--fg3)', fontFamily: 'var(--font-mono)' } }, "\u7A7F\u5C71\u7532 \xB7 v2.4.0"))); } /* ───────── STATS screen ───────── */ function StatsScreen({ t, lang }) { const vals = [2.1, 3.4, 1.8, 4.6, 5.2, 6.1, 3.0]; const max = 6.1; const labels = t('days7'); const card = { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-sm)' }; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', height: '100%' } }, /*#__PURE__*/React.createElement(TopBar, { t: t, lang: lang }), /*#__PURE__*/React.createElement("div", { style: { flex: 1, overflow: 'auto', padding: '0 20px 20px' } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 24, fontWeight: 700, color: 'var(--fg1)', marginBottom: 16 } }, t('statsTitle')), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 12, marginBottom: 16 } }, [[t('trafficMonth'), '42.6', 'GB'], [t('avgPing'), '29', 'ms'], [t('durMonth'), '86.4', 'h']].map(([l, v, u]) => /*#__PURE__*/React.createElement("div", { key: l, style: { ...card, flex: 1, padding: '14px 14px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 11, color: 'var(--fg3)', fontWeight: 600 } }, l), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 20, fontWeight: 500, color: 'var(--fg1)', marginTop: 6 } }, v, /*#__PURE__*/React.createElement("span", { style: { fontSize: 11, color: 'var(--fg3)' } }, " ", u))))), /*#__PURE__*/React.createElement("div", { style: { ...card, padding: '18px 18px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, fontWeight: 600, color: 'var(--fg1)', marginBottom: 18 } }, t('weekTraffic')), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'flex-end', gap: 12, height: 120 } }, vals.map((v, i) => /*#__PURE__*/React.createElement("div", { key: i, style: { flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 7 } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg3)' } }, v), /*#__PURE__*/React.createElement("div", { style: { width: '100%', maxWidth: 30, height: `${v / max * 84}px`, background: 'var(--accent)', borderRadius: '6px 6px 0 0', opacity: 0.85 } }), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11, color: 'var(--fg3)' } }, labels[i]))))))); } /* ───────── Bottom tab ───────── */ function BottomTab({ t, tab, setTab }) { const items = [['connect', 'power', t('tabConnect')], ['servers', 'globe', t('tabServers')], ['stats', 'chart', t('tabStats')], ['me', 'user', t('tabMe')]]; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', borderTop: '1px solid var(--border)', background: 'var(--surface)', paddingBottom: 22 } }, items.map(([id, ic, label]) => { const a = tab === id; return /*#__PURE__*/React.createElement("button", { key: id, onClick: () => setTab(id), style: { flex: 1, border: 'none', background: 'transparent', cursor: 'pointer', padding: '10px 0 4px', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4 } }, /*#__PURE__*/React.createElement(Icon, { name: ic, size: 22, stroke: a ? 2.4 : 2, color: a ? 'var(--accent)' : 'var(--fg3)' }), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-sans)', fontSize: 11, fontWeight: a ? 700 : 500, color: a ? 'var(--accent)' : 'var(--fg3)' } }, label)); })); } Object.assign(window, { ConnectScreen, ServersScreen, StatsScreen, SettingsScreen, BottomTab, LangSwitch }); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/mobile/screens.jsx", error: String((e && e.message) || e) }); } // ui_kits/tablet/tabapp.jsx try { (() => { /* tabapp.jsx — 穿山甲 iPad 客户端 · 分栏布局 复用 ../mobile/parts.jsx 的 Icon/Mark/CC/Signal/SERVERS/makeT/srvName/srvSub。 仅 iPad 专属字串定义在本文件 TSTR。 */ const { useState, useEffect, useRef } = React; /* iPad 专属字串(双语单显) */ const TSTR = { navConnect: { zh: '连接', en: 'Connect' }, navNodes: { zh: '节点', en: 'Nodes' }, navStats: { zh: '统计', en: 'Stats' }, navAccount: { zh: '账户', en: 'Account' }, capOff: { zh: '未连接 · 轻点连接', en: 'Not connected · tap to start' }, capConnecting: { zh: '连接中 Connecting…', en: 'Connecting…' }, capOn: { zh: '已连接 · 网络已加密', en: 'Connected · traffic encrypted' }, download: { zh: '下载', en: 'Down' }, upload: { zh: '上传', en: 'Up' }, latency: { zh: '延迟', en: 'Ping' }, curNode: { zh: '当前节点', en: 'Current node' }, searchPh: { zh: '搜索国家 / 城市', en: 'Search country / city' }, statTraffic: { zh: '本月流量', en: 'Data this month' }, statPing: { zh: '平均延迟', en: 'Avg latency' }, statTime: { zh: '本月时长', en: 'Time this month' }, weekTraffic: { zh: '本周流量 (GB)', en: 'This week (GB)' }, days: { zh: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], en: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, acctEmail: { zh: '邮箱', en: 'Email' }, language: { zh: '语言', en: 'Language' }, darkMode: { zh: '深色外观', en: 'Dark appearance' }, smartRoute: { zh: '智能分流', en: 'Smart routing' }, smartRouteSub: { zh: '海外应用走加速,国内直连', en: 'Accelerate abroad, direct at home' }, killSwitch: { zh: 'Kill Switch', en: 'Kill Switch' }, killSub: { zh: '断线时阻断网络,防止泄露', en: 'Block traffic if the link drops' }, freeBanner: { zh: '免费版', en: 'Free plan' }, trialNote: { zh: '升级 PRO:不限时长 · 80+ 加速线路 · 5 台设备', en: 'Go PRO: unlimited time · 80+ routes · 5 devices' }, version: { zh: '穿山甲 · iPadOS · v2.4.0', en: 'Pangolin · iPadOS · v2.4.0' } }; function makeTT(lang) { return k => (TSTR[k] && TSTR[k][lang]) !== undefined ? TSTR[k][lang] : k; } function fmtHMS(s) { return `${String(Math.floor(s / 3600)).padStart(2, '0')}:${String(Math.floor(s % 3600 / 60)).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}`; } /* ── 左侧栏 ── */ function TabRail({ tt, view, setView, free, t }) { const items = [['connect', 'power', 'navConnect'], ['nodes', 'globe', 'navNodes'], ['stats', 'chart', 'navStats'], ['account', 'user', 'navAccount']]; return /*#__PURE__*/React.createElement("div", { style: { width: 232, flexShrink: 0, background: 'var(--bg-subtle)', borderRight: '1px solid var(--border)', display: 'flex', flexDirection: 'column', padding: '18px 14px 16px' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 10, padding: '0 8px 20px' } }, /*#__PURE__*/React.createElement(Mark, { size: 30 }), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 17, color: 'var(--fg1)', lineHeight: 1 } }, "\u7A7F\u5C71\u7532"), /*#__PURE__*/React.createElement("div", { style: { fontSize: 9, fontWeight: 600, letterSpacing: '0.2em', color: 'var(--accent)', marginTop: 3 } }, "PANGOLIN"))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 } }, items.map(([id, ic, lk]) => { const a = view === id; return /*#__PURE__*/React.createElement("button", { key: id, onClick: () => setView(id), style: { display: 'flex', alignItems: 'center', gap: 12, width: '100%', textAlign: 'left', border: 'none', cursor: 'pointer', background: a ? 'var(--accent-subtle)' : 'transparent', color: a ? 'var(--accent)' : 'var(--fg2)', padding: '13px 14px', borderRadius: 'var(--radius-md)', fontFamily: 'var(--font-sans)', fontSize: 15, fontWeight: a ? 700 : 500, transition: 'background-color 140ms var(--ease-out), color 140ms var(--ease-out)', minHeight: 48 } }, /*#__PURE__*/React.createElement(Icon, { name: ic, size: 20, stroke: a ? 2.4 : 2, color: a ? 'var(--accent)' : 'var(--fg3)' }), tt(lk)); })), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }), /*#__PURE__*/React.createElement("div", { style: { background: free ? 'var(--surface)' : 'linear-gradient(150deg,var(--clay-600),var(--clay-800))', border: free ? '1px solid var(--border)' : 'none', borderRadius: 'var(--radius-lg)', padding: '12px 13px', color: free ? 'var(--fg1)' : '#fff' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 9 } }, /*#__PURE__*/React.createElement("div", { style: { width: 32, height: 32, borderRadius: '50%', background: free ? 'var(--bg-subtle)' : 'rgba(255,255,255,0.18)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(Icon, { name: free ? 'user' : 'crown', size: 16, color: free ? 'var(--fg2)' : '#fff' })), /*#__PURE__*/React.createElement("div", { style: { minWidth: 0 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, fontWeight: 700, whiteSpace: 'nowrap' } }, free ? tt('freeBanner') : t('proMember')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 10.5, opacity: 0.65, whiteSpace: 'nowrap' } }, "me@pangolin.vpn"))))); } /* ── 连接视图:左大按钮 + 右信息列 ── */ function TabConnect({ t, tt, lang, status, onToggle, server, smart, free, mins, adDone, onAd, elapsed, goNodes }) { const map = { off: { ring: 'var(--border)', fill: 'var(--surface)', fg: 'var(--fg2)', icon: 'power', label: 'TAP', cap: tt('capOff') }, connecting: { ring: 'var(--accent-subtle)', fill: 'var(--accent)', fg: '#fff', icon: 'loader-circle', label: '···', cap: tt('capConnecting') }, on: { ring: 'var(--success-subtle)', fill: 'var(--success)', fg: '#fff', icon: 'shield-check', label: 'SAFE', cap: tt('capOn') } }[status]; const card = { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-sm)' }; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', height: '100%', alignItems: 'stretch' } }, /*#__PURE__*/React.createElement("div", { style: { flex: 1.25, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 26 } }, /*#__PURE__*/React.createElement("button", { onClick: onToggle, style: { width: 216, height: 216, borderRadius: '50%', border: 'none', cursor: 'pointer', background: map.fill, color: map.fg, boxShadow: `0 0 0 11px ${map.ring}, var(--shadow-lg)`, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 12, transition: 'box-shadow 300ms var(--ease-out), background-color 300ms var(--ease-out)' } }, /*#__PURE__*/React.createElement(Icon, { name: map.icon, size: 60, stroke: 1.6, style: status === 'connecting' ? { animation: 'pg-spin 1s linear infinite' } : {} }), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontWeight: 700, fontSize: 14, letterSpacing: '0.08em' } }, map.label)), /*#__PURE__*/React.createElement("div", { style: { textAlign: 'center' } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-sans)', fontSize: 16, fontWeight: 600, color: 'var(--fg2)', whiteSpace: 'nowrap' } }, map.cap), status === 'on' && /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 28, fontWeight: 500, color: 'var(--fg1)', marginTop: 8, letterSpacing: '-0.01em' } }, fmtHMS(elapsed)))), /*#__PURE__*/React.createElement("div", { style: { width: 332, flexShrink: 0, display: 'flex', flexDirection: 'column', gap: 14, justifyContent: 'center', paddingRight: 28 } }, free && /*#__PURE__*/React.createElement("div", { style: { ...card, padding: '14px 16px' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 8, marginBottom: 9 } }, /*#__PURE__*/React.createElement(Icon, { name: "clock", size: 15, stroke: 2.2, color: "var(--accent)" }), /*#__PURE__*/React.createElement("span", { style: { fontSize: 12.5, fontWeight: 600, color: 'var(--fg2)' } }, t('quotaToday')), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 14, fontWeight: 600, color: 'var(--fg1)', whiteSpace: 'nowrap' } }, mins, " ", t('minutes')), /*#__PURE__*/React.createElement("span", { style: { marginLeft: 'auto', fontSize: 10.5, fontWeight: 600, color: 'var(--fg3)', background: 'var(--bg-subtle)', padding: '3px 9px', borderRadius: 'var(--radius-full)', whiteSpace: 'nowrap' } }, t('quotaFree'))), /*#__PURE__*/React.createElement("div", { style: { height: 6, background: 'var(--bg-subtle)', borderRadius: 3, overflow: 'hidden', marginBottom: 11 } }, /*#__PURE__*/React.createElement("div", { style: { width: `${Math.min(100, mins / 10 * 100)}%`, height: '100%', background: mins <= 3 ? 'var(--warning)' : 'var(--accent)', borderRadius: 3 } })), adDone ? /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, color: 'var(--success)', fontWeight: 700, fontSize: 13, padding: '8px' } }, /*#__PURE__*/React.createElement(Icon, { name: "check-circle", size: 16, stroke: 2.2, color: "var(--success)" }), t('adUnlocked')) : /*#__PURE__*/React.createElement("button", { onClick: onAd, style: { display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, width: '100%', border: '1.5px solid var(--accent-border)', background: 'var(--accent-subtle)', color: 'var(--accent)', fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 13.5, padding: '10px', borderRadius: 'var(--radius-full)', cursor: 'pointer', minHeight: 44 } }, /*#__PURE__*/React.createElement(Icon, { name: "play-circle", size: 16, stroke: 2.2 }), t('watchAd'))), /*#__PURE__*/React.createElement("button", { onClick: goNodes, style: { ...card, display: 'flex', alignItems: 'center', gap: 13, textAlign: 'left', padding: '13px 15px', cursor: 'pointer', minHeight: 48 } }, /*#__PURE__*/React.createElement(CC, { code: server.code, active: true }), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 11, fontWeight: 600, color: 'var(--fg3)', marginBottom: 2 } }, tt('curNode')), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-sans)', fontSize: 15, fontWeight: 600, color: 'var(--fg1)', display: 'flex', alignItems: 'center', gap: 7 } }, smart ? t('smartSelect') : srvName(server, lang), smart && /*#__PURE__*/React.createElement(Icon, { name: "zap", size: 13, stroke: 2.4, color: "var(--accent)" })), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)' } }, smart ? `${srvName(server, lang)} · ${server.ping}ms` : `${srvSub(server, lang)} · ${server.ping}ms`)), /*#__PURE__*/React.createElement(Icon, { name: "chevron-right", size: 20, color: "var(--fg3)" })), status === 'on' && /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 10 } }, [['arrow-down', tt('download'), '86.4', 'Mb/s'], ['arrow-up', tt('upload'), '12.1', 'Mb/s'], ['zap', tt('latency'), String(server.ping), 'ms']].map(([ic, l, v, u]) => /*#__PURE__*/React.createElement("div", { key: ic, style: { ...card, flex: 1, padding: '11px 13px' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 5, color: 'var(--fg3)', fontSize: 11, fontWeight: 600, marginBottom: 4 } }, /*#__PURE__*/React.createElement(Icon, { name: ic, size: 13, stroke: 2.2, color: "var(--accent)" }), l), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 16, fontWeight: 500, color: 'var(--fg1)' } }, v, /*#__PURE__*/React.createElement("span", { style: { fontSize: 10.5, color: 'var(--fg3)' } }, " ", u))))))); } /* ── 节点视图 ── */ function TabNodes({ t, tt, lang, current, onPick }) { const [q, setQ] = useState(''); const list = SERVERS.filter(s => (s.name + s.en).toLowerCase().includes(q.toLowerCase())); const smartActive = current === 'AUTO'; return /*#__PURE__*/React.createElement("div", { style: { padding: '6px 28px 24px', overflow: 'auto', height: '100%', boxSizing: 'border-box' } }, /*#__PURE__*/React.createElement("button", { onClick: () => onPick('AUTO'), style: { display: 'flex', alignItems: 'center', gap: 13, width: '100%', textAlign: 'left', cursor: 'pointer', background: 'var(--accent-subtle)', border: `1.5px solid ${smartActive ? 'var(--accent)' : 'var(--accent-border)'}`, borderRadius: 'var(--radius-xl)', padding: '15px 16px', boxShadow: smartActive ? 'var(--shadow-md)' : 'var(--shadow-sm)', marginBottom: 14, minHeight: 56 } }, /*#__PURE__*/React.createElement("div", { style: { width: 42, height: 42, borderRadius: 'var(--radius-md)', background: 'linear-gradient(150deg,var(--clay-500),var(--clay-700))', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(Icon, { name: "zap", size: 21, stroke: 2.2, color: "#fff" })), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 8 } }, /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-sans)', fontSize: 15.5, fontWeight: 700, color: 'var(--fg1)' } }, t('smartSelect')), /*#__PURE__*/React.createElement("span", { style: { fontSize: 10, fontWeight: 700, color: '#fff', background: 'var(--accent)', padding: '2px 8px', borderRadius: 999, letterSpacing: '0.04em' } }, t('recommended'))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg2)', marginTop: 3 } }, t('smartSub'))), smartActive && /*#__PURE__*/React.createElement(Icon, { name: "check", size: 19, color: "var(--accent)", stroke: 2.6 })), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 10, background: 'var(--bg-subtle)', borderRadius: 'var(--radius-md)', padding: '11px 14px', marginBottom: 14, maxWidth: 380 } }, /*#__PURE__*/React.createElement(Icon, { name: "search", size: 18, color: "var(--fg3)" }), /*#__PURE__*/React.createElement("input", { value: q, onChange: e => setQ(e.target.value), placeholder: tt('searchPh'), style: { border: 'none', background: 'transparent', outline: 'none', flex: 1, fontFamily: 'var(--font-sans)', fontSize: 14.5, color: 'var(--fg1)' } })), /*#__PURE__*/React.createElement("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 11 } }, list.map(s => { const active = s.code === current; return /*#__PURE__*/React.createElement("button", { key: s.code, onClick: () => onPick(s.code), style: { display: 'flex', alignItems: 'center', gap: 12, textAlign: 'left', cursor: 'pointer', background: active ? 'var(--accent-subtle)' : 'var(--surface)', border: `1.5px solid ${active ? 'var(--accent-border)' : 'var(--border)'}`, borderRadius: 'var(--radius-lg)', padding: '13px 15px', boxShadow: 'var(--shadow-sm)', minHeight: 56 } }, /*#__PURE__*/React.createElement(CC, { code: s.code, active: active }), /*#__PURE__*/React.createElement("div", { style: { flex: 1, minWidth: 0 } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-sans)', fontSize: 14.5, fontWeight: 600, color: 'var(--fg1)' } }, srvName(s, lang)), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } }, srvSub(s, lang))), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 5 } }, /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--fg2)' } }, s.ping, "ms"), /*#__PURE__*/React.createElement(Signal, { ping: s.ping })), active && /*#__PURE__*/React.createElement(Icon, { name: "check", size: 18, color: "var(--accent)" })); }))); } /* ── 统计视图 ── */ function TabStats({ tt, lang }) { const vals = [2.1, 3.4, 1.8, 4.6, 5.2, 6.1, 3.0]; const days = TSTR.days[lang]; const max = Math.max(...vals); const card = { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-sm)' }; return /*#__PURE__*/React.createElement("div", { style: { padding: '6px 28px 24px', overflow: 'auto', height: '100%', boxSizing: 'border-box' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 14, marginBottom: 20 } }, [[tt('statTraffic'), '42.6 GB'], [tt('statPing'), '29 ms'], [tt('statTime'), '86.4 h']].map(([l, v]) => /*#__PURE__*/React.createElement("div", { key: l, style: { ...card, flex: 1, padding: '18px 20px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, color: 'var(--fg3)', fontWeight: 600 } }, l), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 26, fontWeight: 500, color: 'var(--fg1)', marginTop: 7 } }, v)))), /*#__PURE__*/React.createElement("div", { style: { ...card, padding: '20px 22px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 13.5, fontWeight: 600, color: 'var(--fg1)', marginBottom: 20 } }, tt('weekTraffic')), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'flex-end', gap: 22, height: 150 } }, vals.map((v, i) => /*#__PURE__*/React.createElement("div", { key: i, style: { flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 9 } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 10.5, color: 'var(--fg3)' } }, v), /*#__PURE__*/React.createElement("div", { style: { width: '100%', maxWidth: 40, height: `${v / max * 104}px`, background: 'var(--accent)', borderRadius: '6px 6px 0 0', opacity: 0.85 } }), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11.5, color: 'var(--fg3)' } }, days[i])))))); } /* ── 账户视图 ── */ function TabToggle({ on, onChange }) { return /*#__PURE__*/React.createElement("div", { onClick: onChange, style: { width: 48, height: 29, borderRadius: 999, position: 'relative', cursor: 'pointer', flexShrink: 0, background: on ? 'var(--accent)' : 'var(--border-strong)', transition: 'background 220ms var(--ease-out)' } }, /*#__PURE__*/React.createElement("div", { style: { position: 'absolute', top: 3, left: on ? 22 : 3, width: 23, height: 23, borderRadius: '50%', background: '#fff', boxShadow: 'var(--shadow-sm)', transition: 'left 220ms var(--ease-out)' } })); } function TabAccount({ t, tt, lang, setLang, dark, setDark, free, setFree }) { const [smartRoute, setSmartRoute] = useState(true); const [kill, setKill] = useState(true); const card = { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-sm)', overflow: 'hidden', marginBottom: 16 }; const Row = ({ icon, title, sub, right, last }) => /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 13, padding: '15px 18px', borderBottom: last ? 'none' : '1px solid var(--border)', minHeight: 48, boxSizing: 'border-box' } }, icon && /*#__PURE__*/React.createElement("div", { style: { width: 34, height: 34, borderRadius: 'var(--radius-sm)', background: 'var(--accent-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(Icon, { name: icon, size: 17, color: "var(--accent)", stroke: 2.2 })), /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 15, fontWeight: 500, color: 'var(--fg1)' } }, title), sub && /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)', marginTop: 2 } }, sub)), right); const seg = val => ({ border: 'none', cursor: 'pointer', padding: '7px 16px', borderRadius: 'var(--radius-full)', fontFamily: 'var(--font-sans)', fontSize: 13, fontWeight: 600, minHeight: 32, background: lang === val ? 'var(--surface)' : 'transparent', color: lang === val ? 'var(--fg1)' : 'var(--fg3)', boxShadow: lang === val ? 'var(--shadow-sm)' : 'none' }); return /*#__PURE__*/React.createElement("div", { style: { padding: '6px 28px 24px', overflow: 'auto', height: '100%', boxSizing: 'border-box', maxWidth: 640 } }, /*#__PURE__*/React.createElement("div", { style: { background: free ? 'var(--surface)' : 'linear-gradient(155deg,var(--clay-600),var(--clay-800))', border: free ? '1px solid var(--border)' : 'none', borderRadius: 'var(--radius-xl)', padding: 20, color: free ? 'var(--fg1)' : '#fff', marginBottom: 18, boxShadow: 'var(--shadow-md)' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 12 } }, /*#__PURE__*/React.createElement("div", { style: { width: 46, height: 46, borderRadius: '50%', background: free ? 'var(--bg-subtle)' : 'rgba(255,255,255,0.18)', display: 'flex', alignItems: 'center', justifyContent: 'center' } }, /*#__PURE__*/React.createElement(Icon, { name: free ? 'user' : 'crown', size: 22, color: free ? 'var(--fg2)' : '#fff' })), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontWeight: 700, fontSize: 16.5 } }, "me@pangolin.vpn"), /*#__PURE__*/React.createElement("div", { style: { display: 'inline-block', fontSize: 11, fontWeight: 600, background: free ? 'var(--bg-subtle)' : 'rgba(255,255,255,0.2)', color: free ? 'var(--fg2)' : '#fff', padding: '2px 9px', borderRadius: 999, marginTop: 5 } }, free ? tt('freeBanner') : t('proMember')))), /*#__PURE__*/React.createElement("div", { style: { marginTop: 14, paddingTop: 13, borderTop: `1px solid ${free ? 'var(--border)' : 'rgba(255,255,255,0.18)'}`, fontSize: 12.5, opacity: free ? 1 : 0.92, color: free ? 'var(--fg2)' : '#fff' } }, free ? tt('trialNote') : '2026-12-31 · 42.6 GB')), /*#__PURE__*/React.createElement("div", { style: card }, /*#__PURE__*/React.createElement(Row, { icon: "zap", title: tt('smartRoute'), sub: tt('smartRouteSub'), right: /*#__PURE__*/React.createElement(TabToggle, { on: smartRoute, onChange: () => setSmartRoute(!smartRoute) }) }), /*#__PURE__*/React.createElement(Row, { icon: "shield", title: tt('killSwitch'), sub: tt('killSub'), right: /*#__PURE__*/React.createElement(TabToggle, { on: kill, onChange: () => setKill(!kill) }), last: true })), /*#__PURE__*/React.createElement("div", { style: card }, /*#__PURE__*/React.createElement(Row, { icon: "globe", title: tt('language'), right: /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 4, background: 'var(--bg-subtle)', borderRadius: 'var(--radius-full)', padding: 3 } }, /*#__PURE__*/React.createElement("button", { style: seg('zh'), onClick: () => setLang('zh') }, "\u4E2D\u6587"), /*#__PURE__*/React.createElement("button", { style: seg('en'), onClick: () => setLang('en') }, "EN")) }), /*#__PURE__*/React.createElement(Row, { icon: dark ? 'moon' : 'sun', title: tt('darkMode'), right: /*#__PURE__*/React.createElement(TabToggle, { on: dark, onChange: () => setDark(!dark) }) }), /*#__PURE__*/React.createElement(Row, { icon: "clock", title: t('freeDemo'), sub: t('freeDemoSub'), right: /*#__PURE__*/React.createElement(TabToggle, { on: free, onChange: () => setFree(!free) }), last: true })), /*#__PURE__*/React.createElement("div", { style: { textAlign: 'center', fontSize: 12, color: 'var(--fg3)', fontFamily: 'var(--font-mono)' } }, tt('version'))); } /* ── iPad 外壳 + 应用 ── */ function TabletApp() { const [view, setView] = useState('connect'); const [status, setStatus] = useState('off'); const [code, setCode] = useState('AUTO'); const [lang, setLang] = useState('zh'); const [dark, setDark] = useState(false); const [free, setFree] = useState(true); const [mins, setMins] = useState(6); const [adDone, setAdDone] = useState(false); const [elapsed, setElapsed] = useState(0); const timer = useRef(null); const t = makeT(lang), tt = makeTT(lang); const smart = code === 'AUTO'; const server = smart ? SERVERS.reduce((a, b) => a.ping < b.ping ? a : b) : SERVERS.find(s => s.code === code); const titles = { connect: tt('navConnect'), nodes: tt('navNodes'), stats: tt('navStats'), account: tt('navAccount') }; function toggle() { if (status === 'off') { setStatus('connecting'); setTimeout(() => { setStatus('on'); setElapsed(0); }, 1500); } else setStatus('off'); } function pick(c) { setCode(c); setView('connect'); if (status === 'on') { setStatus('connecting'); setTimeout(() => { setStatus('on'); setElapsed(0); }, 1200); } } useEffect(() => { if (status === 'on') timer.current = setInterval(() => setElapsed(e => e + 1), 1000); return () => clearInterval(timer.current); }, [status]); let main; if (view === 'connect') main = /*#__PURE__*/React.createElement(TabConnect, { t: t, tt: tt, lang: lang, status: status, onToggle: toggle, server: server, smart: smart, free: free, mins: mins, adDone: adDone, onAd: () => setAdDone(true), elapsed: elapsed, goNodes: () => setView('nodes') });else if (view === 'nodes') main = /*#__PURE__*/React.createElement(TabNodes, { t: t, tt: tt, lang: lang, current: code, onPick: pick });else if (view === 'stats') main = /*#__PURE__*/React.createElement(TabStats, { tt: tt, lang: lang });else main = /*#__PURE__*/React.createElement(TabAccount, { t: t, tt: tt, lang: lang, setLang: setLang, dark: dark, setDark: setDark, free: free, setFree: setFree }); return /*#__PURE__*/React.createElement("div", { style: { background: '#1a1714', borderRadius: 34, padding: 16, boxShadow: '0 0 0 1px rgba(0,0,0,0.3), 0 30px 80px rgba(0,0,0,0.45)' } }, /*#__PURE__*/React.createElement("div", { "data-theme": dark ? 'dark' : 'light', style: { width: 1180, height: 820, borderRadius: 20, overflow: 'hidden', background: 'var(--bg)', display: 'flex', flexDirection: 'column', fontFamily: 'var(--font-sans)', position: 'relative' } }, /*#__PURE__*/React.createElement("div", { style: { height: 30, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 22px', fontFamily: 'var(--font-sans)', fontSize: 12.5, fontWeight: 600, color: 'var(--fg1)' } }, /*#__PURE__*/React.createElement("span", null, "9:41"), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 8 } }, /*#__PURE__*/React.createElement(Icon, { name: "wifi", size: 15, stroke: 2.2, color: "var(--fg1)" }), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 11.5 } }, "87%"), /*#__PURE__*/React.createElement("div", { style: { width: 24, height: 12, border: '1.5px solid var(--fg2)', borderRadius: 3.5, padding: 1.5, boxSizing: 'border-box' } }, /*#__PURE__*/React.createElement("div", { style: { width: '80%', height: '100%', background: 'var(--fg1)', borderRadius: 1.5 } })))), /*#__PURE__*/React.createElement("div", { style: { flex: 1, minHeight: 0, display: 'flex' } }, /*#__PURE__*/React.createElement(TabRail, { tt: tt, view: view, setView: setView, free: free, t: t }), /*#__PURE__*/React.createElement("div", { style: { flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column' } }, /*#__PURE__*/React.createElement("div", { style: { height: 56, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 28px' } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 19, color: 'var(--fg1)' } }, titles[view]), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 12.5, fontWeight: 600, color: status === 'on' ? 'var(--success)' : 'var(--fg3)', whiteSpace: 'nowrap' } }, status === 'on' ? '● ' + server.code : '○')), /*#__PURE__*/React.createElement("div", { style: { flex: 1, minHeight: 0 } }, main))))); } Object.assign(window, { TabletApp }); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/tablet/tabapp.jsx", error: String((e && e.message) || e) }); } // ui_kits/usercenter/ucapp.jsx try { (() => { /* ucapp.jsx — 穿山甲 Web 用户中心 · views */ const { useState: useStateU } = React; const ucCard = { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--radius-xl)', boxShadow: 'var(--shadow-sm)' }; const ucInput = { border: '1.5px solid var(--border-strong)', borderRadius: 'var(--radius-md)', padding: '12px 14px', fontFamily: 'var(--font-sans)', fontSize: 14.5, color: 'var(--fg1)', background: 'var(--surface)', outline: 'none', width: '100%', boxSizing: 'border-box' }; /* viewport hook — mobile ≤ 700px */ function useIsMobileUC() { const [m, setM] = useStateU(typeof window !== 'undefined' && window.innerWidth <= 700); React.useEffect(() => { const f = () => setM(window.innerWidth <= 700); window.addEventListener('resize', f); return () => window.removeEventListener('resize', f); }, []); return m; } function UCLang({ lang, setLang }) { return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', background: 'var(--bg-subtle)', borderRadius: 999, padding: 3, gap: 2 } }, [['zh', '中文'], ['en', 'EN']].map(([v, l]) => /*#__PURE__*/React.createElement("button", { key: v, onClick: () => setLang(v), style: { border: 'none', cursor: 'pointer', borderRadius: 999, padding: '5px 12px', fontFamily: 'var(--font-sans)', fontSize: 12.5, fontWeight: 700, background: lang === v ? 'var(--accent)' : 'transparent', color: lang === v ? 'var(--fg-on-accent)' : 'var(--fg3)' } }, l))); } /* ───────── Login (+ PRO 2FA step) ───────── */ function UCLogin({ t, lang, setLang, onDone }) { const [email, setEmail] = useStateU(''); const [pw, setPw] = useStateU(''); const [step, setStep] = useStateU('cred'); // cred | totp const [otp, setOtp] = useStateU(''); const ok = /\S+@\S+\.\S+/.test(email) && pw.length > 0; return /*#__PURE__*/React.createElement("div", { style: { minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'var(--bg)', padding: 24 } }, /*#__PURE__*/React.createElement("div", { style: { ...ucCard, width: 400, maxWidth: '100%', padding: '36px 34px', boxSizing: 'border-box' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 26 } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 10 } }, /*#__PURE__*/React.createElement(UCMark, { size: 32 }), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 17, color: 'var(--fg1)', lineHeight: 1 } }, "\u7A7F\u5C71\u7532"), /*#__PURE__*/React.createElement("div", { style: { fontSize: 8.5, fontWeight: 600, letterSpacing: '0.2em', color: 'var(--accent)', marginTop: 3 } }, "PANGOLIN"))), /*#__PURE__*/React.createElement(UCLang, { lang: lang, setLang: setLang })), step === 'cred' ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 22, color: 'var(--fg1)' } }, t('loginTitle')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 13.5, color: 'var(--fg3)', margin: '6px 0 24px' } }, t('loginSub')), /*#__PURE__*/React.createElement("label", { style: { display: 'block', marginBottom: 14 } }, /*#__PURE__*/React.createElement("span", { style: { display: 'block', fontSize: 12.5, fontWeight: 600, color: 'var(--fg2)', marginBottom: 6 } }, t('emailLabel')), /*#__PURE__*/React.createElement("input", { style: ucInput, value: email, onChange: e => setEmail(e.target.value), placeholder: t('emailPh') })), /*#__PURE__*/React.createElement("label", { style: { display: 'block' } }, /*#__PURE__*/React.createElement("span", { style: { display: 'block', fontSize: 12.5, fontWeight: 600, color: 'var(--fg2)', marginBottom: 6 } }, t('pwLabel')), /*#__PURE__*/React.createElement("input", { style: ucInput, type: "password", value: pw, onChange: e => setPw(e.target.value), placeholder: t('pwPh') })), /*#__PURE__*/React.createElement("div", { style: { textAlign: 'right', margin: '10px 0 18px' } }, /*#__PURE__*/React.createElement("span", { style: { fontSize: 13, color: 'var(--accent)', fontWeight: 600, cursor: 'pointer' } }, t('forgotPw'))), /*#__PURE__*/React.createElement("button", { onClick: ok ? () => setStep('totp') : undefined, disabled: !ok, style: { width: '100%', border: 'none', borderRadius: 'var(--radius-full)', padding: '13px', fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 15, cursor: ok ? 'pointer' : 'not-allowed', background: 'var(--accent)', color: 'var(--fg-on-accent)', opacity: ok ? 1 : 0.45 } }, t('doLogin')), /*#__PURE__*/React.createElement("div", { style: { textAlign: 'center', fontSize: 12.5, color: 'var(--fg3)', marginTop: 18 } }, t('noAccount'))) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 9, marginBottom: 6 } }, /*#__PURE__*/React.createElement(UCIcon, { name: "shield-check", size: 20, color: "var(--accent)" }), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 20, color: 'var(--fg1)' } }, t('twoFATitle')), /*#__PURE__*/React.createElement("span", { style: { fontSize: 10.5, fontWeight: 700, color: 'var(--accent)', background: 'var(--accent-subtle)', border: '1px solid var(--accent-border)', padding: '2px 8px', borderRadius: 999 } }, "PRO")), /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, color: 'var(--fg3)', margin: '4px 0 20px', lineHeight: 1.6 } }, t('twoFAHint')), /*#__PURE__*/React.createElement("input", { value: otp, onChange: e => setOtp(e.target.value.replace(/\D/g, '').slice(0, 6)), placeholder: "\xB7\xB7\xB7\xB7\xB7\xB7", style: { ...ucInput, fontFamily: 'var(--font-mono)', fontSize: 22, letterSpacing: '0.5em', textAlign: 'center', padding: '14px' } }), /*#__PURE__*/React.createElement("button", { onClick: otp.length === 6 ? onDone : undefined, disabled: otp.length !== 6, style: { width: '100%', border: 'none', borderRadius: 'var(--radius-full)', padding: '13px', marginTop: 16, fontFamily: 'var(--font-sans)', fontWeight: 700, fontSize: 15, cursor: otp.length === 6 ? 'pointer' : 'not-allowed', background: 'var(--accent)', color: 'var(--fg-on-accent)', opacity: otp.length === 6 ? 1 : 0.45 } }, t('twoFAConfirm')), /*#__PURE__*/React.createElement("div", { onClick: () => setStep('cred'), style: { textAlign: 'center', fontSize: 12.5, color: 'var(--fg3)', marginTop: 18, cursor: 'pointer' } }, t('twoFABack'))))); } /* ───────── Overview ───────── */ function UCOverview({ t, lang, free, mobile, goSub, goRedeem }) { const vals = [1.8, 2.4, 1.2, 3.1, 4.0, 5.2, 2.6]; const max = 5.2; const labels = lang === 'zh' ? ['一', '二', '三', '四', '五', '六', '日'] : ['M', 'T', 'W', 'T', 'F', 'S', 'S']; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 20 } }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 25, fontWeight: 700, color: 'var(--fg1)' } }, t('greeting')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 13.5, color: 'var(--fg3)', marginTop: 3 } }, "me@pangolin.vpn")), /*#__PURE__*/React.createElement("div", { style: { ...ucCard, background: 'linear-gradient(150deg,var(--clay-600),var(--clay-800))', border: 'none', color: '#fff', padding: '20px 24px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 14 } }, /*#__PURE__*/React.createElement("div", { style: { width: 46, height: 46, borderRadius: '50%', background: 'rgba(255,255,255,.18)', display: 'flex', alignItems: 'center', justifyContent: 'center' } }, /*#__PURE__*/React.createElement(UCIcon, { name: "crown", size: 23, color: "#fff" })), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, opacity: .8 } }, t('curPlan')), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 19, fontWeight: 700, marginTop: 2 } }, free ? t('freePlan') : t('proMember')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11.5, opacity: .8, marginTop: 3, fontFamily: 'var(--font-mono)', whiteSpace: 'nowrap' } }, free ? t('quotaFree') : `${t('expires')} 2026-12-31`))), /*#__PURE__*/React.createElement("button", { onClick: goRedeem, style: { border: 'none', background: '#fff', color: 'var(--clay-700)', fontWeight: 700, fontSize: 13.5, padding: '11px 20px', borderRadius: 'var(--radius-full)', cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 7 } }, /*#__PURE__*/React.createElement(UCIcon, { name: "ticket", size: 15, color: "var(--clay-700)" }), t('renew'))), /*#__PURE__*/React.createElement("div", { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(160px,1fr))', gap: 14 } }, [['clock', t('quotaToday'), free ? '6' : '∞', free ? 'min' : ''], ['arrow-down', t('dataToday'), '0.8', 'GB'], ['smartphone', t('devices'), '2 / 5', '']].map(([ic, l, v, u]) => /*#__PURE__*/React.createElement("div", { key: l, style: { ...ucCard, padding: '16px 18px' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 7, color: 'var(--fg3)', fontSize: 12, fontWeight: 600 } }, /*#__PURE__*/React.createElement(UCIcon, { name: ic, size: 15, color: "var(--accent)" }), l), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 23, fontWeight: 500, color: 'var(--fg1)', marginTop: 7 } }, v, u && /*#__PURE__*/React.createElement("span", { style: { fontSize: 12, color: 'var(--fg3)' } }, " ", u))))), /*#__PURE__*/React.createElement("div", { style: { display: 'grid', gridTemplateColumns: mobile ? '1fr' : '1.6fr 1fr', gap: 14, alignItems: 'start' } }, /*#__PURE__*/React.createElement("div", { style: { ...ucCard, padding: '18px 22px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 13.5, fontWeight: 600, color: 'var(--fg1)', marginBottom: 16 } }, t('usageTitle')), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'flex-end', gap: 14, height: 110 } }, vals.map((v, i) => /*#__PURE__*/React.createElement("div", { key: i, style: { flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6 } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 9.5, color: 'var(--fg3)' } }, v), /*#__PURE__*/React.createElement("div", { style: { width: '100%', maxWidth: 30, height: `${v / max * 76}px`, background: 'var(--accent)', borderRadius: '5px 5px 0 0', opacity: .85 } }), /*#__PURE__*/React.createElement("div", { style: { fontSize: 10.5, color: 'var(--fg3)' } }, labels[i]))))), /*#__PURE__*/React.createElement("div", { style: { ...ucCard, padding: '16px 18px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 13.5, fontWeight: 600, color: 'var(--fg1)', marginBottom: 12 } }, t('quickSub')), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 } }, [['link', t('qaSub'), goSub], ['ticket', t('qaRedeem'), goRedeem], ['download', t('qaApp'), null]].map(([ic, l, fn]) => /*#__PURE__*/React.createElement("button", { key: l, onClick: fn || undefined, style: { display: 'flex', alignItems: 'center', gap: 11, width: '100%', textAlign: 'left', cursor: 'pointer', background: 'var(--bg-subtle)', border: '1px solid var(--border)', borderRadius: 'var(--radius-md)', padding: '11px 13px' } }, /*#__PURE__*/React.createElement(UCIcon, { name: ic, size: 16, color: "var(--accent)" }), /*#__PURE__*/React.createElement("span", { style: { flex: 1, fontSize: 13.5, fontWeight: 600, color: 'var(--fg1)' } }, l), /*#__PURE__*/React.createElement(UCIcon, { name: "chevron-right", size: 15, color: "var(--fg3)" }))))))); } /* ───────── Subscription ───────── */ function UCSub({ t, lang, mobile }) { const [copied, setCopied] = useStateU(false); const [reset, setReset] = useStateU(false); const url = 'https://sub.pangolin.vpn/s/8f3kx92m' + (reset ? '-new' : ''); const clients = [{ name: '穿山甲 App', sub: 'iOS / Android / 桌面', icon: 'shield-check', accent: true }, { name: 'Shadowrocket', sub: 'iOS', icon: 'external-link' }, { name: 'Clash Verge', sub: 'Windows / macOS', icon: 'external-link' }, { name: 'v2rayN', sub: 'Windows', icon: 'external-link' }, { name: 'sing-box', sub: '全平台', icon: 'external-link' }]; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 18, maxWidth: 720 } }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 25, fontWeight: 700, color: 'var(--fg1)' } }, t('subTitle')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, color: 'var(--fg3)', marginTop: 5, lineHeight: 1.6 } }, t('subDesc'))), /*#__PURE__*/React.createElement("div", { style: { display: 'grid', gridTemplateColumns: mobile ? '1fr' : '1fr auto', gap: 14, alignItems: 'start' } }, /*#__PURE__*/React.createElement("div", { style: { ...ucCard, padding: '18px 20px' } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 9, background: 'var(--bg-subtle)', border: '1px solid var(--border)', borderRadius: 'var(--radius-md)', padding: '11px 13px', marginBottom: 12 } }, /*#__PURE__*/React.createElement(UCIcon, { name: "link", size: 15, color: "var(--fg3)" }), /*#__PURE__*/React.createElement("span", { style: { flex: 1, fontFamily: 'var(--font-mono)', fontSize: 12.5, color: 'var(--fg1)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, url)), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 10, flexWrap: 'wrap' } }, /*#__PURE__*/React.createElement("button", { onClick: () => { setCopied(true); setTimeout(() => setCopied(false), 1800); }, style: { display: 'inline-flex', alignItems: 'center', gap: 7, border: 'none', borderRadius: 'var(--radius-full)', padding: '10px 18px', background: 'var(--accent)', color: '#fff', fontWeight: 700, fontSize: 13.5, cursor: 'pointer' } }, /*#__PURE__*/React.createElement(UCIcon, { name: copied ? 'check' : 'copy', size: 15, color: "#fff" }), copied ? t('subCopied') : t('subCopy')), /*#__PURE__*/React.createElement("button", { onClick: () => setReset(true), style: { display: 'inline-flex', alignItems: 'center', gap: 7, border: '1.5px solid var(--border-strong)', borderRadius: 'var(--radius-full)', padding: '10px 18px', background: 'transparent', color: 'var(--fg2)', fontWeight: 600, fontSize: 13.5, cursor: 'pointer' } }, /*#__PURE__*/React.createElement(UCIcon, { name: "refresh-cw", size: 14, color: "var(--fg2)" }), t('subReset'))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11.5, color: reset ? 'var(--success)' : 'var(--fg3)', marginTop: 10, display: 'flex', alignItems: 'center', gap: 6 } }, reset && /*#__PURE__*/React.createElement(UCIcon, { name: "check-circle", size: 13, color: "var(--success)" }), reset ? t('subResetOk') : t('subResetSub'))), /*#__PURE__*/React.createElement("div", { style: { ...ucCard, padding: '16px', width: mobile ? '100%' : 170, boxSizing: 'border-box', textAlign: 'center' } }, /*#__PURE__*/React.createElement("div", { style: { width: 138, height: 138, margin: '0 auto', borderRadius: 'var(--radius-md)', background: 'var(--bg-subtle)', border: '1px dashed var(--border-strong)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 8 } }, /*#__PURE__*/React.createElement(UCIcon, { name: "qr-code", size: 42, color: "var(--fg3)", stroke: 1.5 }), /*#__PURE__*/React.createElement("span", { style: { fontSize: 10.5, color: 'var(--fg3)', fontWeight: 600 } }, t('scanTitle'))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 10.5, color: 'var(--fg3)', marginTop: 10, lineHeight: 1.5 } }, t('scanSub')))), /*#__PURE__*/React.createElement("div", { style: { ...ucCard, padding: '18px 20px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14.5, fontWeight: 700, color: 'var(--fg1)' } }, t('importTitle')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, color: 'var(--fg3)', margin: '4px 0 14px' } }, t('importSub')), /*#__PURE__*/React.createElement("div", { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(190px,1fr))', gap: 10 } }, clients.map(c => /*#__PURE__*/React.createElement("button", { key: c.name, style: { display: 'flex', alignItems: 'center', gap: 11, textAlign: 'left', cursor: 'pointer', background: c.accent ? 'var(--accent-subtle)' : 'var(--surface)', border: `1px solid ${c.accent ? 'var(--accent-border)' : 'var(--border)'}`, borderRadius: 'var(--radius-lg)', padding: '12px 14px' } }, /*#__PURE__*/React.createElement("div", { style: { width: 34, height: 34, borderRadius: 'var(--radius-md)', background: c.accent ? 'var(--accent)' : 'var(--bg-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(UCIcon, { name: c.icon, size: 17, color: c.accent ? '#fff' : 'var(--accent)' })), /*#__PURE__*/React.createElement("div", { style: { minWidth: 0 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 13.5, fontWeight: 600, color: 'var(--fg1)', whiteSpace: 'nowrap' } }, c.name), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11, color: 'var(--fg3)' } }, c.sub))))), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11.5, color: 'var(--fg3)', marginTop: 12 } }, t('fmtNote')))); } /* ───────── Redeem ───────── */ function UCRedeem({ t, lang }) { const [code, setCode] = useStateU(''); const [ok, setOk] = useStateU(false); const channels = [{ icon: 'shopping-bag', name: t('chStore'), sub: t('chStoreSub'), accent: true }, { icon: 'credit-card', name: 'USDT (TRC20)', sub: t('chUsdtSub') }, { icon: 'send', name: 'Telegram', sub: '@PangolinVPN_bot', mono: true }, { icon: 'message-circle', name: 'LINE', sub: '@pangolinvpn', mono: true }, { icon: 'mail', name: t('chEmail'), sub: 'buy@pangolin.vpn', mono: true }]; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 18, maxWidth: 680 } }, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 25, fontWeight: 700, color: 'var(--fg1)' } }, t('navRedeem')), /*#__PURE__*/React.createElement("div", { style: { ...ucCard, padding: '20px 22px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14.5, fontWeight: 700, color: 'var(--fg1)', marginBottom: 12 } }, t('redeemTitle')), ok ? /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 9, color: 'var(--success)', fontWeight: 600, fontSize: 15, padding: '4px 0' } }, /*#__PURE__*/React.createElement(UCIcon, { name: "check-circle", size: 19, color: "var(--success)" }), t('redeemOk')) : /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 10 } }, /*#__PURE__*/React.createElement("input", { value: code, onChange: e => setCode(e.target.value.toUpperCase()), placeholder: t('redeemPh'), style: { ...ucInput, fontFamily: 'var(--font-mono)', letterSpacing: '0.08em' } }), /*#__PURE__*/React.createElement("button", { onClick: () => code.length >= 4 && setOk(true), style: { border: 'none', borderRadius: 'var(--radius-md)', padding: '0 22px', background: 'var(--accent)', color: '#fff', fontWeight: 700, fontSize: 14, cursor: 'pointer', flexShrink: 0 } }, t('redeemBtn')))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14.5, fontWeight: 700, color: 'var(--fg1)', marginBottom: 5 } }, t('buyTitle')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, color: 'var(--fg3)', lineHeight: 1.5, marginBottom: 13 } }, t('buySub')), /*#__PURE__*/React.createElement("div", { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(240px,1fr))', gap: 11 } }, channels.map(c => /*#__PURE__*/React.createElement("button", { key: c.name, style: { display: 'flex', alignItems: 'center', gap: 12, textAlign: 'left', cursor: 'pointer', background: c.accent ? 'var(--accent-subtle)' : 'var(--surface)', border: `1px solid ${c.accent ? 'var(--accent-border)' : 'var(--border)'}`, borderRadius: 'var(--radius-lg)', padding: '13px 15px', boxShadow: 'var(--shadow-sm)' } }, /*#__PURE__*/React.createElement("div", { style: { width: 38, height: 38, borderRadius: 'var(--radius-md)', background: c.accent ? 'var(--accent)' : 'var(--bg-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 } }, /*#__PURE__*/React.createElement(UCIcon, { name: c.icon, size: 18, color: c.accent ? '#fff' : 'var(--accent)' })), /*#__PURE__*/React.createElement("div", { style: { flex: 1, minWidth: 0 } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 14, fontWeight: 600, color: 'var(--fg1)' } }, c.name), /*#__PURE__*/React.createElement("div", { style: { fontSize: 11.5, color: 'var(--fg3)', fontFamily: c.mono ? 'var(--font-mono)' : 'var(--font-sans)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' } }, c.sub)), /*#__PURE__*/React.createElement(UCIcon, { name: "external-link", size: 15, color: "var(--fg3)" })))))); } /* ───────── Invite ───────── */ function UCInvite({ t, lang }) { const [copied, setCopied] = useStateU(false); const records = [{ mail: 'k***@gmail.com', date: '2026-06-08', paid: true }, { mail: 'w***@outlook.com', date: '2026-06-05', paid: false }, { mail: 'z***@qq.com', date: '2026-05-30', paid: true }]; return /*#__PURE__*/React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 18, maxWidth: 680 } }, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-display)', fontSize: 25, fontWeight: 700, color: 'var(--fg1)' } }, t('inviteTitle')), /*#__PURE__*/React.createElement("div", { style: { fontSize: 13, color: 'var(--fg3)', marginTop: 5, lineHeight: 1.6 } }, t('inviteSub'))), /*#__PURE__*/React.createElement("div", { style: { ...ucCard, padding: '18px 20px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 12.5, fontWeight: 600, color: 'var(--fg2)', marginBottom: 8 } }, t('inviteLink')), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', gap: 10 } }, /*#__PURE__*/React.createElement("div", { style: { flex: 1, display: 'flex', alignItems: 'center', gap: 9, background: 'var(--bg-subtle)', border: '1px solid var(--border)', borderRadius: 'var(--radius-md)', padding: '11px 13px', minWidth: 0 } }, /*#__PURE__*/React.createElement(UCIcon, { name: "gift", size: 15, color: "var(--fg3)" }), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 12.5, color: 'var(--fg1)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, "https://pangolin.vpn/r/PG8F3K")), /*#__PURE__*/React.createElement("button", { onClick: () => { setCopied(true); setTimeout(() => setCopied(false), 1800); }, style: { display: 'inline-flex', alignItems: 'center', gap: 7, border: 'none', borderRadius: 'var(--radius-md)', padding: '0 18px', background: 'var(--accent)', color: '#fff', fontWeight: 700, fontSize: 13.5, cursor: 'pointer', flexShrink: 0 } }, /*#__PURE__*/React.createElement(UCIcon, { name: copied ? 'check' : 'copy', size: 15, color: "#fff" }), copied ? t('subCopied') : t('subCopy')))), /*#__PURE__*/React.createElement("div", { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(150px,1fr))', gap: 14 } }, [[t('invited'), '8', ''], [t('paidUsers'), '3', ''], [t('earned'), '¥45', '']].map(([l, v]) => /*#__PURE__*/React.createElement("div", { key: l, style: { ...ucCard, padding: '16px 18px' } }, /*#__PURE__*/React.createElement("div", { style: { fontSize: 12, color: 'var(--fg3)', fontWeight: 600 } }, l), /*#__PURE__*/React.createElement("div", { style: { fontFamily: 'var(--font-mono)', fontSize: 23, fontWeight: 500, color: 'var(--fg1)', marginTop: 7 } }, v)))), /*#__PURE__*/React.createElement("div", { style: { ...ucCard, overflow: 'hidden' } }, /*#__PURE__*/React.createElement("div", { style: { padding: '13px 18px', fontSize: 13.5, fontWeight: 700, color: 'var(--fg1)', borderBottom: '1px solid var(--border)' } }, t('inviteRecord')), records.map((r, i) => /*#__PURE__*/React.createElement("div", { key: i, style: { display: 'flex', alignItems: 'center', gap: 12, padding: '12px 18px', borderBottom: i < records.length - 1 ? '1px solid var(--border)' : 'none' } }, /*#__PURE__*/React.createElement("span", { style: { flex: 1, fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--fg1)' } }, r.mail), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--fg3)' } }, r.date), /*#__PURE__*/React.createElement("span", { style: { fontSize: 11, fontWeight: 600, padding: '3px 10px', borderRadius: 999, background: r.paid ? 'var(--success-subtle)' : 'var(--bg-subtle)', color: r.paid ? 'var(--success)' : 'var(--fg3)' } }, r.paid ? t('recPaid') : t('recRegistered')))))); } /* ───────── App shell ───────── */ function UserCenterApp() { const [stage, setStage] = useStateU('app'); // app | login — opens on the dashboard const [view, setView] = useStateU('overview'); const [lang, setLang] = useStateU('zh'); const [free] = useStateU(false); const [dir, setDir] = useStateU(0); // -1 左进 / 1 右进 / 0 无动画 const mobile = useIsMobileUC(); const t = ucT(lang); const touchRef = React.useRef({ x: 0, y: 0 }); const ORDER = ['overview', 'sub', 'redeem', 'invite']; function go(id) { const a = ORDER.indexOf(view), b = ORDER.indexOf(id); setDir(b > a ? 1 : b < a ? -1 : 0); setView(id); setTimeout(() => setDir(0), 300); } function onTouchStart(e) { const p = e.touches ? e.touches[0] : e; touchRef.current = { x: p.clientX, y: p.clientY }; } function onTouchEnd(e) { const p = e.changedTouches ? e.changedTouches[0] : e; const dx = p.clientX - touchRef.current.x, dy = p.clientY - touchRef.current.y; if (Math.abs(dx) > 60 && Math.abs(dx) > Math.abs(dy) * 1.5) { const i = ORDER.indexOf(view); const ni = dx < 0 ? Math.min(ORDER.length - 1, i + 1) : Math.max(0, i - 1); if (ni !== i) go(ORDER[ni]); } } if (stage === 'login') return /*#__PURE__*/React.createElement(UCLogin, { t: t, lang: lang, setLang: setLang, onDone: () => setStage('app') }); const nav = [['overview', 'layout-dashboard', t('navOverview')], ['sub', 'link', t('navSub')], ['redeem', 'ticket', t('navRedeem')], ['invite', 'users', t('navInvite')]]; let main; if (view === 'overview') main = /*#__PURE__*/React.createElement(UCOverview, { t: t, lang: lang, free: free, mobile: mobile, goSub: () => setView('sub'), goRedeem: () => setView('redeem') });else if (view === 'sub') main = /*#__PURE__*/React.createElement(UCSub, { t: t, lang: lang, mobile: mobile });else if (view === 'redeem') main = /*#__PURE__*/React.createElement(UCRedeem, { t: t, lang: lang });else main = /*#__PURE__*/React.createElement(UCInvite, { t: t, lang: lang }); const navBtns = nav.map(([id, ic, l]) => /*#__PURE__*/React.createElement("button", { key: id, onClick: () => go(id), style: { display: 'inline-flex', alignItems: 'center', gap: 7, border: 'none', cursor: 'pointer', borderRadius: 'var(--radius-md)', padding: '8px 13px', flexShrink: 0, background: view === id ? 'var(--accent-subtle)' : 'transparent', color: view === id ? 'var(--accent)' : 'var(--fg2)', fontFamily: 'var(--font-sans)', fontSize: 13.5, fontWeight: view === id ? 700 : 500, whiteSpace: 'nowrap' } }, /*#__PURE__*/React.createElement(UCIcon, { name: ic, size: 15, color: view === id ? 'var(--accent)' : 'var(--fg3)' }), l)); return /*#__PURE__*/React.createElement("div", { style: { minHeight: '100vh', background: 'var(--bg)', fontFamily: 'var(--font-sans)' } }, /*#__PURE__*/React.createElement("div", { style: { position: 'sticky', top: 0, zIndex: 10, background: 'color-mix(in srgb, var(--bg) 85%, transparent)', backdropFilter: 'blur(12px)', borderBottom: '1px solid var(--border)' } }, /*#__PURE__*/React.createElement("div", { style: { maxWidth: 1000, margin: '0 auto', padding: mobile ? '0 16px' : '0 24px', height: mobile ? 54 : 60, display: 'flex', alignItems: 'center', gap: mobile ? 12 : 22 } }, /*#__PURE__*/React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: 9 } }, /*#__PURE__*/React.createElement(UCMark, { size: 26 }), /*#__PURE__*/React.createElement("span", { style: { fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 16.5, color: 'var(--fg1)' } }, "\u7A7F\u5C71\u7532")), !mobile && /*#__PURE__*/React.createElement("nav", { style: { display: 'flex', gap: 4, flex: 1 } }, navBtns), mobile && /*#__PURE__*/React.createElement("div", { style: { flex: 1 } }), /*#__PURE__*/React.createElement(UCLang, { lang: lang, setLang: setLang }), /*#__PURE__*/React.createElement("button", { onClick: () => setStage('login'), style: { display: 'inline-flex', alignItems: 'center', gap: 7, border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--fg2)', fontSize: 13, fontWeight: 600, padding: 6 } }, /*#__PURE__*/React.createElement(UCIcon, { name: "log-out", size: 15, color: "var(--fg3)" }), !mobile && t('signOut'))), mobile && /*#__PURE__*/React.createElement("nav", { style: { display: 'flex', gap: 2, padding: '0 12px 8px', overflowX: 'auto' } }, navBtns)), /*#__PURE__*/React.createElement("div", { onTouchStart: mobile ? onTouchStart : undefined, onTouchEnd: mobile ? onTouchEnd : undefined, style: { maxWidth: 1000, margin: '0 auto', padding: mobile ? '20px 16px 40px' : '30px 24px 48px' } }, /*#__PURE__*/React.createElement("div", { key: view, onAnimationEnd: () => setDir(0), style: { animation: dir !== 0 ? `uc-in-${dir === 1 ? 'l' : 'r'} 200ms var(--ease-out)` : 'none' } }, main))); } Object.assign(window, { UserCenterApp }); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/usercenter/ucapp.jsx", error: String((e && e.message) || e) }); } // ui_kits/usercenter/ucparts.jsx try { (() => { /* ucparts.jsx — 穿山甲 Web 用户中心 · atoms + i18n */ const UCLUCIDE = { 'layout-dashboard': '', link: '', ticket: '', users: '', copy: '', 'refresh-cw': '', 'qr-code': '', download: '', check: '', 'check-circle': '', zap: '', clock: '', 'shield-check': '', crown: '', 'credit-card': '', send: '', 'message-circle': '', mail: '', 'shopping-bag': '', 'log-out': '', 'external-link': '', gift: '', smartphone: '', lock: '', 'chevron-right': '', 'arrow-down': '' }; function UCIcon({ name, size = 18, stroke = 2, color = 'currentColor', style = {} }) { return /*#__PURE__*/React.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round", style: { display: 'block', flexShrink: 0, ...style }, dangerouslySetInnerHTML: { __html: UCLUCIDE[name] || '' } }); } function UCMark({ size = 30, color = 'var(--accent)' }) { return /*#__PURE__*/React.createElement("svg", { width: size, height: size, viewBox: "0 0 96 96", fill: "none", style: { display: 'block' } }, /*#__PURE__*/React.createElement("g", { transform: "translate(96,0) scale(-1,1)" }, /*#__PURE__*/React.createElement("path", { d: "M16 59 Q17 51 26 50 Q34 31 45 30 Q55 30 62 37 Q69 41 75 45 Q85 49 89 44 Q92 50 84 52 Q75 53 67 53 Q66 62 60 62 L56 62 Q54 55 49 55 Q47 62 37 62 L33 62 Q31 56 26 56 Q20 59 16 59 Z", fill: color }), /*#__PURE__*/React.createElement("g", { stroke: "#fff", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", fill: "none", opacity: "0.5" }, /*#__PURE__*/React.createElement("path", { d: "M27 50 Q35 43 43 50" }), /*#__PURE__*/React.createElement("path", { d: "M37 48 Q45 41 53 48" }), /*#__PURE__*/React.createElement("path", { d: "M47 48 Q55 41 63 49" })), /*#__PURE__*/React.createElement("circle", { cx: "19", cy: "56", r: "2.2", fill: "#fff", opacity: "0.85" }))); } const UCSTRINGS = { navOverview: { zh: '概览', en: 'Overview' }, navSub: { zh: '订阅', en: 'Subscription' }, navRedeem: { zh: '兑换 & 购买', en: 'Redeem & buy' }, navInvite: { zh: '邀请返利', en: 'Referral' }, signOut: { zh: '退出', en: 'Sign out' }, /* login */ loginTitle: { zh: '登录用户中心', en: 'Log in to your account' }, loginSub: { zh: '管理订阅、兑换激活码、查看用量', en: 'Manage subscription, redeem codes, track usage' }, emailLabel: { zh: '邮箱', en: 'Email' }, emailPh: { zh: '你的邮箱地址', en: 'your@email.com' }, pwLabel: { zh: '密码', en: 'Password' }, pwPh: { zh: '输入密码', en: 'Enter password' }, doLogin: { zh: '登录', en: 'Log in' }, forgotPw: { zh: '忘记密码?', en: 'Forgot password?' }, noAccount: { zh: '没有账户?在 App 内注册', en: 'No account? Sign up in the app' }, /* overview */ greeting: { zh: '欢迎回来', en: 'Welcome back' }, curPlan: { zh: '当前套餐', en: 'Current plan' }, freePlan: { zh: '免费版', en: 'Free' }, proMember: { zh: 'PRO 会员', en: 'PRO member' }, expires: { zh: '有效期至', en: 'Expires' }, renew: { zh: '续费 / 升级', en: 'Renew / Upgrade' }, quotaToday: { zh: '今日剩余时长', en: 'Time left today' }, dataToday: { zh: '今日已用流量', en: 'Data used today' }, devices: { zh: '在线设备', en: 'Devices online' }, quotaFree: { zh: '免费版 · 每日 10 分钟', en: 'Free · 10 min/day' }, usageTitle: { zh: '近 7 日流量 (GB)', en: 'Last 7 days (GB)' }, quickSub: { zh: '快速操作', en: 'Quick actions' }, qaSub: { zh: '获取订阅链接', en: 'Get subscription' }, qaRedeem: { zh: '兑换激活码', en: 'Redeem a code' }, qaApp: { zh: '下载 App', en: 'Download apps' }, /* subscription */ subTitle: { zh: '我的订阅', en: 'My subscription' }, subDesc: { zh: '订阅链接是你的专属凭证,泄露后他人可使用你的额度。请勿分享。', en: 'Your subscription link is a private credential. Never share it.' }, subCopy: { zh: '复制链接', en: 'Copy link' }, subCopied: { zh: '已复制', en: 'Copied' }, subReset: { zh: '重置链接', en: 'Reset link' }, subResetSub: { zh: '旧链接立即失效,所有设备需重新导入', en: 'Old link stops working; re-import on all devices' }, subResetOk: { zh: '已重置,请重新导入', en: 'Reset — re-import on your devices' }, scanTitle: { zh: '扫码导入', en: 'Scan to import' }, scanSub: { zh: '用穿山甲 App 或三方客户端扫码', en: 'Scan with the Pangolin app or a 3rd-party client' }, importTitle: { zh: '一键导入三方客户端', en: 'One-tap import' }, importSub: { zh: '已安装对应客户端时,点击即自动导入订阅。', en: 'If the client is installed, tapping imports the subscription automatically.' }, fmtNote: { zh: '同一链接同时兼容 sing-box / Clash.Meta / v2ray 格式。', en: 'One link serves sing-box / Clash.Meta / v2ray formats.' }, /* redeem */ redeemTitle: { zh: '兑换激活码', en: 'Redeem a code' }, redeemPh: { zh: '输入激活码', en: 'Enter activation code' }, redeemBtn: { zh: '激活', en: 'Redeem' }, redeemOk: { zh: '激活成功 · 套餐已到账', en: 'Activated — plan applied' }, buyTitle: { zh: '购买渠道', en: 'Where to buy' }, buySub: { zh: '本站不直接收款。通过以下渠道购买激活码,回到本页兑换即可:', en: 'We never take payment on this site. Buy a code via a channel below, then redeem here:' }, chStore: { zh: '自助发卡商店', en: 'Self-serve store' }, chStoreSub: { zh: '支付宝 / 微信 · 自动发码', en: 'Alipay / WeChat · instant code' }, chUsdtSub: { zh: '链上转账 · 最隐私 · 自动发码', en: 'On-chain · most private · instant code' }, chEmail: { zh: '邮箱客服', en: 'Email support' }, /* invite */ inviteTitle: { zh: '邀请返利', en: 'Referral' }, inviteSub: { zh: '好友通过你的链接注册并付费,你获得其首单 20% 余额返利,可抵扣续费。', en: 'When a friend signs up and pays via your link, you earn 20% of their first order as credit.' }, inviteLink: { zh: '我的邀请链接', en: 'My invite link' }, invited: { zh: '已邀请', en: 'Invited' }, paidUsers: { zh: '已付费', en: 'Converted' }, earned: { zh: '累计返利', en: 'Credit earned' }, inviteRecord: { zh: '邀请记录', en: 'History' }, recEmpty: { zh: '暂无邀请记录', en: 'No referrals yet' }, recRegistered: { zh: '已注册', en: 'Registered' }, recPaid: { zh: '已付费', en: 'Paid' }, /* 2FA */ twoFATitle: { zh: '双重认证', en: 'Two-factor auth' }, twoFAHint: { zh: '你的账户已开启双重认证。请输入身份验证器 App 中的 6 位动态码。', en: 'Two-factor auth is on for this account. Enter the 6-digit code from your authenticator app.' }, twoFAConfirm: { zh: '验证并登录', en: 'Verify & log in' }, twoFABack: { zh: '返回上一步', en: 'Back' } }; function ucT(lang) { return k => { const v = UCSTRINGS[k]; return v ? v[lang] || k : k; }; } Object.assign(window, { UCIcon, UCMark, UCSTRINGS, ucT }); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/usercenter/ucparts.jsx", error: String((e && e.message) || e) }); } // ui_kits/website/site.js try { (() => { /* site.js — 穿山甲 VPN 官网 · i18n + 交互 */ (function () { // ---------- i18n ---------- const I18N = { 'ann.txt': ['新用户注册即享 7 天免费试用', 'New users get a 7-day free trial'], 'ann.cta': ['立即注册 →', 'Sign up →'], 'su.ph': ['输入邮箱,免费注册', 'Enter email to sign up free'], 'su.btn': ['免费注册', 'Sign up free'], 'su.ok': ['验证码已发送!下载 App 并用同一邮箱继续完成注册。', 'Code sent! Download the app and continue with the same email.'], 'su.hint': ['免费注册 · 无需付款 · 7 天免费试用', 'Free to join · no payment · 7-day free trial'], 'su.dl': ['或直接下载 App', 'or just download the app'], 'why.eyebrow': ['免费注册', 'Sign up'], 'why.h': ['注册一次,处处可用', 'One account, everywhere'], 'why.sub': ['一个邮箱就能开始。注册免费,不需要任何付款信息。', 'All you need is an email. Free to join — no payment details, ever.'], 'why.1t': ['7 天免费试用', '7-day free trial'], 'why.1d': ['新用户注册即享 7 天免费使用,无需任何付款信息。', 'New accounts get 7 days of free, unrestricted use — no payment details.'], 'why.2t': ['多端同步', 'Multi-device sync'], 'why.2d': ['手机、平板、电脑共用一个账户,套餐与设置随身走。', 'Phone, tablet and desktop share one account — your plan follows you.'], 'why.3t': ['无需付款信息', 'No payment details'], 'why.3d': ['注册只要邮箱。想升级时,再通过外部渠道兑换激活码。', 'Just an email to join. Upgrade later with an activation code.'], 'why.s1': ['填写邮箱', 'Enter email'], 'why.s2': ['输入验证码', 'Verify code'], 'why.s3': ['开始畅连', 'Start connecting'], 'why.cta': ['立即免费注册', 'Sign up free'], 'cta.btn2': ['免费注册', 'Sign up free'], 'nav.product': ['产品', 'Product'], 'nav.pricing': ['定价', 'Pricing'], 'nav.download': ['下载', 'Download'], 'nav.docs': ['文档', 'Docs'], 'nav.blog': ['Blog', 'Blog'], 'nav.login': ['登录', 'Log in'], 'nav.get': ['立即下载', 'Get the app'], 'hero.eyebrow': ['极速 · 稳定 · 省心', 'Fast · Stable · Effortless'], 'hero.h1': ['极速畅连,\n网络如丝顺滑', 'Faster, smoother,\neverywhere'], 'hero.lede': ['轻盈、亲和、即开即用的跨平台网络加速应用。一键连接,智能选线,稳定不掉线。', 'A lightweight, friendly cross-platform network accelerator. One tap, smart routing, rock-solid.'], 'hero.cta1': ['免费下载', 'Download free'], 'hero.cta2': ['查看定价', 'See pricing'], 'hero.t1': ['80+ 全球加速线路', '80+ global routes'], 'hero.t2': ['严格无日志', 'Strict no-logs'], 'hero.t3': ['端到端加密', 'End-to-end encrypted'], 'orb.cap': ['已连接', 'CONNECTED'], 'orb.down': ['下载', 'Down'], 'orb.up': ['上传', 'Up'], 'orb.node': ['香港 · 流媒体', 'Hong Kong'], 'orb.nodesub': ['延迟 18ms · 已连接', '18ms · Connected'], 'strip.txt': ['已支持', 'Available on'], 'feat.eyebrow': ['产品', 'Product'], 'feat.h': ['为日常而生的连接体验', 'Built for everyday connection'], 'feat.sub': ['没有复杂配置,没有技术门槛。打开就用,把稳定与隐私留给我们。', 'No complex setup, no jargon. Just open and go — we handle speed and privacy.'], 'feat.1t': ['一键连接', 'One-tap connect'], 'feat.1d': ['一颗按钮,智能挑选最快线路。无需手动配置,也能秒连。', 'One button picks the fastest route. No manual setup, instant connect.'], 'feat.2t': ['智能分流', 'Smart routing'], 'feat.2d': ['按规则智能分流,该加速的加速,本地服务直连,互不打扰。', 'Smart rule-based routing — accelerate what needs it, keep local traffic direct.'], 'feat.3t': ['80+ 全球加速线路', '80+ global routes'], 'feat.3d': ['覆盖港日新美欧韩等地,视频与游戏优化线路随心选。', 'Routes across HK / JP / SG / US / EU and more, tuned for video & gaming.'], 'feat.4t': ['严格无日志', 'Strict no-logs'], 'feat.4d': ['我们不记录你的浏览数据。隐私是底线,不是卖点。', 'We never log your browsing. Privacy is the baseline, not a feature.'], 'feat.5t': ['Kill Switch', 'Kill Switch'], 'feat.5d': ['一旦连接中断,立即阻断网络,杜绝真实 IP 泄露。', 'If the tunnel drops, traffic is blocked instantly — no IP leaks.'], 'feat.6t': ['多端同步', 'Multi-device'], 'feat.6d': ['一个账户,手机、平板、电脑同时在线,最多 5 台设备。', 'One account across phone, tablet and desktop — up to 5 devices.'], 'price.eyebrow': ['定价', 'Pricing'], 'price.h': ['简单透明的价格', 'Simple, honest pricing'], 'price.sub': ['随时升级或取消。所有套餐均含核心加密与无日志承诺。', 'Upgrade or cancel anytime. Every plan includes core encryption and our no-logs promise.'], 'price.monthly': ['按月', 'Monthly'], 'price.yearly': ['按年', 'Yearly'], 'price.save': ['省 20%', 'Save 20%'], 'price.permo': ['/月', '/mo'], 'price.free': ['免费版', 'Free'], 'price.freedesc': ['适合轻度使用与尝鲜', 'For light, casual use'], 'price.pro': ['专业版', 'Pro'], 'price.prodesc': ['个人用户的最佳选择', 'Best for individuals'], 'price.team': ['团队版', 'Team'], 'price.teamdesc': ['小团队集中管理', 'For small teams'], 'price.popular': ['最受欢迎', 'Most popular'], 'price.cta_free': ['免费下载', 'Download free'], 'price.cta_pro': ['获取激活码', 'Get a code'], 'price.cta_team': ['获取激活码', 'Get a code'], 'pf.free1': ['每日 10 分钟时长', '10 min per day'], 'pf.free2': ['仅 1 个基础节点', '1 basic node only'], 'pf.free3': ['使用前观看广告', 'Watch an ad to start'], 'pf.free4': ['核心加密 · 无日志', 'Core encryption · no-logs'], 'pf.pro1': ['80+ 全球加速线路', '80+ global routes'], 'pf.pro2': ['无限流量 · 极速', 'Unlimited · top speed'], 'pf.pro3': ['5 台设备同时在线', '5 devices at once'], 'pf.pro4': ['流媒体 & P2P 优化', 'Streaming & P2P routes'], 'pf.pro5': ['Kill Switch · 智能分流', 'Kill Switch · smart routing'], 'pf.team1': ['专业版全部功能', 'Everything in Pro'], 'pf.team2': ['10 个成员席位', '10 seats'], 'pf.team3': ['集中计费与管理', 'Central billing & admin'], 'pf.team4': ['优先客服', 'Priority support'], 'pay.title': ['为什么网页上没有支付按钮?', 'Why no checkout on this page?'], 'pay.body': ['出于风控与隐私考虑,穿山甲不在网页或 App 内直接收款。你可以通过以下任一渠道获取激活码,在客户端内兑换即可开通。', 'For risk and privacy reasons, Pangolin never takes payment in the web or app. Get an activation code through any channel below, then redeem it in the client.'], 'pay.store': ['自助发卡商店', 'Self-serve store'], 'pay.usdt': ['USDT (TRC20) · 最隐私', 'USDT (TRC20) · most private'], 'cmp.h': ['功能对比', 'Compare plans'], 'cmp.feature': ['功能', 'Feature'], 'cmp.locations': ['可用线路', 'Routes'], 'cmp.data': ['流量', 'Data'], 'cmp.time': ['每日时长', 'Daily time'], 'cmp.time_free': ['10 分钟/天(试用期不限)', '10 min/day (trial: unlimited)'], 'cmp.devices': ['设备数', 'Devices'], 'cmp.speed': ['极速线路', 'Top-speed routes'], 'cmp.stream': ['视频优化', 'Video routes'], 'cmp.kill': ['Kill Switch', 'Kill Switch'], 'cmp.support': ['客服', 'Support'], 'cmp.unlimited': ['无限', 'Unlimited'], 'cmp.daily': ['不限', 'Unlimited'], 'cmp.basic': ['标准', 'Standard'], 'cmp.priority': ['优先', 'Priority'], 'dl.eyebrow': ['下载', 'Download'], 'dl.h': ['全平台,随处可用', 'Every platform, everywhere'], 'dl.sub': ['一个账户,所有设备同步。下载即用,无需配置。', 'One account syncs every device. Download and go.'], 'dl.get': ['下载', 'Download'], 'docs.eyebrow': ['文档', 'Docs'], 'docs.h': ['需要帮助?都在这里', 'Need help? It’s all here'], 'docs.sub': ['从快速上手到协议细节,清晰直接。', 'From quickstart to protocol details — clear and direct.'], 'docs.1t': ['快速开始', 'Quickstart'], 'docs.1d': ['三分钟完成注册、下载与首次连接。', 'Sign up, download and connect in three minutes.'], 'docs.2t': ['常见问题', 'FAQ'], 'docs.2d': ['连接、计费、设备与兑换码的常见疑问。', 'Connection, billing, devices and redeem codes.'], 'docs.3t': ['协议与安全', 'Protocol & security'], 'docs.3d': ['WireGuard、加密方式与无日志架构说明。', 'WireGuard, encryption and our no-logs architecture.'], 'docs.4t': ['隐私政策', 'Privacy policy'], 'docs.4d': ['我们收集什么、不收集什么,一目了然。', 'Exactly what we collect — and what we never do.'], 'docs.read': ['阅读', 'Read'], 'blog.eyebrow': ['Blog', 'Blog'], 'blog.h': ['来自团队的最新动态', 'Latest from the team'], 'blog.sub': ['产品更新、安全科普与节点公告。', 'Product updates, security explainers and node news.'], 'blog.1tag': ['产品更新', 'Product'], 'blog.1t': ['v2.4:更快的智能分流与全新统计页', 'v2.4: faster smart routing & a new stats tab'], 'blog.1d': ['本次更新重写了分流引擎,连接建立速度提升约 40%。', 'We rewrote the routing engine — connections are ~40% faster.'], 'blog.2tag': ['安全', 'Security'], 'blog.2t': ['无日志到底意味着什么?', 'What “no-logs” really means'], 'blog.2d': ['我们逐条拆解收集与不收集的数据,以及背后的架构。', 'A line-by-line look at what we keep — and what we never touch.'], 'blog.3tag': ['公告', 'News'], 'blog.3t': ['新增首尔与法兰克福高速节点', 'New high-speed nodes: Seoul & Frankfurt'], 'blog.3d': ['两条新线路已上线,为东北亚与欧洲用户带来更低延迟。', 'Two new routes are live, cutting latency for NE Asia and Europe.'], 'blog.readmore': ['阅读全文', 'Read more'], 'cta.h': ['准备好体验极速畅连了吗?', 'Ready for a faster connection?'], 'cta.p': ['免费下载,数分钟内开始你的第一次极速连接。', 'Download free and get connected in minutes.'], 'cta.btn': ['免费下载', 'Download free'], 'ft.tag': ['极简、轻量、亲和的跨平台网络加速应用。守护你的每一次连接。', 'A minimal, friendly cross-platform network accelerator. Protecting every connection.'], 'ft.product': ['产品', 'Product'], 'ft.resources': ['资源', 'Resources'], 'ft.contact': ['联系与渠道', 'Contact'], 'ft.features': ['功能', 'Features'], 'ft.pricing': ['定价', 'Pricing'], 'ft.download': ['下载', 'Download'], 'ft.docs': ['文档', 'Docs'], 'ft.blog': ['Blog', 'Blog'], 'ft.faq': ['常见问题', 'FAQ'], 'ft.privacy': ['隐私政策', 'Privacy'], 'ft.status': ['服务状态', 'Status'], 'ft.hours': ['服务时间 每日 9:00–24:00 (GMT+8)', 'Hours: Daily 9:00–24:00 (GMT+8)'], 'ft.copy': ['© 2026 穿山甲 · Pangolin', '© 2026 Pangolin'], 'ft.madenote': ['App 内不支持直接支付 · 资金流全走外部渠道', 'No in-app payment · all purchases via external channels'] }; let lang = localStorage.getItem('pg_site_lang') || 'zh'; function applyLang() { const i = lang === 'zh' ? 0 : 1; document.documentElement.lang = lang === 'zh' ? 'zh' : 'en'; document.querySelectorAll('[data-i18n]').forEach(el => { const k = el.getAttribute('data-i18n'); if (I18N[k]) el.textContent = I18N[k][i]; }); document.querySelectorAll('[data-i18n-ph]').forEach(el => { const k = el.getAttribute('data-i18n-ph'); if (I18N[k]) el.placeholder = I18N[k][i]; }); document.querySelectorAll('.langseg button').forEach(b => b.classList.toggle('on', b.dataset.lang === lang)); } window.__setLang = function (l) { lang = l; localStorage.setItem('pg_site_lang', l); applyLang(); }; // ---------- pricing monthly/yearly ---------- const PRICES = { free: ['¥0', '¥0'], pro: ['¥25', '¥20'], team: ['¥99', '¥79'] }; let cycle = 'monthly'; window.__setCycle = function (c) { cycle = c; const i = c === 'monthly' ? 0 : 1; document.querySelectorAll('[data-price]').forEach(el => { const p = el.getAttribute('data-price'); el.firstChild.textContent = PRICES[p][i]; }); document.querySelectorAll('.price-toggle button').forEach(b => b.classList.toggle('on', b.dataset.cycle === c)); }; // ---------- signup (demo: real impl sends a verification code) ---------- window.__signup = function (e) { e.preventDefault(); const em = document.getElementById('su-email'); if (!/\S+@\S+\.\S+/.test(em.value)) { em.focus(); return false; } document.getElementById('su-ok').hidden = false; return false; }; // ---------- announcement bar ---------- window.__closeAnn = function () { const a = document.getElementById('ann'); if (a) a.remove(); }; // ---------- mobile menu ---------- window.__toggleMenu = function () { document.getElementById('mnav').classList.toggle('open'); }; // ---------- scroll glass header ---------- function onScroll() { document.querySelector('.hdr').classList.toggle('scrolled', window.scrollY > 8); } window.addEventListener('scroll', onScroll, { passive: true }); // ---------- init ---------- document.addEventListener('DOMContentLoaded', function () { applyLang(); onScroll(); // close mobile menu when a link is tapped document.querySelectorAll('#mnav a').forEach(a => a.addEventListener('click', () => document.getElementById('mnav').classList.remove('open'))); if (window.lucide) lucide.createIcons(); }); })(); })(); } catch (e) { __ds_ns.__errors.push({ path: "ui_kits/website/site.js", error: String((e && e.message) || e) }); } })();