cicy-desktop 2.1.117 → 2.1.119

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/bin/cicy-desktop CHANGED
@@ -13,13 +13,13 @@ const GLOBAL_CONFIG_FILE = path.join(HOME, "global.json");
13
13
  const STATE_FILE = path.join(HOME, ".cicy-cluster.json");
14
14
  const LOGS_DIR = path.join(HOME, "logs");
15
15
  const PACKAGE_ROOT = path.join(__dirname, "..");
16
- // CN/global defaults: a fresh machine has no cached electron binary, so the
17
- // electron postinstall (and our own self-provisioning below) would otherwise
18
- // hit GitHub releases, which is slow/blocked on many networks. Default to our
19
- // own Cloudflare R2 mirror the three platform zips we ship are mirrored at
20
- // <ELECTRON_MIRROR>v<version>/electron-v<version>-<platform>.zip (+ SHASUMS256.txt),
21
- // the exact layout @electron/get expects. Overridable via the env var.
22
- const ELECTRON_MIRROR = process.env.ELECTRON_MIRROR || "https://r2.deepfetch.de5.net/electron/";
16
+ // Electron 二进制来源:**不用用户设任何变量**,自动判断网络。
17
+ // CN(或探测不通,兜底)→ 我们的 Aliyun OSS 镜像(CN-fast,三平台 zip 镜像在
18
+ // <OSS>electron/v<version>/electron-v<version>-<platform>.zip,正是 @electron/get 的布局)。
19
+ // 海外 electron 官方 GitHub release(不压我们 OSS,海外更快)。
20
+ // 仍可用 ELECTRON_MIRROR 显式覆盖(power user / CI)。下载只在首次(无缓存)发生。
21
+ const OSS_ELECTRON_MIRROR = "https://cicy-1372193042-cn.oss-cn-shanghai.aliyuncs.com/electron/";
22
+ const GH_ELECTRON_BASE = "https://github.com/electron/electron/releases/download/";
23
23
  const NPM_REGISTRY = process.env.CICY_NPM_REGISTRY || process.env.npm_config_registry || "https://registry.npmmirror.com";
24
24
  const MASTER_ENTRY = path.join(PACKAGE_ROOT, "src", "master", "master-main.js");
25
25
 
@@ -89,30 +89,80 @@ function electronArtifact() {
89
89
  };
90
90
  }
91
91
 
92
+ // 同步探测是否 CN 网络:curl HEAD google(2s 超时)。通 → 海外;不通(CN/被墙/离线)
93
+ // → 当 CN,用 OSS 兜底。裸 node 可跑(不依赖 electron-log/net-detect.js)。只在真正要下
94
+ // electron 时调一次(已有二进制就 return,不探不下),所以不拖慢日常启动。
95
+ function isCNNetwork() {
96
+ if (process.env.CICY_FORCE_CN === "1") return true;
97
+ if (process.env.CICY_FORCE_GLOBAL === "1") return false;
98
+ const curl = isWindows ? "curl.exe" : "curl";
99
+ const nul = isWindows ? "NUL" : "/dev/null";
100
+ try {
101
+ execFileSync(curl, ["-sI", "--max-time", "2", "-o", nul, "https://www.google.com/generate_204"], { stdio: "ignore" });
102
+ return false; // google 可达 → 海外,走官方
103
+ } catch { return true; } // google 不可达 → CN/兜底,走 OSS
104
+ }
105
+
106
+ // 决定 electron zip 的下载地址(不用用户设变量):ELECTRON_MIRROR 显式覆盖 > CN→OSS > 海外→官方 GitHub。
107
+ function electronZipUrl() {
108
+ const { zip } = electronArtifact();
109
+ if (process.env.ELECTRON_MIRROR) return { url: `${process.env.ELECTRON_MIRROR}v${ELECTRON_VERSION}/${zip}`, src: "ELECTRON_MIRROR" };
110
+ if (isCNNetwork()) return { url: `${OSS_ELECTRON_MIRROR}v${ELECTRON_VERSION}/${zip}`, src: "OSS(CN)" };
111
+ return { url: `${GH_ELECTRON_BASE}v${ELECTRON_VERSION}/${zip}`, src: "GitHub(海外)" };
112
+ }
113
+
92
114
  // Provision the Electron binary INTO the bundled npx copy ourselves: download the
