cicy-desktop 2.1.200 → 2.1.201
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/src/app-updater.js +164 -94
- package/src/backends/homepage-preload.js +1 -0
- package/src/backends/homepage-react/assets/index-BShnCn32.css +1 -0
- package/src/backends/homepage-react/assets/index-DTbVwDSc.js +377 -0
- package/src/backends/homepage-react/index.html +2 -2
- package/src/backends/ipc.js +1 -0
- package/src/i18n/locales/en.json +8 -0
- package/src/i18n/locales/fr.json +8 -0
- package/src/i18n/locales/ja.json +8 -0
- package/src/i18n/locales/zh-CN.json +8 -0
- package/src/main.js +2 -2
- package/src/sidecar/mirrors.js +10 -5
- package/src/utils/window-utils.js +8 -0
- package/workers/render/src/App.css +33 -0
- package/workers/render/src/App.jsx +49 -0
- package/src/backends/homepage-react/assets/index-BdfzcJ59.css +0 -1
- package/src/backends/homepage-react/assets/index-QFlSWxJR.js +0 -377
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="./favicon.svg" />
|
|
7
7
|
<link rel="icon" type="image/png" sizes="256x256" href="./favicon-256.png" />
|
|
8
8
|
<title>CiCy Desktop</title>
|
|
9
|
-
<script type="module" crossorigin src="./assets/index-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
9
|
+
<script type="module" crossorigin src="./assets/index-DTbVwDSc.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="./assets/index-BShnCn32.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<div id="root"></div>
|
package/src/backends/ipc.js
CHANGED
|
@@ -172,6 +172,7 @@ function register(opts = {}) {
|
|
|
172
172
|
const appUpdater = require("../app-updater");
|
|
173
173
|
ipcMain.handle("app:update-state", () => appUpdater.getState());
|
|
174
174
|
ipcMain.handle("app:check-update", async () => { await appUpdater.check(); return appUpdater.getState(); });
|
|
175
|
+
ipcMain.handle("app:download-update", async () => { await appUpdater.downloadUpdate(); return appUpdater.getState(); }); // 用户点「下载」→ 按平台/网络下安装包(带进度,可重试)
|
|
175
176
|
ipcMain.handle("app:install-update", () => { appUpdater.installNow(); return true; });
|
|
176
177
|
|
|
177
178
|
// Static version info: cicy-desktop's own version + the cicy-code version we
|
package/src/i18n/locales/en.json
CHANGED
|
@@ -484,5 +484,13 @@
|
|
|
484
484
|
"noContainerConfig": "Could not read container mihomo config",
|
|
485
485
|
"binMissing": "mihomo binary missing (run ensureBinary first)",
|
|
486
486
|
"configMissing": "host config missing (run writeConfig first)"
|
|
487
|
+
},
|
|
488
|
+
"updateBanner": {
|
|
489
|
+
"available": "New version v{{v}} available",
|
|
490
|
+
"downloading": "Downloading update",
|
|
491
|
+
"ready": "Update downloaded — restart to install",
|
|
492
|
+
"error": "Update failed",
|
|
493
|
+
"downloadBtn": "Download",
|
|
494
|
+
"installBtn": "Install now"
|
|
487
495
|
}
|
|
488
496
|
}
|
package/src/i18n/locales/fr.json
CHANGED
|
@@ -484,5 +484,13 @@
|
|
|
484
484
|
"noContainerConfig": "Impossible de lire la config mihomo du conteneur",
|
|
485
485
|
"binMissing": "Binaire mihomo manquant (exécutez dabord ensureBinary)",
|
|
486
486
|
"configMissing": "Config host manquante (exécutez dabord writeConfig)"
|
|
487
|
+
},
|
|
488
|
+
"updateBanner": {
|
|
489
|
+
"available": "Nouvelle version v{{v}} disponible",
|
|
490
|
+
"downloading": "Téléchargement de la mise à jour",
|
|
491
|
+
"ready": "Téléchargé — redémarrez pour installer",
|
|
492
|
+
"error": "Échec de la mise à jour",
|
|
493
|
+
"downloadBtn": "Télécharger",
|
|
494
|
+
"installBtn": "Installer"
|
|
487
495
|
}
|
|
488
496
|
}
|
package/src/i18n/locales/ja.json
CHANGED
|
@@ -484,5 +484,13 @@
|
|
|
484
484
|
"noContainerConfig": "コンテナの mihomo 設定を取得できませんでした",
|
|
485
485
|
"binMissing": "mihomo バイナリがありません(先に ensureBinary)",
|
|
486
486
|
"configMissing": "host 設定がありません(先に writeConfig)"
|
|
487
|
+
},
|
|
488
|
+
"updateBanner": {
|
|
489
|
+
"available": "新しいバージョン v{{v}} が利用可能",
|
|
490
|
+
"downloading": "アップデートをダウンロード中",
|
|
491
|
+
"ready": "ダウンロード完了 — 再起動でインストール",
|
|
492
|
+
"error": "アップデート失敗",
|
|
493
|
+
"downloadBtn": "ダウンロード",
|
|
494
|
+
"installBtn": "今すぐインストール"
|
|
487
495
|
}
|
|
488
496
|
}
|
|
@@ -484,5 +484,13 @@
|
|
|
484
484
|
"noContainerConfig": "没有拿到容器 mihomo 配置",
|
|
485
485
|
"binMissing": "mihomo 二进制不存在(先 ensureBinary)",
|
|
486
486
|
"configMissing": "host 配置不存在(先 writeConfig)"
|
|
487
|
+
},
|
|
488
|
+
"updateBanner": {
|
|
489
|
+
"available": "发现新版本 v{{v}}",
|
|
490
|
+
"downloading": "正在下载更新",
|
|
491
|
+
"ready": "新版本已下载,重启即可安装",
|
|
492
|
+
"error": "更新失败",
|
|
493
|
+
"downloadBtn": "下载",
|
|
494
|
+
"installBtn": "立即安装"
|
|
487
495
|
}
|
|
488
496
|
}
|
package/src/main.js
CHANGED
|
@@ -1205,10 +1205,10 @@ electronApp.whenReady().then(async () => {
|
|
|
1205
1205
|
// already run via the existing event handlers in app-updater.init() — we
|
|
1206
1206
|
// just surface the verdict so the user knows their click had effect.
|
|
1207
1207
|
async function onCheckForUpdatesClicked() {
|
|
1208
|
-
const result = await appUpdater.
|
|
1208
|
+
const result = await appUpdater.check();
|
|
1209
1209
|
const currentVersion = electronApp.getVersion();
|
|
1210
1210
|
if (result.status === "available") {
|
|
1211
|
-
const v =
|
|
1211
|
+
const v = result.version || "?";
|
|
1212
1212
|
dialog.showMessageBox({
|
|
1213
1213
|
type: "info",
|
|
1214
1214
|
message: i18n.t("menu.updateAvailable", { version: v }),
|
package/src/sidecar/mirrors.js
CHANGED
|
@@ -8,12 +8,15 @@
|
|
|
8
8
|
//
|
|
9
9
|
// All current mirrors are prepend-style. Add domain-style entries as needed.
|
|
10
10
|
|
|
11
|
+
// 自更新 CN feed 首选 OSS(自建,稳)。gh-proxy.com 反代已删(不稳/有问题);
|
|
12
|
+
// ghproxy.net 留作 OSS 不可达时的兜底镜像。非 CN 走 GitHub 直连(见 app-updater)。
|
|
13
|
+
const OSS_RELEASES_BASE = process.env.CICY_OSS_RELEASES_BASE
|
|
14
|
+
|| "https://cicy-1372193042-cn.oss-cn-shanghai.aliyuncs.com/releases";
|
|
15
|
+
|
|
11
16
|
const MIRRORS = [
|
|
12
|
-
// gh.llkk.cc
|
|
13
|
-
//
|
|
14
|
-
// are healthy. Re-add only after re-validating reachability.
|
|
17
|
+
// gh.llkk.cc / gh-proxy.com removed — unreachable / unstable from APAC.
|
|
18
|
+
// Re-add only after re-validating reachability.
|
|
15
19
|
{ url: "https://ghproxy.net/", type: "prepend" },
|
|
16
|
-
{ url: "https://gh-proxy.com/", type: "prepend" },
|
|
17
20
|
// { url: "hub.gitmirror.com", type: "domain" }, // example domain-replace
|
|
18
21
|
];
|
|
19
22
|
|
|
@@ -57,6 +60,8 @@ async function resolveFeedUrl(feedBase) {
|
|
|
57
60
|
req.end();
|
|
58
61
|
});
|
|
59
62
|
|
|
63
|
+
// CN 首选 OSS:OSS 上有 electron-updater feed(latest*.yml)才用它。
|
|
64
|
+
if (await probe(OSS_RELEASES_BASE + "/latest.yml")) return OSS_RELEASES_BASE;
|
|
60
65
|
for (const m of MIRRORS) {
|
|
61
66
|
const base = mirrorUrl(feedBase, m);
|
|
62
67
|
if (await probe(base + "/latest.yml")) return base;
|
|
@@ -64,4 +69,4 @@ async function resolveFeedUrl(feedBase) {
|
|
|
64
69
|
return feedBase; // fallback: direct
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
module.exports = { MIRRORS, mirrorUrl, buildUrlList, resolveFeedUrl };
|
|
72
|
+
module.exports = { MIRRORS, OSS_RELEASES_BASE, mirrorUrl, buildUrlList, resolveFeedUrl };
|
|
@@ -83,6 +83,14 @@ function setupWindowHandlers(win) {
|
|
|
83
83
|
if (!ses._autoDownloadEnabled) {
|
|
84
84
|
ses._autoDownloadEnabled = true;
|
|
85
85
|
ses.on("will-download", (event, item, webContents) => {
|
|
86
|
+
// File-explorer downloads (/api/fs/download) should let the user choose
|
|
87
|
+
// where to save: leave savePath unset so Electron shows the native Save As
|
|
88
|
+
// dialog. Everything else keeps the silent auto-save to ~/Downloads/electron.
|
|
89
|
+
const dlUrl = (() => { try { return item.getURL() || ""; } catch { return ""; } })();
|
|
90
|
+
if (dlUrl.includes("/api/fs/download")) {
|
|
91
|
+
log.info(`[Download] save-as dialog for ${item.getFilename()}`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
86
94
|
// 如果没有设置 savePath,自动保存
|
|
87
95
|
setTimeout(() => {
|
|
88
96
|
if (!item.getSavePath()) {
|
|
@@ -365,6 +365,39 @@ body {
|
|
|
365
365
|
.bcard--skeleton__head { display: flex; align-items: center; gap: 12px; }
|
|
366
366
|
.bcard--skeleton__lines { flex: 1; min-width: 0; }
|
|
367
367
|
|
|
368
|
+
/* ── App 自更新 banner(顶部细条)──────────────────────────────────────────────── */
|
|
369
|
+
.update-banner {
|
|
370
|
+
position: relative; flex: 0 0 auto;
|
|
371
|
+
padding: 9px 14px 9px 16px; font-size: 13px;
|
|
372
|
+
border-bottom: 1px solid rgba(255,255,255,.06);
|
|
373
|
+
background: rgba(59,130,246,.10); /* available: accent tint */
|
|
374
|
+
}
|
|
375
|
+
.update-banner--ready { background: rgba(34,197,94,.12); }
|
|
376
|
+
.update-banner--error { background: rgba(239,68,68,.12); }
|
|
377
|
+
.update-banner--downloading { background: rgba(255,255,255,.05); }
|
|
378
|
+
.update-banner__row { display: flex; align-items: center; gap: 10px; }
|
|
379
|
+
.update-banner__icon {
|
|
380
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
381
|
+
width: 18px; height: 18px; border-radius: 50%; flex: 0 0 auto;
|
|
382
|
+
font-size: 12px; font-weight: 700; color: #fff;
|
|
383
|
+
background: linear-gradient(135deg,#3b82f6,#8b5cf6);
|
|
384
|
+
}
|
|
385
|
+
.update-banner--ready .update-banner__icon { background: #22c55e; }
|
|
386
|
+
.update-banner--error .update-banner__icon { background: #ef4444; }
|
|
387
|
+
.update-banner--downloading .update-banner__icon { background: transparent; color: #7aa2f7; }
|
|
388
|
+
.update-banner__text { flex: 1; min-width: 0; color: #e6edf3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
389
|
+
.update-banner__actions { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
|
|
390
|
+
.update-banner__btn {
|
|
391
|
+
border: none; border-radius: 7px; padding: 5px 14px; font-size: 12px; font-weight: 600;
|
|
392
|
+
cursor: pointer; color: #fff; background: rgba(255,255,255,.12);
|
|
393
|
+
}
|
|
394
|
+
.update-banner__btn.is-accent { background: linear-gradient(135deg,#3b82f6,#8b5cf6); }
|
|
395
|
+
.update-banner__btn:hover { filter: brightness(1.12); }
|
|
396
|
+
.update-banner__x { border: none; background: transparent; color: #9aa0a6; font-size: 18px; line-height: 1; cursor: pointer; padding: 0 4px; border-radius: 6px; }
|
|
397
|
+
.update-banner__x:hover { color: #e6edf3; background: rgba(255,255,255,.08); }
|
|
398
|
+
.update-banner__bar { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: rgba(255,255,255,.08); overflow: hidden; }
|
|
399
|
+
.update-banner__bar > span { display: block; height: 100%; background: linear-gradient(90deg,#3b82f6,#8b5cf6); transition: width .2s ease; }
|
|
400
|
+
|
|
368
401
|
/* ── Tabs row ── */
|
|
369
402
|
.app__tabs {
|
|
370
403
|
display: inline-flex;
|
|
@@ -900,6 +900,7 @@ export default function App() {
|
|
|
900
900
|
<div className="shell__left">
|
|
901
901
|
<Header me={me} welcome={welcome} onLogout={handleLogout}
|
|
902
902
|
mitmTeam={localList.length > 0 ? localList[0] : null} />
|
|
903
|
+
<UpdateBanner />
|
|
903
904
|
<main className="main">
|
|
904
905
|
{/* 整行:左边 tab 药丸,右边「新加团队」顶到行尾 */}
|
|
905
906
|
<div className="app__tabsrow">
|
|
@@ -3128,6 +3129,54 @@ function Brand() {
|
|
|
3128
3129
|
);
|
|
3129
3130
|
}
|
|
3130
3131
|
|
|
3132
|
+
// app 自更新 banner(产品级):顶部细条,跟随 app:update-state。
|
|
3133
|
+
// available → 「发现新版本 vX [下载]」(可关闭)
|
|
3134
|
+
// downloading→ 进度条 + 「45% · 32.1/72.4 MB」(不可关,可后台)
|
|
3135
|
+
// ready → 「已下载,重启安装 [立即安装] [稍后]」
|
|
3136
|
+
// error → 「更新失败:… [重试]」(可关闭)
|
|
3137
|
+
function UpdateBanner() {
|
|
3138
|
+
const [st, setSt] = useState(null);
|
|
3139
|
+
const [dismissed, setDismissed] = useState(false);
|
|
3140
|
+
useEffect(() => {
|
|
3141
|
+
let alive = true;
|
|
3142
|
+
window.cicy?.app?.updateState?.().then((s) => { if (alive) setSt(s); }).catch(() => {});
|
|
3143
|
+
const unsub = window.cicy?.app?.onUpdateState?.((s) => setSt(s));
|
|
3144
|
+
return () => { alive = false; try { unsub && unsub(); } catch {} };
|
|
3145
|
+
}, []);
|
|
3146
|
+
const status = st?.status;
|
|
3147
|
+
// 每次状态变化都重置「已关闭」——新状态(如下载完成)要重新出现。
|
|
3148
|
+
useEffect(() => { setDismissed(false); }, [status]);
|
|
3149
|
+
const IMPORTANT = ["available", "downloading", "ready", "error"];
|
|
3150
|
+
if (!IMPORTANT.includes(status) || dismissed) return null;
|
|
3151
|
+
const p = st?.progress || {};
|
|
3152
|
+
const mb = (b) => (b ? (b / 1048576).toFixed(1) : "0");
|
|
3153
|
+
const download = () => { window.cicy?.app?.downloadUpdate?.(); };
|
|
3154
|
+
const install = () => { window.cicy?.app?.installUpdate?.(); };
|
|
3155
|
+
return (
|
|
3156
|
+
<div className={`update-banner update-banner--${status}`} data-id="UpdateBanner" data-status={status}>
|
|
3157
|
+
<div className="update-banner__row">
|
|
3158
|
+
<span className="update-banner__icon" aria-hidden>
|
|
3159
|
+
{status === "downloading" ? <Spinner /> : status === "ready" ? "✓" : status === "error" ? "!" : "↑"}
|
|
3160
|
+
</span>
|
|
3161
|
+
<span className="update-banner__text" data-id="UpdateBanner-text">
|
|
3162
|
+
{status === "available" && tr("updateBanner.available", "发现新版本 v{{v}}", { v: st.version })}
|
|
3163
|
+
{status === "downloading" && `${tr("updateBanner.downloading", "正在下载更新")} ${p.percent || 0}%${p.total ? ` · ${mb(p.transferred)}/${mb(p.total)} MB` : ""}`}
|
|
3164
|
+
{status === "ready" && tr("updateBanner.ready", "新版本已下载,重启即可安装")}
|
|
3165
|
+
{status === "error" && `${tr("updateBanner.error", "更新失败")}${st.error ? `:${st.error}` : ""}`}
|
|
3166
|
+
</span>
|
|
3167
|
+
<div className="update-banner__actions">
|
|
3168
|
+
{status === "available" && <button type="button" className="update-banner__btn is-accent" data-id="UpdateBanner-download" onClick={download}>{tr("updateBanner.downloadBtn", "下载")}</button>}
|
|
3169
|
+
{status === "ready" && <button type="button" className="update-banner__btn is-accent" data-id="UpdateBanner-install" onClick={install}>{tr("updateBanner.installBtn", "立即安装")}</button>}
|
|
3170
|
+
{status === "error" && <button type="button" className="update-banner__btn is-accent" data-id="UpdateBanner-retry" onClick={download}>{tr("common.retry", "重试")}</button>}
|
|
3171
|
+
{status !== "downloading" && <button type="button" className="update-banner__x" data-id="UpdateBanner-dismiss" onClick={() => setDismissed(true)} aria-label="dismiss">×</button>}
|
|
3172
|
+
</div>
|
|
3173
|
+
</div>
|
|
3174
|
+
{status === "downloading" && (
|
|
3175
|
+
<div className="update-banner__bar" data-id="UpdateBanner-bar"><span style={{ width: `${p.percent || 0}%` }} /></div>
|
|
3176
|
+
)}
|
|
3177
|
+
</div>
|
|
3178
|
+
);
|
|
3179
|
+
}
|
|
3131
3180
|
// 首次加载的团队卡占位骨架(与 .bcard 大致同形:头像圈 + 两行标题 + CTA 条)。
|
|
3132
3181
|
function SkeletonCard() {
|
|
3133
3182
|
return (
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@font-face{font-family:Noto Sans Mono CJK SC;src:url(./NotoMonoSC-Regular-CYHoGOBB.woff2) format("woff2");font-weight:400;font-style:normal;font-display:swap}:root{--mono: "Noto Sans Mono CJK SC", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace}:root{--accent: #5b8df7;--accent-soft: rgba(91,141,247,.16);--accent-line: rgba(91,141,247,.32);--accent-text: #a5c4ff;--ok: #4ade80;--danger: #f7a3a3;--text: #e5e7eb;--text-dim: #9da7b3;--text-mute: #6b7280;--line: rgba(255,255,255,.08)}*{box-sizing:border-box}html,body,#root{margin:0;height:100%}html,body{overflow:hidden}body{font-family:-apple-system,BlinkMacSystemFont,PingFang SC,Segoe UI,Roboto,Helvetica Neue,sans-serif;background:#07080c;color:#e5e7eb;-webkit-font-smoothing:antialiased}.shell{position:relative;min-height:100vh;display:flex;align-items:center;justify-content:center;overflow:hidden;-webkit-app-region:drag}.shell--app{align-items:stretch;justify-content:stretch;flex-direction:row;background:linear-gradient(180deg,#0b0d13,#07080c);overflow:hidden;-webkit-app-region:no-drag}.shell__left{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;overflow:hidden}.helper-aside{flex:0 0 auto;position:relative;background:#0f1115;border-left:1px solid rgba(255,255,255,.06);display:flex;flex-direction:column;min-width:320px;z-index:1}.helper-aside,.helper-aside *,.shell--app .main{-webkit-app-region:no-drag}.shell--app .topbar{-webkit-app-region:drag}.shell--app .topbar .user-chip,.shell--app .topbar .user-chip *,.shell--app .topbar .btn-ghost{-webkit-app-region:no-drag}.glow{position:absolute;top:-40%;right:-40%;bottom:-40%;left:-40%;z-index:0;pointer-events:none;background:radial-gradient(closest-side,rgba(91,141,247,.2),transparent 60%),radial-gradient(closest-side at 30% 70%,rgba(167,139,250,.13),transparent 65%);filter:blur(30px)}.card{-webkit-app-region:no-drag;position:relative;z-index:1;width:380px;padding:36px 36px 28px;background:linear-gradient(180deg,#141820d9,#0d1016d9);border:1px solid rgba(255,255,255,.06);border-radius:16px;box-shadow:0 1px #ffffff0a inset,0 30px 60px #0006;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);display:flex;flex-direction:column;align-items:center;gap:18px}.brand{display:flex;align-items:center;gap:12px;align-self:stretch}.brand-mark{width:40px;height:40px;border-radius:12px;display:grid;place-items:center;background:linear-gradient(135deg,#5b8df7,#a78bfa);box-shadow:0 8px 20px #5b8df759}.brand-mark.sm{width:28px;height:28px;border-radius:8px;box-shadow:none}.brand-mark.sm svg{width:16px;height:16px}.brand-text{line-height:1.2}.brand-name{font-weight:600;font-size:15px}.brand-sub{font-size:12px;color:#9ca3af;margin-top:2px}.tagline{margin:4px 0 0;color:#c7cdd6;font-size:13.5px;text-align:center;line-height:1.55}.btn-primary{-webkit-app-region:no-drag;margin-top:4px;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:42px;display:inline-flex;align-items:center;justify-content:center;gap:8px;background:linear-gradient(180deg,#5b8df7,#4570d8);color:#fff;border:0;border-radius:10px;font-size:14px;font-weight:500;letter-spacing:.2px;cursor:pointer;box-shadow:0 1px #ffffff2e inset,0 -1px #0000002e inset,0 10px 22px #5b8df747;transition:transform 80ms ease,filter .12s ease}.btn-primary:hover{filter:brightness(1.08)}.btn-primary:active{transform:translateY(1px)}.btn-primary:disabled{filter:grayscale(.4) brightness(.7);cursor:default}.btn-ghost{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;color:#9ca3af;border:1px solid rgba(255,255,255,.08);border-radius:8px;padding:6px 14px;font-size:12.5px;cursor:pointer;transition:color .12s ease,border-color .12s ease,background .12s ease}.btn-ghost.sm{padding:4px 10px;font-size:11.5px}.btn-ghost:hover{color:#e5e7eb;background:#ffffff0a;border-color:#ffffff24}.btn-ghost:disabled{opacity:.4;cursor:default}.modal-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:18px}.modal-actions .btn-primary{width:auto;margin-top:0;padding:0 18px}.modal-actions .btn-ghost,.modal-actions .btn-primary{flex:0 0 auto;white-space:nowrap}.login-divider{display:flex;align-items:center;gap:10px;margin:4px 0;color:#6b7280;font-size:11.5px}.login-divider:before,.login-divider:after{content:"";flex:1;height:1px;background:#ffffff14}.login-email-input{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;box-sizing:border-box;background:#ffffff08;color:#e5e7eb;border:1px solid rgba(255,255,255,.1);border-radius:8px;padding:8px 12px;font-size:13px;transition:border-color .12s ease,background .12s ease}.login-email-input::placeholder{color:#6b7280}.login-email-input:focus{outline:none;border-color:#6366f18c;background:#ffffff0d}.hint{margin:0;font-size:11.5px;color:#6b7280}.spinner-row{display:inline-flex;align-items:center;gap:8px;color:#c7cdd6;font-size:13px}.spin{animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.error{width:100%;font-size:12px;color:#fca5a5;background:#ef444414;border:1px solid rgba(239,68,68,.18);padding:8px 12px;border-radius:8px;text-align:center;line-height:1.5}.topbar{-webkit-app-region:drag;position:relative;flex:0 0 auto;z-index:10;display:flex;align-items:center;justify-content:space-between;padding:14px 24px 12px;background:#08090e99;border-bottom:1px solid rgba(255,255,255,.05);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}[data-platform=darwin][data-fullscreen="0"] .topbar{padding-top:34px}.brand-mini{display:inline-flex;align-items:center;gap:10px}.topbar .user-chip{margin-left:auto}.brand-mini .brand-name{font-size:14px}.user-chip{-webkit-app-region:no-drag;display:inline-flex;align-items:center;gap:10px}.welcome{font-size:12px;color:var(--text-dim);padding:4px 10px;border-radius:999px;background:#ffffff0d;border:1px solid var(--line);animation:fadein .2s ease}@keyframes fadein{0%{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:none}}.avatar{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;background:linear-gradient(135deg,#5b8df7,#a78bfa);font-size:12px;font-weight:600;color:#fff}.user-name{font-size:13px;color:#c7cdd6}.user-chip{position:relative}.user-chip__trigger{-webkit-app-region:no-drag;display:inline-flex;align-items:center;gap:8px;border:1px solid transparent;background:transparent;border-radius:999px;padding:3px 8px 3px 3px;cursor:pointer;transition:.12s}.user-chip__trigger:hover,.user-chip__trigger.is-open{background:#ffffff0f;border-color:#ffffff1f}.user-chip__caret{font-size:10px;color:#8a93a3;transition:transform .12s}.user-chip__trigger.is-open .user-chip__caret{transform:rotate(180deg)}.user-chip__menu{position:absolute;top:38px;right:0;z-index:30;min-width:200px;padding:6px;background:#1b2027;border:1px solid rgba(255,255,255,.12);border-radius:12px;box-shadow:0 12px 34px #00000080;display:flex;flex-direction:column;gap:2px;animation:fadein .14s ease}.user-chip__menu-item{text-align:left;width:100%;border:none;background:transparent;color:#d1d5db;border-radius:8px;padding:9px 11px;font-size:13px;cursor:pointer;transition:.12s}.user-chip__menu-item:hover{background:#ffffff12;color:#fff}.user-chip__menu-item.is-danger{color:#f7a3a3}.user-chip__menu-item.is-danger:hover{background:#ef444429;color:#fff}.user-chip__menu-sep{height:1px;margin:4px 2px;background:#ffffff14}.user-chip__menu-version{margin-top:4px;padding:8px 11px 4px;font-size:11px;color:#6b7280;text-align:center;font-variant-numeric:tabular-nums;-webkit-user-select:text;user-select:text;border-top:1px solid rgba(255,255,255,.06)}.user-chip__mitm-row{display:flex;align-items:center;justify-content:space-between;gap:10px;cursor:default}.user-chip__mitm-row:hover{background:transparent}.user-chip__mitm-label{font-size:13px;color:var(--text)}.mini-switch{-webkit-app-region:no-drag;position:relative;flex:0 0 auto;width:36px;height:20px;padding:0;border-radius:999px;border:1px solid var(--line);background:#ffffff14;cursor:pointer;transition:background .16s ease,border-color .16s ease}.mini-switch.is-on{background:var(--accent);border-color:var(--accent)}.mini-switch.is-busy{opacity:.6;cursor:default}.mini-switch:disabled{cursor:default}.mini-switch__knob{position:absolute;top:1px;left:1px;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px #00000073;transition:transform .16s ease}.mini-switch.is-on .mini-switch__knob{transform:translate(16px)}.mini-switch.is-busy .mini-switch__knob{animation:spin 1s linear infinite}.user-chip__mitm-note{margin:0 4px;padding:2px 4px 6px;font-size:11px;color:var(--text-mute)}.user-chip__mitm-err{margin:2px 4px 6px;padding:5px 8px;font-size:11px;color:var(--danger);background:#ef44441a;border-radius:6px;line-height:1.4}.bcard__top-right{display:inline-flex;align-items:center;gap:6px}.bcard__billing-btn{-webkit-app-region:no-drag;border:1px solid var(--line);background:transparent;color:var(--text-dim);border-radius:7px;padding:3px 9px;font-size:11px;cursor:pointer;transition:color .12s,border-color .12s,background .12s}.bcard__billing-btn:hover{color:var(--accent-text);border-color:var(--accent-line);background:var(--accent-soft)}.glow--app{inset:-10% -10% auto -10%;height:50vh;background:radial-gradient(closest-side at 75% 0%,rgba(91,141,247,.18),transparent 65%),radial-gradient(closest-side at 20% 10%,rgba(167,139,250,.1),transparent 60%);filter:blur(40px)}.main{position:relative;z-index:1;padding:22px 32px 48px;width:100%;display:flex;flex-direction:column;gap:16px;flex:1 1 auto;min-height:0;overflow-y:auto}.main::-webkit-scrollbar{width:8px}.main::-webkit-scrollbar-track{background:transparent}.main::-webkit-scrollbar-thumb{background:#7d87964d;border-radius:999px;border:2px solid transparent;background-clip:padding-box}.main::-webkit-scrollbar-thumb:hover{background-color:#7d87968c}*::-webkit-scrollbar{width:8px;height:8px}*::-webkit-scrollbar-track{background:transparent}*::-webkit-scrollbar-thumb{background:#7d87964d;border-radius:999px;border:2px solid transparent;background-clip:padding-box}*::-webkit-scrollbar-thumb:hover{background:#7d87968c;background-clip:padding-box}*::-webkit-scrollbar-corner{background:transparent}*{scrollbar-width:thin;scrollbar-color:rgba(125,135,150,.35) transparent}@keyframes cicy-shimmer{0%{background-position:-240px 0}to{background-position:calc(240px + 100%) 0}}.skel{background-color:#ffffff0d;background-image:linear-gradient(90deg,#fff0 0,#ffffff14,#fff0);background-size:240px 100%;background-repeat:no-repeat;animation:cicy-shimmer 1.25s ease-in-out infinite;border-radius:8px}.skel--avatar{width:30px;height:30px;border-radius:50%;flex:0 0 auto}.skel--name{width:72px;height:12px;border-radius:6px}.skel--line{height:12px;border-radius:6px}.skel--cta{height:34px;border-radius:9px;margin-top:16px}.user-chip__trigger--skel{display:inline-flex;align-items:center;gap:10px;cursor:default}.bcard--skeleton{pointer-events:none}.bcard--skeleton__head{display:flex;align-items:center;gap:12px}.bcard--skeleton__lines{flex:1;min-width:0}.app__tabs{display:inline-flex;align-items:center;gap:4px;padding:4px;background:#1418208c;border:1px solid rgba(255,255,255,.06);border-radius:10px;align-self:flex-start;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.app__tab{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;color:#9ca3af;border:0;border-radius:7px;padding:6px 14px;font-size:12.5px;font-weight:500;letter-spacing:.15px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;transition:color .12s ease,background .12s ease}.app__tab:hover{color:#e5e7eb;background:#ffffff0a}.app__tab.is-active{color:#fff;background:#5b8df72e;box-shadow:0 0 0 1px #5b8df74d inset}.app__tab-count{font-size:10.5px;color:#9ca3af;background:#ffffff0f;padding:1px 6px;border-radius:999px;min-width:18px;text-align:center}.app__tab.is-active .app__tab-count{background:#5b8df74d;color:#fff}.app__tabsrow{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%}.app__add-team{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer;flex:none;color:#5b8df7;font-weight:600;font-size:12.5px;background:#5b8df71a;border:1px solid rgba(91,141,247,.35);border-radius:9px;padding:7px 14px;transition:color .12s ease,background .12s ease,border-color .12s ease}.app__add-team:hover{color:#fff;background:#5b8df738;border-color:#5b8df7a6}.app__grid{display:grid;grid-template-columns:repeat(auto-fill,200px);gap:14px}.add-card{-webkit-app-region:no-drag;-webkit-appearance:none;-moz-appearance:none;appearance:none;width:200px;height:200px;background:transparent;border:1.5px dashed rgba(255,255,255,.12);border-radius:14px;color:#9ca3af;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;transition:border-color .16s ease,color .16s ease,background .16s ease}.add-card:hover{border-color:#5b8df780;color:#e5e7eb;background:#5b8df70d}.add-card__plus{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;background:#ffffff0a;font-size:22px;font-weight:300;color:inherit}.add-card__label{font-size:13px;font-weight:500}.bcard--helper{background:linear-gradient(160deg,#5b8df729,#a78bfa24 60%,#1418208c);border-color:#a78bfa40}.bcard--helper .bcard__accent{background:linear-gradient(90deg,#5b8df7,#a78bfa);opacity:1}.bcard--helper:hover{border-color:#a78bfa73}.bcard__pill--helper{background:#a78bfa2e;border-color:#a78bfa4d;color:#c4b5fd;font-size:11px;font-weight:600;letter-spacing:.2px}.bcard__helper-icon{font-size:12px;filter:grayscale(.2)}.bcard__badge--free{background:#34d39926;color:#34d399;border:1px solid rgba(52,211,153,.3)}.bcard__badge--trial{background:#ffffff0f;color:var(--text-dim);border:1px solid var(--line);font-size:9.5px;letter-spacing:.3px;padding:2px 7px}.bcard__badge--local{background:#5b8df72e;color:#a5c4ff;border:1px solid rgba(91,141,247,.35);font-size:9.5px;letter-spacing:.3px;padding:2px 7px}.bcard--helper .bcard__name{color:#f3f4f6}.bcard__desc{margin:4px 0 0;font-size:11.5px;line-height:1.5;color:#c7cdd6;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.bcard__fineprint{margin:4px 0 0;font-size:10.5px;color:#9ca3af;opacity:.8}.bcard__cta--helper{background:#ffffff0d;box-shadow:none}.bcard__cta--helper:hover{background:var(--accent-soft)}.helper-aside__top{display:flex;align-items:center;justify-content:space-between;padding:12px 14px 10px;border-bottom:1px solid rgba(255,255,255,.05)}.helper-aside__title{font-size:12.5px;font-weight:600;color:#c7cdd6}.helper-aside__close{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:transparent;border:0;color:#6b7280;font-size:20px;line-height:1;width:26px;height:26px;border-radius:6px;cursor:pointer;transition:color .12s ease,background .12s ease}.helper-aside__close:hover{color:#e5e7eb;background:#ffffff0f}.helper-modal__backdrop{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;background:transparent;z-index:20;animation:fadein .14s ease;padding:16px;pointer-events:auto}.helper-modal{width:min(360px,100%);background:linear-gradient(180deg,#1f2733,#1a2029);border:1px solid rgba(255,255,255,.1);border-radius:12px;padding:20px 22px 16px;color:#e5e7eb;box-shadow:0 24px 48px -12px #0009,0 1px #ffffff14 inset;animation:fadein .18s ease}.helper-modal__title{font-size:14px;font-weight:600;color:#f3f4f6;margin-bottom:8px}.helper-modal__desc{font-size:12.5px;line-height:1.6;color:#b6bcc6;margin-bottom:18px}.helper-modal__desc code{font-family:var(--mono);font-size:11.5px;padding:1px 6px;background:#ffffff14;border:1px solid rgba(255,255,255,.08);border-radius:4px;color:#e7eaef}.helper-modal__actions{display:flex;align-items:center;justify-content:flex-end;gap:8px}.helper-modal__btn{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:#ffffff0f;color:#d2d6dd;border:1px solid rgba(255,255,255,.1);border-radius:7px;padding:7px 14px;font-size:12.5px;font-weight:500;cursor:pointer;transition:background .12s ease,color .12s ease,transform 80ms ease}.helper-modal__btn:hover{background:#ffffff1a;color:#fff}.helper-modal__btn:active{transform:translateY(1px)}.helper-modal__btn--ghost{background:transparent;border-color:transparent;color:#ffffff8c;margin-right:auto;padding-left:4px;padding-right:4px}.helper-modal__btn--ghost:hover{background:transparent;color:#ffffffd9}.helper-modal__btn--primary{background:linear-gradient(180deg,#5b8df7,#4570d8);border-color:#ffffff2e;color:#fff}.helper-modal__btn--primary:hover{background:linear-gradient(180deg,#6c9af9,#5a82e0)}.helper-modal__btn:disabled{filter:grayscale(.4) brightness(.7);cursor:default}.helper-placeholder{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:32px 40px;text-align:center;color:#9ca3af}.helper-placeholder__mark{font-size:48px;line-height:1;filter:grayscale(.2);opacity:.85}.helper-placeholder__title{margin:0;font-size:16px;font-weight:600;color:#e5e7eb}.helper-placeholder__sub{margin:0;font-size:12.5px;line-height:1.6;color:#9ca3af;max-width:320px}.helper-placeholder__note{margin-top:8px;font-size:11px;color:#6b7280;padding:4px 10px;background:#ffffff08;border:1px solid rgba(255,255,255,.06);border-radius:999px}.helper-placeholder__note code{font-family:var(--mono);font-size:11px;color:#c7cdd6}.section{background:linear-gradient(180deg,#141820b8,#0d1016b8);border:1px solid rgba(255,255,255,.06);border-radius:14px;box-shadow:0 1px #ffffff0a inset,0 14px 30px #00000052;-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);padding:18px 18px 16px}.section-head{display:flex;align-items:center;gap:8px;padding:0 4px 14px;border-bottom:1px solid rgba(255,255,255,.04);margin-bottom:14px}.section-icon{font-size:14px;opacity:.8}.section-head h2{margin:0;font-size:13.5px;font-weight:600;color:#e5e7eb;letter-spacing:.2px}.section-sub{font-size:12px;color:#6b7280}.section-body{display:flex;flex-direction:column;gap:10px}.grid{display:grid;grid-template-columns:repeat(auto-fill,200px);gap:14px}.bcard{position:relative;width:200px;height:200px;background:#1418208c;border:1px solid rgba(255,255,255,.07);border-radius:14px;padding:16px;display:flex;flex-direction:column;overflow:hidden;transition:transform .18s ease,border-color .18s ease,box-shadow .18s ease;--brand: #5b8df7;--accent-cloud: #f59e0b;--accent-custom: #8b5cf6}.bcard:hover{transform:translateY(-2px);border-color:#ffffff24;box-shadow:0 12px 32px -10px #00000073,0 1px #ffffff0a inset}.bcard__accent{position:absolute;top:0;left:0;right:0;height:3px;background:var(--brand);opacity:.9}.bcard--cloud .bcard__accent{background:var(--accent-cloud)}.bcard--custom .bcard__accent{background:var(--accent-custom)}.bcard--online:before{content:"";position:absolute;bottom:-40%;right:-20%;width:140%;height:100%;background:radial-gradient(circle at center,rgba(91,141,247,.22) 0%,transparent 60%);pointer-events:none;opacity:.55}.bcard--cloud.bcard--online:before{background:radial-gradient(circle at center,rgba(245,158,11,.22) 0%,transparent 60%)}.bcard--custom.bcard--online:before{background:radial-gradient(circle at center,rgba(139,92,246,.22) 0%,transparent 60%)}.bcard__top{display:flex;align-items:center;justify-content:space-between;position:relative;z-index:5}.bcard__pill{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:#08090eb3;border:1px solid rgba(255,255,255,.07);border-radius:999px;color:#9ca3af}.bcard__pill svg{display:block}.bcard__dot{width:7px;height:7px;border-radius:50%;background:#6b7280;flex-shrink:0}.bcard__dot[data-tone=ok]{background:#34d399;box-shadow:0 0 0 2px #34d39940}.bcard__dot[data-tone=off]{background:#6b7280}.bcard__dot[data-tone=warn]{background:#fbbf24;box-shadow:0 0 0 2px #fbbf2440}.bcard__dot[data-tone=err]{background:#f87171;box-shadow:0 0 0 2px #f8717140}.bcard__badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:var(--accent-soft);color:var(--accent-text);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.5px}.bcard__body{flex:1;display:flex;flex-direction:column;gap:4px;padding-top:12px;padding-bottom:12px;position:relative;z-index:1;min-width:0}.bcard__name{margin:0;font-size:17px;font-weight:700;color:#e5e7eb;letter-spacing:-.015em;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bcard__host{font-family:var(--mono);font-size:11px;color:#9ca3af;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bcard__meta{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.bcard__chip{font-size:10.5px;color:#9ca3af;background:#ffffff08;border:1px solid rgba(255,255,255,.06);padding:2px 7px;border-radius:999px}.bcard__cta{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;gap:8px;width:100%;height:38px;border:1px solid var(--line);border-radius:9px;background:#ffffff0d;color:var(--text);font-size:13px;font-weight:600;letter-spacing:.1px;cursor:pointer;transition:transform 80ms ease,background .14s ease,border-color .14s ease,color .14s ease;box-shadow:none}.bcard--cloud .bcard__cta,.bcard--custom .bcard__cta{background:#ffffff0d;box-shadow:none}.bcard__cta:hover{background:var(--accent-soft);border-color:var(--accent-line);color:var(--accent-text)}.bcard__cta:active{transform:translateY(1px)}.bcard__cta:disabled{background:#ffffff08;color:#6b7280;cursor:not-allowed;box-shadow:none;border:1px solid rgba(255,255,255,.06)}.empty{font-size:12.5px;color:#6b7280;padding:14px 16px;background:#ffffff05;border:1px dashed rgba(255,255,255,.08);border-radius:10px}.bcard__menuwrap{position:relative}.bcard__kebab{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border:1px solid transparent;border-radius:8px;background:transparent;color:#8b949e;cursor:pointer;transition:.15s}.bcard__kebab:hover:not(:disabled){color:#e6edf3;background:#ffffff0f;border-color:#ffffff1f}.bcard__kebab:disabled{opacity:.5;cursor:default}.bcard__kebab.has-dot{color:#e6edf3}.bcard__kebab.has-dot:after{content:"";position:absolute;top:3px;right:3px;width:7px;height:7px;border-radius:50%;background:#f59e0b;box-shadow:0 0 0 2px #0f1115}.bcard__menu{position:absolute;top:32px;right:0;z-index:20;min-width:150px;padding:5px;background:#1b2027;border:1px solid rgba(255,255,255,.12);border-radius:10px;box-shadow:0 10px 30px #00000073;display:flex;flex-direction:column;gap:2px}.bcard__menu-item{text-align:left;width:100%;border:none;background:transparent;color:#d1d5db;border-radius:7px;padding:7px 10px;font-size:12.5px;cursor:pointer;transition:.12s}.bcard__menu-item:hover{background:#ffffff12;color:#fff}.bcard__menu-item.is-accent{color:var(--accent-text);font-weight:600}.bcard__menu-item.is-accent:hover{background:var(--accent-soft);color:#c7dbff}.bcard__menu-item.is-danger{color:#f7a3a3}.bcard__menu-item.is-danger:hover{background:#ef444429;color:#fff}.bcard__menu-sep{height:1px;margin:5px 10px;background:#ffffff14}.bcard__menu-item--switch{display:flex;align-items:center;justify-content:space-between;gap:10px}.bcard__switch{flex:none;width:30px;height:17px;border-radius:999px;background:#ffffff29;position:relative;transition:background .15s}.bcard__switch:after{content:"";position:absolute;top:2px;left:2px;width:13px;height:13px;border-radius:50%;background:#fff;transition:transform .15s}.bcard__switch.is-on{background:var(--accent-text, #4f8cff)}.bcard__switch.is-on:after{transform:translate(13px)}.bcard__menu--portal{z-index:9990}.bcard__menu--portal .bcard__menu-item{white-space:normal;word-break:break-word}.docker-setup{margin-bottom:14px;padding:14px 16px;background:linear-gradient(180deg,#5b8df714,#14182080);border:1px solid rgba(91,141,247,.22);border-radius:12px}.docker-setup__head{display:flex;flex-direction:column;gap:3px;margin-bottom:12px}.docker-setup__title{font-size:13.5px;font-weight:600;color:#e6edf3}.docker-setup__sub{font-size:11.5px;color:#9ca3af;line-height:1.5}.docker-setup__steps{display:flex;flex-direction:column;gap:6px;margin-bottom:12px}.docker-step{display:flex;align-items:center;gap:8px;font-size:12px;color:#9ca3af}.docker-step__dot{width:8px;height:8px;border-radius:50%;flex:none;background:#3a4150;transition:.2s}.docker-step__label{color:#c7cdd6;min-width:96px}.docker-step__msg{color:#8b949e;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.docker-step__pct{margin-left:auto;font-variant-numeric:tabular-nums;color:#5b8df7;flex:none}.docker-step.is-running .docker-step__dot{background:#5b8df7;box-shadow:0 0 0 3px #5b8df72e;animation:dpulse 1.2s ease-in-out infinite}.docker-step.is-running .docker-step__label{color:#e6edf3}.docker-step.is-done .docker-step__dot,.docker-step.is-skip .docker-step__dot{background:#10b981}.docker-step.is-skip{opacity:.7}.docker-step.is-retry .docker-step__dot{background:#f59e0b}.docker-step.is-error .docker-step__dot{background:#ef4444;box-shadow:0 0 0 3px #ef444426}.docker-step.is-error .docker-step__msg{color:#f7a3a3}@keyframes dpulse{0%,to{opacity:1}50%{opacity:.45}}.docker-setup__actions{display:flex;gap:8px;align-items:center}.docker-setup__actions .btn-primary{width:auto;padding:7px 16px;font-size:12.5px}.bcard__ver{font-size:11px;color:#8b949e;font-variant-numeric:tabular-nums}.bcard__chip--new{color:var(--accent-text);background:var(--accent-soft);border-color:var(--accent-line)}.bcard__opmsg{display:flex;align-items:center;gap:6px;margin-top:9px;font-size:11.5px;color:#9ca3af;word-break:break-word}.toast-host{position:fixed;right:16px;bottom:16px;z-index:9999;display:flex;flex-direction:column;gap:8px;max-width:min(360px,calc(100vw - 32px));pointer-events:none}.toast{pointer-events:auto;position:relative;display:flex;flex-direction:column;gap:6px;padding:10px 30px 10px 12px;font-size:12.5px;line-height:1.4;color:var(--text, #e6eaf0);background:#161a21f5;border:1px solid rgba(125,135,150,.22);border-left:3px solid var(--accent, #3b82f6);border-radius:10px;box-shadow:0 8px 28px #0000006b;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);animation:toast-in .18s ease}@keyframes toast-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}.toast[data-status=error]{border-left-color:#f87171}.toast[data-status=error] .toast__msg{color:#f87171}.toast[data-status=done]{border-left-color:#4ade80}.toast[data-status=done] .toast__msg{color:#4ade80}.toast__msg{word-break:break-word}.toast__x{position:absolute;top:6px;right:8px;background:none;border:none;cursor:pointer;padding:0;font-size:15px;line-height:1;color:var(--text-dim, #9da7b3)}.toast__x:hover{color:var(--text, #e6eaf0)}.toast__bar{display:block;height:4px;border-radius:2px;background:#7d879640;overflow:hidden}.toast__bar>span{display:block;height:100%;border-radius:2px;background:var(--accent, #3b82f6);transition:width .25s ease}.drawer-scrim{position:fixed;top:0;right:0;bottom:0;left:0;z-index:10000;display:flex;align-items:flex-end;justify-content:center;background:#06080c80;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);animation:drawer-fade .18s ease}@keyframes drawer-fade{0%{opacity:0}to{opacity:1}}.drawer{width:min(560px,calc(100vw - 24px));max-height:76vh;display:flex;flex-direction:column;margin-bottom:12px;background:#14181ffa;border:1px solid rgba(125,135,150,.2);border-radius:16px 16px 12px 12px;box-shadow:0 -10px 44px #00000080;overflow:hidden;animation:drawer-up .24s cubic-bezier(.22,1,.36,1)}@keyframes drawer-up{0%{opacity:0;transform:translateY(28px)}to{opacity:1;transform:none}}.drawer__head{display:flex;align-items:center;justify-content:space-between;padding:14px 14px 12px 16px;border-bottom:1px solid rgba(125,135,150,.14)}.drawer__title{display:flex;align-items:center;gap:11px}.drawer__spark{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:8px;font-size:14px;font-weight:700;background:#5b8df729;color:var(--brand, #5b8df7)}.drawer__spark--done{background:#4ade8029;color:#4ade80}.drawer__spark--error{background:#f8717129;color:#f87171}.drawer__h{font-size:13.5px;font-weight:650;color:var(--text, #e6eaf0)}.drawer__sub{font-size:11.5px;color:var(--text-dim, #9da7b3);margin-top:1px}.drawer__x{background:none;border:none;cursor:pointer;padding:2px 6px;font-size:19px;line-height:1;color:var(--text-dim, #9da7b3);border-radius:6px}.drawer__x:hover:not(:disabled){color:var(--text, #e6eaf0);background:#7d87961f}.drawer__x:disabled{opacity:.35;cursor:default}.drawer__steps{display:flex;align-items:center;gap:0;padding:14px 18px 4px}.drawer__step{display:flex;align-items:center;gap:7px;color:var(--text-dim, #9da7b3);font-size:12px}.drawer__step-dot{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;font-size:11px;font-weight:700;border:1.5px solid rgba(125,135,150,.35);color:var(--text-dim, #9da7b3);background:transparent;flex:none}.drawer__step-bar{width:30px;height:1.5px;background:#7d879640;margin:0 8px}.drawer__step.is-active .drawer__step-dot{border-color:var(--brand, #5b8df7);color:var(--brand, #5b8df7);box-shadow:0 0 0 3px #5b8df72e}.drawer__step.is-active .drawer__step-label{color:var(--text, #e6eaf0)}.drawer__step.is-done .drawer__step-dot{border-color:#4ade80;color:#06210f;background:#4ade80}.drawer__step.is-done .drawer__step-bar{background:#4ade8080}.drawer__step.is-error .drawer__step-dot{border-color:#f87171;color:#f87171}.drawer__log{flex:1;min-height:96px;overflow-y:auto;margin:10px 14px;padding:10px 12px;background:#0a0c10b3;border:1px solid rgba(125,135,150,.12);border-radius:10px;font-family:var(--mono);font-size:11.5px;line-height:1.7}.drawer__log--scroll{max-height:168px;scrollbar-width:thin;scrollbar-color:rgba(125,135,150,.4) transparent}.drawer__log--scroll::-webkit-scrollbar{width:7px}.drawer__log--scroll::-webkit-scrollbar-track{background:transparent;margin:4px 0}.drawer__log--scroll::-webkit-scrollbar-thumb{background:#7d879652;border-radius:6px;border:1.5px solid transparent;background-clip:padding-box}.drawer__log--scroll::-webkit-scrollbar-thumb:hover{background:#7d87968c;background-clip:padding-box}.drawer__now{display:flex;align-items:center;gap:9px;margin:12px 14px 2px;padding:9px 12px;background:#5b8df714;border:1px solid rgba(91,141,247,.2);border-radius:10px;font-size:12.5px;color:var(--text, #e6eaf0)}.drawer__now span{flex:1;min-width:0}.drawer__dlbars{display:flex;flex-direction:column;gap:10px;margin:12px 14px 2px}.dlbar{padding:10px 12px;border-radius:10px;background:#0a0c108c;border:1px solid rgba(125,135,150,.14)}.dlbar__head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:7px}.dlbar__name{font-size:12.5px;font-weight:600;color:var(--text, #e6eaf0)}.dlbar__pct{font-size:11px;color:var(--text-dim, #9da7b3);font-variant-numeric:tabular-nums}.dlbar__track{height:6px;border-radius:4px;background:#7d879629;overflow:hidden}.dlbar__fill{height:100%;border-radius:4px;background:linear-gradient(90deg,#5b8df7,#2496ed);transition:width .2s ease}.dlbar__fill.is-done{background:#4ade80}.dlbar__url{margin-top:6px;font-size:10.5px;color:#6b7686;font-family:var(--mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dlbar__urlk{display:inline-block;min-width:16px;text-align:center;margin-right:5px;padding:0 4px;border-radius:4px;font-family:inherit;font-size:9.5px;color:#8fb0f5;background:#5b8df729}.drawer__headbtns{display:flex;align-items:center;gap:2px}.drawer-min{position:fixed;right:20px;bottom:20px;z-index:2001;display:inline-flex;align-items:center;gap:9px;padding:10px 15px;border-radius:999px;cursor:pointer;background:#16181d;border:1px solid rgba(125,135,150,.22);box-shadow:0 10px 30px #00000080;color:var(--text, #e6eaf0);font-size:12.5px;font-weight:550;animation:drawer-min-in .18s cubic-bezier(.2,.8,.2,1)}.drawer-min:hover{border-color:#7d879666;background:#1b1e24}@keyframes drawer-min-in{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}.drawer-min__spark{display:inline-flex;width:16px;height:16px;align-items:center;justify-content:center;font-weight:700}.drawer-min--done .drawer-min__spark{color:#4ade80}.drawer-min--error .drawer-min__spark{color:#f87171}.drawer-min__label{font-variant-numeric:tabular-nums}.drawer__log-empty{color:var(--text-dim, #9da7b3)}.drawer__line{display:flex;align-items:baseline;gap:8px;padding:1px 0}.drawer__t{color:#6b7686;flex:none;font-variant-numeric:tabular-nums}.drawer__badge{flex:none;padding:0 6px;border-radius:4px;font-size:10px;font-weight:600;background:#5b8df729;color:#8fb0f5}.drawer__badge--swap{background:#f59e0b29;color:#f5b342}.drawer__badge--done{background:#4ade8029;color:#6ee79b}.drawer__linemsg{color:var(--text, #e6eaf0);word-break:break-word}.drawer__line[data-status=error] .drawer__linemsg{color:#f87171}.drawer__line[data-status=done] .drawer__linemsg{color:#6ee79b}.drawer__line[data-status=skip] .drawer__linemsg{color:var(--text-dim, #9da7b3)}.drawer__hint{margin:0 14px 8px;padding:8px 12px;background:#f59e0b1a;border:1px solid rgba(245,158,11,.28);border-radius:8px;color:#f5b342;font-size:11.5px;line-height:1.5}.drawer__foot{display:flex;align-items:center;gap:8px;padding:12px 14px;border-top:1px solid rgba(125,135,150,.14)}.drawer__foot-status{font-size:12.5px;color:var(--text-dim, #9da7b3);margin-right:auto}.drawer__foot-status.is-error{color:#f87171}.drawer__foot-status.is-done{color:#4ade80}.drawer__foot-status.is-reboot,.drawer__spark--reboot,.drawer-min--reboot .drawer-min__spark{color:#f5b342}.drawer__btn{padding:7px 16px;border-radius:8px;cursor:pointer;font-size:12.5px;font-weight:550;background:#7d879624;border:1px solid rgba(125,135,150,.2);color:var(--text, #e6eaf0)}.drawer__btn:hover{background:#7d879638}.drawer__btn.is-accent{background:var(--brand, #5b8df7);border-color:var(--brand, #5b8df7);color:#fff}.drawer__btn.is-accent:hover{filter:brightness(1.08)}.mitm-card{border:1px solid rgba(125,135,150,.22);border-radius:12px;padding:14px 16px;margin-bottom:14px;background:#1e242e66}.mitm-card--on{border-color:#4ade8059;background:#16281e66}.mitm-pill{position:fixed;top:64px;right:16px;z-index:9998;-webkit-app-region:no-drag;display:inline-flex;align-items:center;gap:8px;padding:4px 6px 4px 11px;border-radius:999px;width:fit-content;max-width:calc(100vw - 32px);background:#141e18d9;border:1px solid rgba(74,222,128,.3);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);box-shadow:0 4px 14px #0000004d;font-size:12px;line-height:1}.mitm-pill__dot{width:7px;height:7px;border-radius:50%;flex:none;background:#4ade80;box-shadow:0 0 0 3px #4ade8029}.mitm-pill__dot[data-busy="1"]{background:#9da7b3;box-shadow:0 0 0 3px #9da7b329}.mitm-pill__text{color:var(--text-dim, #9da7b3);white-space:nowrap}.mitm-pill__off{background:none;border:none;cursor:pointer;color:#6b7686;font-size:11.5px;padding:3px 7px;border-radius:999px}.mitm-pill__off:hover{color:#f87171;background:#f871711a}.mitm-card__head{display:flex;align-items:center;gap:8px;margin-bottom:6px}.mitm-card__dot{width:8px;height:8px;border-radius:50%;background:#9da7b3;flex:0 0 auto}.mitm-card__dot[data-state=on]{background:#4ade80;box-shadow:0 0 6px #4ade8099}.mitm-card__dot[data-state=warn]{background:#fbbf24}.mitm-card__dot[data-state=off]{background:#60a5fa}.mitm-card__title{font-size:14px;font-weight:600;color:var(--text, #e6edf3)}.mitm-card__desc{font-size:12.5px;line-height:1.5;color:var(--text-dim, #9da7b3);margin:0 0 10px}.mitm-card__note{color:#fbbf24}.mitm-card__error{font-size:12px;color:#f87171;margin-bottom:8px}.mitm-card__actions{display:flex;gap:8px}.mitm-card__btn{font-size:13px;padding:7px 16px;border-radius:8px;border:none;cursor:pointer;background:var(--accent, #3b82f6);color:#fff;font-weight:500}.mitm-card__btn:disabled{opacity:.6;cursor:default}.mitm-card__btn--ghost{background:transparent;border:1px solid rgba(125,135,150,.35);color:var(--text-dim, #9da7b3)}.mitm-card__sub{color:var(--text-dim, #9da7b3);opacity:.8;font-size:11.5px}.terms-gate{display:flex;align-items:center;justify-content:center;padding:24px}.terms-gate__panel,.terms-gate__panel *{-webkit-app-region:no-drag}.terms-gate__panel{position:relative;z-index:1;width:min(680px,94vw);max-height:90vh;display:flex;flex-direction:column;background:#141921eb;border:1px solid rgba(125,135,150,.22);border-radius:16px;padding:28px 30px;box-shadow:0 24px 60px #00000080}.terms-gate__title{font-size:20px;font-weight:700;margin:0 0 4px;color:var(--text, #e6edf3)}.terms-gate__subtitle{font-size:13px;color:var(--text-dim, #9da7b3);margin:0 0 16px}.terms-gate__body{overflow-y:auto;flex:1 1 auto;min-height:0;padding-right:10px;border-top:1px solid rgba(125,135,150,.15);border-bottom:1px solid rgba(125,135,150,.15);padding-top:14px;padding-bottom:14px;overscroll-behavior:contain}.terms-gate__body{scrollbar-width:thin;scrollbar-color:rgba(125,135,150,.35) transparent}.terms-gate__body::-webkit-scrollbar{width:8px}.terms-gate__body::-webkit-scrollbar-track{background:transparent}.terms-gate__body::-webkit-scrollbar-thumb{background:#7d87964d;border-radius:8px;border:2px solid transparent;background-clip:padding-box}.terms-gate__body::-webkit-scrollbar-thumb:hover{background:#7d87968c;background-clip:padding-box;border:2px solid transparent}.terms-gate--review{padding:24px}.terms-gate--review .glow{display:none}.terms-gate--review .terms-gate__panel{width:min(640px,92vw);max-height:min(82vh,760px);background:#12161efa;box-shadow:0 28px 80px #0009;animation:terms-pop .16s ease}@keyframes terms-pop{0%{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:none}}.terms-md{font-size:13px;line-height:1.65;color:var(--text-dim, #c2cbd6);word-break:break-word}.terms-md>:first-child{margin-top:0}.terms-md h1{font-size:17px;font-weight:700;color:var(--text, #e6edf3);margin:0 0 6px}.terms-md h2{font-size:15px;font-weight:700;color:var(--text, #e6edf3);margin:22px 0 8px;padding-top:14px;border-top:1px solid rgba(125,135,150,.12)}.terms-md h3{font-size:13.5px;font-weight:600;color:var(--text, #e6edf3);margin:16px 0 6px}.terms-md p{margin:8px 0}.terms-md strong{color:var(--text, #e6edf3);font-weight:600}.terms-md code{font-family:var(--mono);font-size:12px;background:#7d879629;padding:1px 5px;border-radius:4px;color:#d7dee8}.terms-md ul,.terms-md ol{margin:8px 0;padding-left:22px}.terms-md li{margin:4px 0}.terms-md hr{border:none;border-top:1px solid rgba(125,135,150,.14);margin:18px 0}.terms-md blockquote{margin:10px 0;padding:8px 14px;border-left:3px solid rgba(91,141,247,.55);background:#5b8df712;border-radius:0 8px 8px 0;color:var(--text-dim, #b9c2cf)}.terms-md table{width:100%;border-collapse:collapse;margin:10px 0;font-size:12px;display:block;overflow-x:auto}.terms-md th,.terms-md td{border:1px solid rgba(125,135,150,.18);padding:7px 10px;text-align:left;vertical-align:top}.terms-md th{background:#7d87961a;color:var(--text, #e6edf3);font-weight:600;white-space:nowrap}.terms-gate__scrollhint{font-size:12px;color:#fbbf24;text-align:center;margin:12px 0 0}.terms-gate__actions{display:flex;gap:12px;justify-content:flex-end;margin-top:18px}.terms-gate__btn{font-size:14px;padding:10px 22px;border-radius:9px;border:none;cursor:pointer;background:var(--accent, #3b82f6);color:#fff;font-weight:600}.terms-gate__btn:disabled{opacity:.45;cursor:not-allowed}.terms-gate__btn--ghost{background:transparent;border:1px solid rgba(125,135,150,.35);color:var(--text-dim, #9da7b3);font-weight:500}
|