93
- // platform zip from the mirror (R2) with curl, extract with the OS's own unzip,
94
- // then write path.txt. We deliberately do NOT use electron's install.js /
95
- // @electron/get: on Windows its bundled extract-zip only PARTIALLY unpacks
96
- // electron 41 (leaves no path.txt → "Electron failed to install correctly") even
97
- // though the downloaded zip is valid. curl + Expand-Archive/unzip is reliable,
98
- // mirror-only (no GitHub), and writes a complete dist/.
115
+ // platform zip with curl (实时进度条 -#), extract with the OS's own unzip, then
116
+ // write path.txt. We deliberately do NOT use electron's install.js / @electron/get:
117
+ // on Windows its bundled extract-zip only PARTIALLY unpacks electron 41 (leaves no
118
+ // path.txt → "Electron failed to install correctly") even though the downloaded zip
119
+ // is valid. curl + Expand-Archive/unzip is reliable and writes a complete dist/.
120
+ // 远端文件大小(取最终响应的 content-length,跟随重定向)。失败返回 0。
121
+ function remoteContentLength(curl, url) {
122
+ try {
123
+ const out = execFileSync(curl, ["-sIL", "--max-time", "15", url], { encoding: "utf8" });
124
+ const all = [...out.matchAll(/content-length:\s*(\d+)/ig)].map((m) => Number(m[1]));
125
+ return all.length ? all[all.length - 1] : 0;
126
+ } catch { return 0; }
127
+ }
128
+
99
129
  function provisionElectronFromMirror(bundledDir) {
100
130
  const { zip, exe } = electronArtifact();
101
- const url = `${ELECTRON_MIRROR}v${ELECTRON_VERSION}/${zip}`;
102
- const tmpZip = path.join(os.tmpdir(), `cicy-${zip}`);
131
+ const { url, src } = electronZipUrl();
103
132
  const curl = isWindows ? "curl.exe" : "curl";
104
- execFileSync(curl, ["-fL", "--retry", "5", "--retry-delay", "2", "--connect-timeout", "20", "-o", tmpZip, url], { stdio: "inherit" });
133
+ // 缓存到 ~/Downloads(主人:下到 Downloads,下过就别再下,最好断点续传):
134
+ // • 已完整(大小==远端)→ 直接复用,不再下;
135
+ // • 没下全(部分)→ curl -C - 断点续传;
136
+ // • 没有 → 全新下载。下完保留 zip,不删,下次免下。
137
+ const dlDir = path.join(os.homedir(), "Downloads");
138
+ try { fs.mkdirSync(dlDir, { recursive: true }); } catch {}
139
+ const dest = path.join(dlDir, zip);
140
+ const expected = remoteContentLength(curl, url);
141
+ let localSz = 0; try { localSz = fs.statSync(dest).size; } catch {}
142
+ const complete = localSz >= 50 * 1024 * 1024 && (!expected || localSz === expected);
143
+ if (complete) {
144
+ console.log(`✓ 复用已下载的 Electron:${dest}`);
145
+ } else {
146
+ const resuming = localSz > 0;
147
+ console.log(`⬇️ 下载 Electron ${ELECTRON_VERSION}(来源:${src}${resuming ? ",断点续传" : ""})→ ${dest}`);
148
+ // -C - 断点续传(部分则 206 续,缺则 200 全下);-# 进度条;inherit 让进度条画到终端。
149
+ execFileSync(curl, ["-fL", "-#", "-C", "-", "--retry", "5", "--retry-delay", "2", "--connect-timeout", "20", "-o", dest, url], { stdio: "inherit" });
150
+ try { localSz = fs.statSync(dest).size; } catch {}
151
+ if (localSz < 50 * 1024 * 1024 || (expected && localSz !== expected)) {
152
+ throw new Error(`Electron zip 下载不完整(${localSz}/${expected || "?"} 字节,${dest})—— 重跑会从断点续传`);
153
+ }
154
+ }
105
155
  const distDir = path.join(bundledDir, "dist");
106
156
  fs.rmSync(distDir, { recursive: true, force: true });
107
157
  fs.mkdirSync(distDir, { recursive: true });
108
158
  if (isWindows) {
109
- execFileSync("powershell", ["-NoProfile", "-Command", `Expand-Archive -LiteralPath "${tmpZip}" -DestinationPath "${distDir}" -Force`], { stdio: "inherit" });
159
+ execFileSync("powershell", ["-NoProfile", "-Command", `Expand-Archive -LiteralPath "${dest}" -DestinationPath "${distDir}" -Force`], { stdio: "inherit" });
110
160
  } else {
111
- execFileSync("unzip", ["-o", "-q", tmpZip, "-d", distDir], { stdio: "inherit" });
161
+ execFileSync("unzip", ["-o", "-q", dest, "-d", distDir], { stdio: "inherit" });
112
162
  try { fs.chmodSync(path.join(distDir, exe), 0o755); } catch {}
113
163
  }
114
164
  fs.writeFileSync(path.join(bundledDir, "path.txt"), exe);
115
- try { fs.rmSync(tmpZip, { force: true }); } catch {}
165
+ // 不删 dest:留在 ~/Downloads 缓存,下次免下(主人:下过就别再下)
116
166
  }
117
167
 
118
168
  // Make sure a USABLE electron exists before spawning the worker. A pre-existing
@@ -528,11 +578,11 @@ function ensureMacDesktopApp() {
528
578
  : "cicy-desktop";
529
579
  // do shell script needs node + the global bin on PATH (GUI launch has a
530
580
  // minimal PATH); trailing & + nohup + </dev/null lets the shell return so the
531
- // applet quits. ELECTRON_MIRROR + npmmirror only matter if electron ever
532
- // (re)downloads harmless otherwise.
581
+ // applet quits. 不再 export ELECTRON_MIRROR —— bin 自己按网络自动选(CN→OSS / 海外→GitHub)。
582
+ // npm_config_registry(npmmirror)留着给 cicy-code 子包下载用。
533
583
  const ascript =
534
584
  `do shell script "export PATH=\\"${nodeDir}:${gbin}:/usr/local/bin:/opt/homebrew/bin:$PATH\\" ; ` +
535
- `export ELECTRON_MIRROR=\\"${ELECTRON_MIRROR}\\" ; export npm_config_registry=\\"${NPM_REGISTRY}\\" ; ` +
585
+ `export npm_config_registry=\\"${NPM_REGISTRY}\\" ; ` +
536
586
  `nohup '${cicyBin}' > /tmp/cicy-desktop.log 2>&1 < /dev/null &"`;
537
587
  const tmp = path.join(os.tmpdir(), `cicy-launch-${process.pid}.applescript`);
538
588
  fs.writeFileSync(tmp, ascript);
@@ -559,7 +609,7 @@ function ensureLinuxDesktopEntry() {
559
609
  `[Desktop Entry]
560
610
  Type=Application
561
611
  Name=CiCy Desktop
562
- Exec=sh -c 'export PATH="${nodeBinDir()}:$PATH"; export ELECTRON_MIRROR="${ELECTRON_MIRROR}"; export npm_config_registry="${NPM_REGISTRY}"; exec npx -y cicy-desktop'
612
+ Exec=sh -c 'export PATH="${nodeBinDir()}:$PATH"; export npm_config_registry="${NPM_REGISTRY}"; exec npx -y cicy-desktop'
563
613
  Icon=${icon}
564
614
  Terminal=false
565
615
  Categories=Development;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cicy-desktop",
3
- "version": "2.1.117",
3
+ "version": "2.1.119",
4
4
  "description": "CiCy - AI-powered operating system browser",
5
5
  "main": "src/main.js",
6
6
  "bin": {
@@ -133,11 +133,11 @@
133
133
  "//optionalDependencies": "Runtime Bundle v1 (主人指令): platform binaries delivered by `npm i -g cicy-desktop` itself — npm installs only the current-platform subpackage (os/cpu pinned in each), so first start seeds the runtime store with ZERO network, ZERO npx. Windows packages are named *-windows-* (npm spam filter 403s new names containing win32). cicy-msys2 added once published.",
134
134
  "optionalDependencies": {
135
135
  "electron": "41.0.3",
136
- "cicy-code-darwin-x64": "2.3.16",
137
- "cicy-code-darwin-arm64": "2.3.16",
138
- "cicy-code-linux-x64": "2.3.16",
139
- "cicy-code-linux-arm64": "2.3.16",
140
- "cicy-code-windows-x64": "2.3.16",
136
+ "cicy-code-darwin-x64": "2.3.19",
137
+ "cicy-code-darwin-arm64": "2.3.19",
138
+ "cicy-code-linux-x64": "2.3.19",
139
+ "cicy-code-linux-arm64": "2.3.19",
140
+ "cicy-code-windows-x64": "2.3.19",
141
141
  "cicy-mihomo-darwin-x64": "1.10.4",
142
142
  "cicy-mihomo-darwin-arm64": "1.10.4",
143
143
  "cicy-mihomo-linux-x64": "1.10.4",
@@ -161,7 +161,9 @@ contextBridge.exposeInMainWorld("cicy", {
161
161
  // streaming phase/progress on 'docker:app-progress'.
162
162
  appStatus: () => logInvoke("docker:app-status"),
163
163
  appBootstrap: () => logInvoke("docker:app-bootstrap"),
164
- appRestart: () => logInvoke("docker:app-restart"),
164
+ appRestart: () => logInvoke("docker:app-restart"), // supervisorctl 重启 cicy-code
165
+ appDockerRestart: () => logInvoke("docker:app-docker-restart"), // docker restart 整个容器
166
+ appRecreate: () => logInvoke("docker:app-recreate"), // 删容器+重建(换 key,需 confirm)
165
167
  appUpdate: () => logInvoke("docker:app-update"),
166
168
  appStop: () => logInvoke("docker:app-stop"),
167
169
  appUpgrade: () => logInvoke("docker:app-upgrade"),
@@ -203,6 +205,8 @@ contextBridge.exposeInMainWorld("cicy", {
203
205
  tabs: {
204
206
  open: (url, title) => logInvoke("tabs:open", { url, title }),
205
207
  reload: (url, title) => logInvoke("tabs:reload", { url, title }),
208
+ reloadIfOpen: (url, title) => logInvoke("tabs:reloadIfOpen", { url, title }),
209
+ activateIfOpen: (url) => logInvoke("tabs:activateIfOpen", { url }),
206
210
  },
207
211
 
208
212
  // ------- new bridges (last rebuild!) -------
@@ -0,0 +1 @@
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}.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}.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}.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--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}