deckide 3.5.42 → 3.5.44

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/README.md CHANGED
@@ -64,6 +64,11 @@ deckide config 全設定表示
64
64
  deckide config set <key> <val> 設定値変更
65
65
  deckide config get <key> 設定値取得
66
66
  deckide config reset 設定リセット
67
+
68
+ deckide codeserver install code-server(VS Code エディタ)を取得/インストール
69
+ deckide codeserver status code-server のインストール状態
70
+ deckide codeserver path code-server バイナリのパスを表示
71
+ deckide codeserver uninstall 取得済み code-server を削除
67
72
  ```
68
73
 
69
74
  ### 起動オプション
@@ -167,6 +172,29 @@ ide/
167
172
  | `AGENT_BROWSER_FFMPEG` | ffmpeg 実行ファイル | PATH から自動検出 |
168
173
  | `AGENT_BROWSER_PACTL` | pactl 実行ファイル | PATH から自動検出 |
169
174
  | `AGENT_BROWSER_AUDIO_SOURCE` | 音声キャプチャ元 | 既定 sink の monitor source |
175
+ | `AGENT_BROWSER_WEBRTC` | エージェントブラウザ映像を WebRTC 配信(`true`/`auto`/`false`、現状はオプトイン) | false |
176
+ | `AGENT_BROWSER_WEBRTC_BITRATE` | WebRTC ビットレート(ffmpeg `-b:v` 形式) | 3M |
177
+ | `AGENT_BROWSER_WEBRTC_FPS` | WebRTC フレームレート | 30 |
178
+ | `AGENT_BROWSER_WEBRTC_ICE_SERVERS` | ICE サーバ(JSON配列)。空ならホスト候補のみ(同一ホスト/LAN) | — |
179
+ | `AGENT_BROWSER_DISPLAY` | キャプチャする X ディスプレイ(未設定なら Chrome から自動検出) | — |
180
+ | `AGENT_BROWSER_CDP_PORT` | 共有ブラウザの CDP ポート | 9222 |
181
+ | `AGENT_BROWSER_REAP_MCP` | リークした chrome-devtools-mcp スタックを自動回収 | true |
182
+ | `AGENT_BROWSER_MAX_MCP_PER_AGENT` | 1エージェントが保持できる MCP スタック上限(超過分の古いものを回収) | 3 |
183
+ | `AGENT_BROWSER_MCP_IDLE_MS` | 回収対象とみなすアイドル閾値 (ms) | 600000 |
184
+ | `DECKIDE_CODE_SERVER_BIN` | code-server バイナリ(未設定なら ~/.deckide → PATH → 初回自動DL) | — |
185
+ | `DECKIDE_CODE_SERVER_VERSION` | 取得する code-server バージョン | 4.125.0 |
186
+
187
+ ## Deck Drive シェルと code-server
188
+
189
+ 既定の UI は **Deck Drive**(Google Drive 風のファイル/ワークスペース・ブラウザ)です。ファイルを開くと **code-server(ブラウザ版 VS Code)** が同一オリジンのリバースプロキシ(`/codeserver/:wsId/*`)越しに起動します。ターミナルデッキ・エージェントブラウザもタブとして同じシェルに統合されています。
190
+
191
+ - **code-server の取得**: 初回利用時に固定版(`DECKIDE_CODE_SERVER_VERSION`、既定 4.125.0)を `~/.deckide/code-server` へ自動ダウンロードします。手動なら `deckide codeserver install`。
192
+ - **拡張機能**: Microsoft マーケットプレイスは利用不可(Open VSX のみ)。Pylance/Copilot/Remote-* は使えません(Pyright 等で代替)。
193
+ - **リソース**: code-server はワークスペース毎に1プロセス(目安 +1GB RAM / +2 コア)。アイドル20分で自動停止します。
194
+ - **認証**: code-server は `--auth none` で起動し、Deck IDE の Basic 認証配下の同一オリジンプロキシで保護します。
195
+ - **旧 UI**: 従来の Monaco/分割ターミナル・シェルは `?shell=legacy` で引き続き利用できます。
196
+
197
+ > エージェントブラウザの WebRTC 配信(`AGENT_BROWSER_WEBRTC` / `?webrtc=1`)は実験的なオプトインです。既定は従来の JPEG ストリーミングです。音声トラックは PulseAudio がある環境でのみ動作します。
170
198
 
171
199
  ## MCP / OAuth
172
200
 
package/bin/deckide.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import path from 'node:path';
@@ -172,6 +172,11 @@ Usage:
172
172
  deckide config get <key> Get a config value
173
173
  deckide config reset Reset all settings
174
174
 
175
+ deckide codeserver install Download/install code-server (the VS Code editor)
176
+ deckide codeserver status Show code-server install status
177
+ deckide codeserver path Print the code-server binary path
178
+ deckide codeserver uninstall Remove the downloaded code-server
179
+
175
180
  Options (for start):
176
181
  -p, --port <port> Port (default: 8787)
177
182
  --host <host> Host (default: 0.0.0.0)
@@ -338,6 +343,50 @@ if (command === 'auth') {
338
343
  }
339
344
 
340
345
  // ── deckide status ──
346
+ // ── deckide codeserver ──
347
+ if (command === 'codeserver') {
348
+ const sub = args[1] || 'status';
349
+ process.env.DECKIDE_DATA_DIR = dataDir;
350
+ const modPath = path.join(__dirname, '..', 'dist', 'utils', 'code-server.js');
351
+ let CodeServerService;
352
+ try {
353
+ ({ CodeServerService } = await import(modPath));
354
+ } catch (e) {
355
+ console.error(`code-server module not found — is Deck IDE built? (${e.message})`);
356
+ process.exit(1);
357
+ }
358
+ const cs = new CodeServerService(new Map());
359
+ if (sub === 'install') {
360
+ try {
361
+ const bin = await cs.download((m) => console.log(` ${m}`));
362
+ console.log(`\x1b[32mInstalled\x1b[0m → ${bin}`);
363
+ process.exit(0);
364
+ } catch (e) {
365
+ console.error(`\x1b[31mInstall failed:\x1b[0m ${e.message}`);
366
+ process.exit(1);
367
+ }
368
+ } else if (sub === 'status') {
369
+ const s = await cs.getStatus();
370
+ console.log('code-server');
371
+ console.log(` acquired: ${s.acquired}`);
372
+ console.log(` binPath: ${s.binPath || '(none)'}`);
373
+ if (s.reason) console.log(` note: ${s.reason}`);
374
+ process.exit(0);
375
+ } else if (sub === 'path') {
376
+ const bin = await cs.resolveBin();
377
+ if (bin) { console.log(bin); process.exit(0); }
378
+ console.error('code-server is not installed (run: deckide codeserver install)');
379
+ process.exit(1);
380
+ } else if (sub === 'uninstall') {
381
+ await cs.uninstall();
382
+ console.log('Uninstalled code-server.');
383
+ process.exit(0);
384
+ } else {
385
+ console.error('usage: deckide codeserver install|status|path|uninstall');
386
+ process.exit(1);
387
+ }
388
+ }
389
+
341
390
  if (command === 'status') {
342
391
  const settings = loadSettings();
343
392
  const port = settings.port || 8787;
@@ -71,6 +71,14 @@ export function createCodeServerRouter(codeServer) {
71
71
  }
72
72
  return c.json(await codeServer.getStatus(wsId || undefined));
73
73
  });
74
+ // Kick off the (single-flight) code-server download without blocking — the
75
+ // client polls /status until acquired. No-op if already installed.
76
+ router.post('/install', async (c) => {
77
+ if (!(await codeServer.isAcquired())) {
78
+ void codeServer.download().catch(() => undefined);
79
+ }
80
+ return c.json(await codeServer.getStatus());
81
+ });
74
82
  // Reverse-proxy everything else under /codeserver/:wsId/* to that workspace's
75
83
  // code-server instance (prefix stripped).
76
84
  router.all('/:wsId/*', (c) => proxy(c, codeServer));
@@ -480,6 +480,25 @@ export class AgentBrowserService {
480
480
  })
481
481
  .catch(() => undefined);
482
482
  }
483
+ // Pin the active tab's render viewport to a fixed size (the WebRTC framebuffer)
484
+ // so captured pixels equal page coordinates. Does not mutate this.viewport, so
485
+ // the JPEG path's client-driven resize is unaffected when WebRTC isn't active.
486
+ async pinViewport(width, height) {
487
+ await this.ensureActiveCdp();
488
+ if (!this.activeCdp) {
489
+ return;
490
+ }
491
+ await this.activeCdp
492
+ .send('Emulation.setDeviceMetricsOverride', {
493
+ width,
494
+ height,
495
+ deviceScaleFactor: 1,
496
+ mobile: false,
497
+ screenWidth: width,
498
+ screenHeight: height,
499
+ })
500
+ .catch(() => undefined);
501
+ }
483
502
  async navigate(input) {
484
503
  const url = normalizeBrowserUrl(input);
485
504
  await this.start();
@@ -623,6 +642,9 @@ export class AgentBrowserService {
623
642
  this.port = null;
624
643
  this.disconnectActiveCdp();
625
644
  this.closeBrowserCdp();
645
+ // Tear down the WebRTC relay too, so a Chrome crash never leaves an
646
+ // orphaned x11grab/ffmpeg encoder pointed at a dead display.
647
+ void this.webrtcRelay.stop();
626
648
  this.tabs.clear();
627
649
  this.activeTargetId = null;
628
650
  this.ready = false;
@@ -4,7 +4,7 @@ import fs from 'node:fs/promises';
4
4
  import path from 'node:path';
5
5
  import { promisify } from 'node:util';
6
6
  import { WebSocket } from 'ws';
7
- import { AGENT_BROWSER_WEBRTC, AGENT_BROWSER_WEBRTC_CODEC, AGENT_BROWSER_WEBRTC_BITRATE, AGENT_BROWSER_WEBRTC_FPS, AGENT_BROWSER_DISPLAY, AGENT_BROWSER_WEBRTC_ICE_SERVERS, } from '../config.js';
7
+ import { AGENT_BROWSER_WEBRTC, AGENT_BROWSER_WEBRTC_CODEC, AGENT_BROWSER_WEBRTC_BITRATE, AGENT_BROWSER_WEBRTC_FPS, AGENT_BROWSER_DISPLAY, AGENT_BROWSER_WEBRTC_ICE_SERVERS, AGENT_BROWSER_CDP_PORT, } from '../config.js';
8
8
  const execFileAsync = promisify(execFile);
9
9
  let weriftPromise = null;
10
10
  function loadWerift() {
@@ -51,7 +51,7 @@ async function resolveExecutable(envName, names) {
51
51
  // picks the display number for the Chrome child and exports DISPLAY/XAUTHORITY
52
52
  // only into that child's environment, so the server process can't read them from
53
53
  // its own env — we recover them from /proc/<pid>/environ instead.
54
- async function resolveXEnv() {
54
+ async function resolveXEnv(cdpPort) {
55
55
  if (AGENT_BROWSER_DISPLAY) {
56
56
  return { display: AGENT_BROWSER_DISPLAY, xauthority: process.env.XAUTHORITY ?? null };
57
57
  }
@@ -63,6 +63,8 @@ async function resolveXEnv() {
63
63
  // Not Linux / no procfs.
64
64
  return process.env.DISPLAY ? { display: process.env.DISPLAY, xauthority: process.env.XAUTHORITY ?? null } : null;
65
65
  }
66
+ const portToken = cdpPort ? `--remote-debugging-port=${cdpPort}` : null;
67
+ let fallback = null;
66
68
  for (const pid of pids) {
67
69
  let comm = '';
68
70
  try {
@@ -87,9 +89,27 @@ async function resolveXEnv() {
87
89
  continue;
88
90
  }
89
91
  const xauthority = vars.find((v) => v.startsWith('XAUTHORITY='))?.slice('XAUTHORITY='.length) ?? null;
90
- return { display, xauthority };
92
+ const candidate = { display, xauthority };
93
+ if (!portToken) {
94
+ return candidate;
95
+ }
96
+ // With multiple Chrome instances, prefer the one bound to OUR CDP port so we
97
+ // capture (and control) the same browser. Fall back to the first found.
98
+ let cmdline = '';
99
+ try {
100
+ cmdline = (await fs.readFile(`/proc/${pid}/cmdline`, 'utf8')).replace(/\0/g, ' ');
101
+ }
102
+ catch {
103
+ // ignore
104
+ }
105
+ if (cmdline.includes(portToken)) {
106
+ return candidate;
107
+ }
108
+ if (!fallback) {
109
+ fallback = candidate;
110
+ }
91
111
  }
92
- return process.env.DISPLAY ? { display: process.env.DISPLAY, xauthority: process.env.XAUTHORITY ?? null } : null;
112
+ return fallback ?? (process.env.DISPLAY ? { display: process.env.DISPLAY, xauthority: process.env.XAUTHORITY ?? null } : null);
93
113
  }
94
114
  // Query the real screen geometry of the display so x11grab captures the exact
95
115
  // region (a mismatch makes ffmpeg error or grab garbage).
@@ -145,7 +165,7 @@ export class BrowserWebRtcRelay {
145
165
  else {
146
166
  const werift = await loadWerift();
147
167
  const ffmpeg = await resolveExecutable('AGENT_BROWSER_FFMPEG', ['ffmpeg']);
148
- const xenv = await resolveXEnv();
168
+ const xenv = await resolveXEnv(AGENT_BROWSER_CDP_PORT);
149
169
  if (!werift) {
150
170
  available = false;
151
171
  reason = 'werift is not installed (npm install werift)';
@@ -298,7 +318,7 @@ export class BrowserWebRtcRelay {
298
318
  if (!ffmpeg) {
299
319
  throw new Error('ffmpeg is required for WebRTC streaming');
300
320
  }
301
- const xenv = await resolveXEnv();
321
+ const xenv = await resolveXEnv(AGENT_BROWSER_CDP_PORT);
302
322
  if (!xenv) {
303
323
  throw new Error('No X display found to capture');
304
324
  }
@@ -311,6 +331,8 @@ export class BrowserWebRtcRelay {
311
331
  // Size the page's OS window to fill the captured screen so the framebuffer
312
332
  // region maps 1:1 to page coordinates. Best-effort; ignore failures.
313
333
  await this.host.setActiveWindowBounds(0, 0, this.size.width, this.size.height).catch(() => undefined);
334
+ // Pin the page render size to the framebuffer so input coords map 1:1.
335
+ await this.host.pinViewport(this.size.width, this.size.height).catch(() => undefined);
314
336
  // Bind an ephemeral UDP port; ffmpeg sends RTP here and we fan each packet
315
337
  // out to every viewer's track (no re-encode in werift).
316
338
  const udp = dgram.createSocket('udp4');
@@ -1,4 +1,5 @@
1
- import { spawn } from 'node:child_process';
1
+ import { spawn, execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
2
3
  import net from 'node:net';
3
4
  import fs from 'node:fs/promises';
4
5
  import path from 'node:path';
@@ -6,6 +7,9 @@ import { dataDir } from '../config.js';
6
7
  const IDLE_TIMEOUT_MS = 20 * 60 * 1000;
7
8
  const START_TIMEOUT_MS = 30_000;
8
9
  const REAP_INTERVAL_MS = 60_000;
10
+ // Pinned code-server version for reproducible auto-download.
11
+ const CODE_SERVER_VERSION = process.env.DECKIDE_CODE_SERVER_VERSION || '4.125.0';
12
+ const execFileAsync = promisify(execFile);
9
13
  function sleep(ms) {
10
14
  return new Promise((resolve) => setTimeout(resolve, ms));
11
15
  }
@@ -49,6 +53,9 @@ export class CodeServerService {
49
53
  workspaces;
50
54
  instances = new Map();
51
55
  reaper = null;
56
+ // Single-flight auto-download of the code-server binary.
57
+ downloadPromise = null;
58
+ downloading = false;
52
59
  // Directory layout under ~/.deckide/code-server (set by config.dataDir).
53
60
  root = path.join(dataDir, 'code-server');
54
61
  constructor(workspaces) {
@@ -70,6 +77,62 @@ export class CodeServerService {
70
77
  async isAcquired() {
71
78
  return (await this.resolveBin()) !== null;
72
79
  }
80
+ // Download + install the pinned code-server build into dataDir (single-flight).
81
+ // Returns the resolved binary path. Auto-invoked by ensure() when not present.
82
+ download(onLog) {
83
+ if (this.downloadPromise) {
84
+ return this.downloadPromise;
85
+ }
86
+ this.downloading = true;
87
+ this.downloadPromise = this.doDownload(onLog).finally(() => {
88
+ this.downloading = false;
89
+ this.downloadPromise = null;
90
+ });
91
+ return this.downloadPromise;
92
+ }
93
+ async doDownload(onLog) {
94
+ const version = CODE_SERVER_VERSION;
95
+ const os = process.platform === 'darwin' ? 'macos' : process.platform === 'linux' ? 'linux' : null;
96
+ if (!os) {
97
+ throw new Error(`Automatic code-server download is unsupported on ${process.platform}. Install code-server manually and set DECKIDE_CODE_SERVER_BIN.`);
98
+ }
99
+ const arch = process.arch === 'arm64' ? 'arm64' : process.arch === 'x64' ? 'amd64' : null;
100
+ if (!arch) {
101
+ throw new Error(`Automatic code-server download is unsupported on architecture ${process.arch}.`);
102
+ }
103
+ const name = `code-server-${version}-${os}-${arch}`;
104
+ const url = `https://github.com/coder/code-server/releases/download/v${version}/${name}.tar.gz`;
105
+ const libDir = path.join(this.root, 'lib');
106
+ const tarPath = path.join(this.root, `${name}.tar.gz`);
107
+ await fs.mkdir(libDir, { recursive: true });
108
+ const log = (m) => { onLog?.(m); console.log(`[code-server] ${m}`); };
109
+ log(`downloading ${url}`);
110
+ const res = await fetch(url, { redirect: 'follow' });
111
+ if (!res.ok) {
112
+ throw new Error(`code-server download failed: HTTP ${res.status}`);
113
+ }
114
+ const bytes = Buffer.from(await res.arrayBuffer());
115
+ await fs.writeFile(tarPath, bytes);
116
+ log(`extracting ${(bytes.length / 1024 / 1024).toFixed(0)}MB`);
117
+ await execFileAsync('tar', ['-xzf', tarPath, '-C', libDir]);
118
+ await fs.rm(tarPath, { force: true });
119
+ const innerBin = path.join(libDir, name, 'bin', 'code-server');
120
+ if (!(await pathExists(innerBin))) {
121
+ throw new Error('code-server binary not found after extraction');
122
+ }
123
+ const binDir = path.join(this.root, 'bin');
124
+ await fs.mkdir(binDir, { recursive: true });
125
+ const link = path.join(binDir, 'code-server');
126
+ await fs.rm(link, { force: true });
127
+ await fs.symlink(innerBin, link);
128
+ log('installed');
129
+ return link;
130
+ }
131
+ // Remove the downloaded code-server install (and its per-workspace data).
132
+ async uninstall() {
133
+ await this.stopAll();
134
+ await fs.rm(this.root, { recursive: true, force: true });
135
+ }
73
136
  async getStatus(wsId) {
74
137
  const bin = await this.resolveBin();
75
138
  const instance = wsId ? this.instances.get(wsId) : undefined;
@@ -79,8 +142,13 @@ export class CodeServerService {
79
142
  binPath: bin,
80
143
  running: instance ? instance.proc.exitCode == null : false,
81
144
  instances: this.instances.size,
145
+ downloading: this.downloading,
82
146
  wsId: wsId ?? null,
83
- reason: bin ? undefined : 'code-server is not installed (run: deckide codeserver install)',
147
+ reason: bin
148
+ ? undefined
149
+ : this.downloading
150
+ ? 'code-server is downloading…'
151
+ : 'code-server will be downloaded automatically on first use',
84
152
  error: instance?.error,
85
153
  };
86
154
  }
@@ -99,9 +167,10 @@ export class CodeServerService {
99
167
  if (!workspace) {
100
168
  throw new Error(`Unknown workspace: ${wsId}`);
101
169
  }
102
- const bin = await this.resolveBin();
170
+ let bin = await this.resolveBin();
103
171
  if (!bin) {
104
- throw new Error('code-server is not installed (run: deckide codeserver install)');
172
+ // Auto-acquire on first use (single-flight ~100MB download).
173
+ bin = await this.download();
105
174
  }
106
175
  const port = await getFreePort();
107
176
  const userDataDir = path.join(this.root, 'user', wsId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deckide",
3
- "version": "3.5.42",
3
+ "version": "3.5.44",
4
4
  "description": "Deck IDE - Browser-based IDE with terminal, file explorer, and git integration",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,32 @@
1
+ @import"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&family=Noto+Sans+JP:wght@400;500;600&display=swap";/**
2
+ * Copyright (c) 2014 The xterm.js authors. All rights reserved.
3
+ * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
4
+ * https://github.com/chjj/term.js
5
+ * @license MIT
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ *
25
+ * Originally forked from (with the author's permission):
26
+ * Fabrice Bellard's javascript vt100 for jslinux:
27
+ * http://bellard.org/jslinux/
28
+ * Copyright (c) 2011 Fabrice Bellard
29
+ * The original design remains. The terminal itself
30
+ * has been extended to include xterm CSI codes, among
31
+ * other features.
32
+ */.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:"JetBrains Mono", monospace;--color-red-400:oklch(70.4% .191 22.216);--color-black:#000;--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--tracking-wide:.025em;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-bg:#f3f3f3;--color-bg-soft:#e8e8e8;--color-panel:#fff;--color-sidebar:#f3f3f3;--color-activitybar:#2c2c2c;--color-activitybar-fg:#fff;--color-activitybar-inactive:#fff9;--color-border:#e5e5e5;--color-ink:#333;--color-ink-muted:#6e6e6e;--color-muted:#717171;--color-accent:#007acc;--color-statusbar:#007acc;--color-statusbar-fg:#fff;--color-list-hover:#0000000a;--color-list-active:#0078d41a;--color-focus:#0090f1;--color-title-bar:#ddd;--color-git-modified:#cca700;--color-git-untracked:#4ec9b0;--color-git-deleted:#f14c4c;--color-git-staged:#73c991;--color-git-renamed:#4fc1ff;--color-git-conflicted:#ff6b6b;--font-ui:"Noto Sans JP", sans-serif}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*,:before,:after{box-sizing:border-box}html,body,#root{height:100%;min-height:100%;margin:0}body{font-family:var(--font-ui);background:var(--color-bg);color:var(--color-ink);font-size:13px;line-height:1.4;overflow:hidden}button,input,select,textarea{color:inherit;font-family:inherit}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:2px solid var(--color-focus);outline-offset:2px}@supports (height:100dvh){html,body,#root{height:100dvh;min-height:100dvh}}html,body,#root{height:var(--viewport-height,100dvh);min-height:var(--viewport-height,100dvh)}*{scrollbar-width:thin;scrollbar-color:#8080804d transparent}:root[data-theme=dark] *{scrollbar-color:#ffffff26 transparent}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:#8080804d;border-radius:3px}::-webkit-scrollbar-thumb:hover{background:#80808080}:root[data-theme=dark] ::-webkit-scrollbar-thumb{background:#ffffff26}:root[data-theme=dark] ::-webkit-scrollbar-thumb:hover{background:#ffffff4d}::-webkit-scrollbar-corner{background:0 0}}@layer components{.activity-bar-item.active:before{content:"";background:var(--color-activitybar-fg);width:2px;position:absolute;top:0;bottom:0;left:0}.workspace-editor-grid .activity-bar-item.active:before{background:var(--color-accent)}.app>nav.activity-bar .activity-bar-item.active:before{width:auto;height:2px;inset:0 0 auto}.git-tab.active:after{content:"";background:var(--color-accent);height:2px;position:absolute;bottom:0;left:0;right:0}.editor-tab:hover .editor-tab-close,.editor-tab.active .editor-tab-close{opacity:1}.editor-tab.dirty .editor-tab-close{opacity:0}.editor-tab.dirty:hover .editor-tab-close{opacity:1}.editor-tab.dirty:hover .editor-tab-dirty{display:none}.deck-tab:hover .deck-tab-close,.deck-tab.active .deck-tab-close{opacity:.5}.deck-tab-close:hover{color:var(--color-ink);background:#ffffff1f;opacity:1!important}.git-file-row:hover .git-file-actions{opacity:1}.tree-row.is-open .tree-chevron-icon{transform:rotate(90deg)}.terminal-split-container.is-drop-target:after{content:"デッキをここにドロップして分割";border:2px dashed var(--color-accent);color:var(--color-ink-muted);pointer-events:none;z-index:2;background:#0078d414;border-radius:6px;justify-content:center;align-items:center;font-size:12px;font-weight:600;display:flex;position:absolute;top:10px;right:10px;bottom:10px;left:10px}.git-tree-modified .tree-label{color:var(--color-git-modified)}.git-tree-untracked .tree-label{color:var(--color-git-untracked)}.git-tree-deleted .tree-label{color:var(--color-git-deleted)}.git-tree-staged .tree-label{color:var(--color-git-staged)}.git-tree-renamed .tree-label{color:var(--color-git-renamed)}.git-tree-conflicted .tree-label{color:var(--color-git-conflicted)}.sidebar-content .panel{box-shadow:none;background:0 0;border:none;border-radius:0}.sidebar-content .panel-header{background:var(--color-sidebar);z-index:1;margin-bottom:0;padding:8px 12px;position:sticky;top:0}.sidebar-content .panel-body{padding:0}}@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-1{top:calc(var(--spacing) * 1)}.right-1{right:calc(var(--spacing) * 1)}.z-50{z-index:50}.z-\[500\]{z-index:500}.z-\[999\]{z-index:999}.z-\[1000\]{z-index:1000}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.m-0{margin:calc(var(--spacing) * 0)}.my-1{margin-block:calc(var(--spacing) * 1)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-7{height:calc(var(--spacing) * 7)}.h-\[22px\]{height:22px}.h-full{height:100%}.h-px{height:1px}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-\[28px\]{min-height:28px}.min-h-\[36px\]{min-height:36px}.min-h-\[40px\]{min-height:40px}.min-h-\[44px\]{min-height:44px}.min-h-\[50px\]{min-height:50px}.min-h-screen{min-height:100vh}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-7{width:calc(var(--spacing) * 7)}.w-\[22px\]{width:22px}.w-\[220px\]{width:220px}.w-\[500px\]{width:500px}.w-full{width:100%}.max-w-\[160px\]{max-width:160px}.max-w-\[180px\]{max-width:180px}.max-w-\[500px\]{max-width:500px}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[44px\]{min-width:44px}.min-w-\[140px\]{min-width:140px}.min-w-\[160px\]{min-width:160px}.flex-1{flex:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.resize{resize:both}.resize-y{resize:vertical}.grid-rows-\[35px_minmax\(0\,1fr\)\]{grid-template-rows:35px minmax(0,1fr)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.\!overflow-hidden{overflow:hidden!important}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded{border-radius:.25rem}.rounded-\[2px\]{border-radius:2px}.rounded-\[3px\]{border-radius:3px}.rounded-\[6px\]{border-radius:6px}.rounded-full{border-radius:3.40282e38px}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-accent{border-color:var(--color-accent)}.border-border{border-color:var(--color-border)}.bg-\[\#f14c4c\]{background-color:#f14c4c}.bg-accent{background-color:var(--color-accent)}.bg-accent\/20{background-color:#007acc33}@supports (color:color-mix(in lab,red,red)){.bg-accent\/20{background-color:color-mix(in oklab,var(--color-accent) 20%,transparent)}}.bg-bg{background-color:var(--color-bg)}.bg-bg-soft{background-color:var(--color-bg-soft)}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab,red,red)){.bg-black\/50{background-color:color-mix(in oklab,var(--color-black) 50%,transparent)}}.bg-border{background-color:var(--color-border)}.bg-list-active{background-color:var(--color-list-active)}.bg-list-hover{background-color:var(--color-list-hover)}.bg-panel{background-color:var(--color-panel)}.bg-sidebar{background-color:var(--color-sidebar)}.bg-title-bar{background-color:var(--color-title-bar)}.bg-transparent{background-color:#0000}.fill-current{fill:currentColor}.p-0{padding:calc(var(--spacing) * 0)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pl-3{padding-left:calc(var(--spacing) * 3)}.text-center{text-align:center}.text-left{text-align:left}.font-\[inherit\]{font-family:inherit}.font-mono{font-family:var(--font-mono)}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.75rem\]{font-size:.75rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[32px\]{font-size:32px}.leading-none{--tw-leading:1;line-height:1}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.5px\]{--tw-tracking:.5px;letter-spacing:.5px}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-words{overflow-wrap:break-word}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#f14c4c\]{color:#f14c4c}.text-accent{color:var(--color-accent)}.text-ink{color:var(--color-ink)}.text-ink-muted{color:var(--color-ink-muted)}.text-muted{color:var(--color-muted)}.text-red-400{color:var(--color-red-400)}.text-white{color:var(--color-white)}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.shadow-\[0_4px_12px_rgba\(0\,0\,0\,0\.15\)\]{--tw-shadow:0 4px 12px var(--tw-shadow-color,#00000026);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.group-hover\:flex:is(:where(.group):hover *){display:flex}.hover\:bg-\[rgba\(0\,0\,0\,0\.08\)\]:hover{background-color:#00000014}.hover\:bg-\[rgba\(241\,76\,76\,0\.1\)\]:hover{background-color:#f14c4c1a}.hover\:bg-list-hover:hover{background-color:var(--color-list-hover)}.hover\:bg-red-400\/10:hover{background-color:#ff65681a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-red-400\/10:hover{background-color:color-mix(in oklab,var(--color-red-400) 10%,transparent)}}.hover\:text-ink:hover{color:var(--color-ink)}.hover\:text-red-400:hover{color:var(--color-red-400)}.hover\:opacity-90:hover{opacity:.9}}.focus\:border-focus:focus{border-color:var(--color-focus)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-default:disabled{cursor:default}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media(hover:hover){.dark\:hover\:bg-\[rgba\(255\,255\,255\,0\.08\)\]:where([data-theme=dark],[data-theme=dark] *):hover{background-color:#ffffff14}}.scrollbar-none{scrollbar-width:none}.scrollbar-none::-webkit-scrollbar{display:none}.spin{animation:1s linear infinite spin}.slide-in{animation:.2s slideIn}}:root[data-theme=dark]{--color-bg:#1e1e1e;--color-bg-soft:#252526;--color-panel:#1e1e1e;--color-sidebar:#252526;--color-activitybar:#333;--color-activitybar-inactive:#fff6;--color-border:#3c3c3c;--color-ink:#ccc;--color-ink-muted:#9e9e9e;--color-muted:#8b8b8b;--color-accent:#0078d4;--color-list-hover:#ffffff0a;--color-list-active:#0078d433;--color-focus:#007fd4;--color-title-bar:#3c3c3c}@keyframes spin{to{transform:rotate(360deg)}}@keyframes slideIn{0%{transform:translate(-100%)}to{transform:translate(0)}}.app{grid-template-rows:minmax(0,1fr) 22px;grid-template-columns:48px minmax(0,1fr);height:100%;display:grid;overflow:hidden}.activity-bar{background:var(--color-activitybar);flex-direction:column;grid-row:1/3;width:48px;display:flex}.activity-bar-top{flex-direction:column;display:flex}.activity-bar-bottom{flex-direction:column;margin-top:auto;display:flex}.activity-bar-item{width:48px;height:48px;color:var(--color-activitybar-inactive);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;transition:color .15s;display:flex;position:relative}.activity-bar-item:hover,.activity-bar-item.active{color:var(--color-activitybar-fg)}.activity-bar-item svg{width:24px;height:24px}.activity-bar-badge{text-align:center;background:var(--color-accent);color:#fff;border-radius:8px;min-width:16px;height:16px;padding:0 4px;font-size:10px;font-weight:600;line-height:16px;position:absolute;top:8px;right:6px}.main{background:var(--color-bg);flex-direction:column;min-height:0;display:flex}.workspace-editor-overlay{background:var(--color-bg);z-index:30;grid-template-rows:35px minmax(0,1fr);display:grid;position:fixed;top:0;right:0;bottom:0;left:0}.workspace-editor-header{background:var(--color-title-bar);border-bottom:1px solid var(--color-border);align-items:center;gap:12px;padding:0 12px;display:flex}.workspace-meta{color:var(--color-muted);font-size:12px;font-family:var(--font-mono);text-overflow:ellipsis;white-space:nowrap;text-align:center;flex:1;overflow:hidden}.workspace-editor-grid{grid-template-rows:minmax(0,1fr);grid-template-columns:48px 220px minmax(0,1fr);height:100%;min-height:0;display:grid}.sidebar-panel{background:var(--color-sidebar);border-right:1px solid var(--color-border);flex-direction:column;height:100%;min-height:0;display:flex}.sidebar-content{flex:1;min-height:0;overflow:auto}.workspace-editor-grid>.activity-bar{background:var(--color-activitybar);border-right:1px solid var(--color-border);grid-row:unset;flex-direction:column;width:48px;display:flex}.workspace-editor-grid .activity-bar-item{color:var(--color-activitybar-fg);opacity:.6;transition:opacity .15s}.workspace-editor-grid .activity-bar-item:hover,.workspace-editor-grid .activity-bar-item.active{opacity:1}.panel{background:var(--color-panel);border:1px solid var(--color-border);border-radius:0;flex-direction:column;min-height:0;padding:0;display:flex}.panel-header{border-bottom:1px solid var(--color-border);background:var(--color-sidebar);justify-content:space-between;align-items:center;gap:8px;padding:8px 12px;display:flex}.panel-title{text-transform:uppercase;letter-spacing:.5px;color:var(--color-ink-muted);font-size:11px;font-weight:600}.panel-subtitle{color:var(--color-muted);text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.panel-body{flex:1;min-height:0;overflow:auto}.modal{background:var(--color-panel);border:1px solid var(--color-border);border-radius:4px;width:480px;max-width:96vw;max-height:90dvh;padding:16px;overflow-y:auto;box-shadow:0 8px 32px #0000004d}.modal-close-btn{color:var(--color-muted);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;width:32px;height:32px;padding:0;font-size:24px;line-height:1;display:flex}.modal-close-btn:hover{color:var(--color-ink);background:var(--color-list-hover)}.tree-body{padding:4px 0}.tree-row{color:var(--color-ink);text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:4px;width:100%;min-height:22px;padding:2px 8px 2px 4px;font-size:13px;transition:background .1s;display:flex}.tree-row:hover{background:var(--color-list-hover)}.tree-row:focus-visible{outline:2px solid var(--color-focus);outline-offset:-2px}.tree-chevron{width:16px;height:16px;color:var(--color-ink-muted);flex-shrink:0;justify-content:center;align-items:center;display:flex}.tree-chevron-icon{width:12px;height:12px;transition:transform .1s}.tree-icon{flex-shrink:0;justify-content:center;align-items:center;width:16px;height:16px;display:flex}.tree-svg{width:16px;height:16px}.tree-label{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.tree-meta{color:var(--color-muted);font-size:11px;font-family:var(--font-mono);margin-left:auto}.tree-state{color:var(--color-muted);padding:8px 12px;font-size:12px}.tree-actions{align-items:center;gap:4px;display:flex}.tree-input-row{align-items:center;gap:4px;min-height:22px;padding:2px 8px 2px 4px;display:flex}.tree-input{border:1px solid var(--color-accent);background:var(--color-panel);min-width:0;color:var(--color-ink);border-radius:2px;outline:none;flex:1;padding:2px 6px;font-size:13px}.tree-input::placeholder{color:var(--color-muted)}.editor-container{background:var(--color-panel);flex-direction:column;height:100%;display:flex;overflow:hidden}.editor-container.editor-empty{justify-content:center;align-items:center;display:flex}.editor-welcome{color:var(--color-ink-muted);text-align:center;flex-direction:column;align-items:center;gap:16px;padding:60px 40px;display:flex}.editor-welcome-icon{opacity:.2;width:80px;height:80px}.editor-welcome-icon svg{width:100%;height:100%;stroke:var(--color-ink)}.editor-welcome-text{color:var(--color-ink-muted);font-size:18px;font-weight:400}.editor-welcome-hint{opacity:.6;font-size:13px}.editor-tabs{background:var(--color-bg-soft);border-bottom:1px solid var(--color-border);flex-shrink:0;align-items:stretch;min-height:35px;display:flex}.editor-tabs-list{scrollbar-width:none;display:flex;overflow-x:auto}.editor-tabs-list::-webkit-scrollbar{display:none}.editor-tab{background:var(--color-bg-soft);border:none;border-right:1px solid var(--color-border);min-width:100px;max-width:180px;height:35px;color:var(--color-ink-muted);cursor:pointer;align-items:center;gap:6px;padding:0 10px;font-size:13px;transition:background .1s,color .1s;display:flex;position:relative}.editor-tab:hover{background:var(--color-panel);color:var(--color-ink)}.editor-tab.active{background:var(--color-panel);color:var(--color-ink);border-bottom:1px solid var(--color-panel);margin-bottom:-1px}.editor-tab-icon{font-size:10px;font-weight:600;font-family:var(--font-mono);flex-shrink:0}.editor-tab-name{text-overflow:ellipsis;white-space:nowrap;text-align:left;flex:1;overflow:hidden}.editor-tab-dirty{color:var(--color-ink);flex-shrink:0;font-size:18px;line-height:1}.editor-tab-saving{flex-shrink:0;width:14px;height:14px}.editor-tab-saving svg{width:100%;height:100%;stroke:var(--color-ink-muted)}.editor-tab-close{width:20px;height:20px;color:var(--color-ink-muted);cursor:pointer;opacity:0;background:0 0;border:none;border-radius:3px;flex-shrink:0;justify-content:center;align-items:center;padding:0;transition:opacity .1s,background .1s;display:flex}.editor-tab-close svg{width:16px;height:16px}.editor-tab-close:hover{background:var(--color-list-hover);color:var(--color-ink)}.editor-breadcrumb{background:var(--color-panel);border-bottom:1px solid var(--color-border);color:var(--color-ink-muted);flex-shrink:0;align-items:center;height:22px;padding:0 12px;font-size:12px;display:flex}.editor-breadcrumb-path{text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-mono);overflow:hidden}.editor-content{flex:1;min-height:0;position:relative}.editor-no-file{height:100%;color:var(--color-ink-muted);justify-content:center;align-items:center;display:flex}.editor-statusbar{background:var(--color-statusbar);height:22px;color:var(--color-statusbar-fg);flex-shrink:0;justify-content:space-between;align-items:center;padding:0 12px;font-size:12px;display:flex}.editor-statusbar-left,.editor-statusbar-right{align-items:center;gap:14px;display:flex}.editor-status-item{cursor:default;align-items:center;gap:4px;display:flex}.editor-status-item svg{width:14px;height:14px}.terminal-layout{overflow-anchor:none;flex-direction:column;flex:1;min-width:0;min-height:0;display:flex;overflow:hidden}.terminal-topbar{background:var(--color-sidebar);border-bottom:1px solid var(--color-border);flex-shrink:0;align-items:stretch;min-width:0;display:flex;overflow:hidden}.topbar-left{flex:1;align-items:stretch;min-width:0;display:flex;overflow:hidden}.deck-tabs{scrollbar-width:none;flex:1;align-items:stretch;min-width:0;display:flex;overflow-x:auto}.deck-tabs::-webkit-scrollbar{display:none}.deck-tab{border:none;border-top:2px solid #0000;border-right:1px solid var(--color-border);min-width:80px;max-width:200px;color:var(--color-muted);cursor:pointer;white-space:nowrap;background:0 0;flex-shrink:0;align-items:center;gap:4px;padding:0 8px 0 12px;font-size:12px;font-weight:500;transition:background .12s,color .12s;display:flex}.deck-tab[draggable=true]{cursor:grab}.deck-tab.is-dragging{opacity:.5}.deck-tab.is-drag-over{background:var(--color-list-active);color:var(--color-ink)}.deck-tab:hover{background:var(--color-list-hover);color:var(--color-ink)}.deck-tab.active{background:var(--color-panel);color:var(--color-ink);border-top-color:var(--color-accent)}.deck-tab-name{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.deck-tab-close{opacity:0;width:16px;height:16px;color:var(--color-muted);border-radius:3px;flex-shrink:0;justify-content:center;align-items:center;font-size:13px;line-height:1;transition:opacity .12s,background .12s;display:flex}.deck-tab-add{border-top:none;justify-content:center;min-width:35px;max-width:35px;padding:0;font-size:16px;font-weight:300}.deck-tab-add:hover{background:var(--color-list-hover);color:var(--color-ink)}.terminal-split-container{flex:1;grid-auto-rows:minmax(0,1fr);gap:4px;width:100%;min-width:0;max-width:100%;min-height:0;padding:4px;display:grid;position:relative}.deck-split-pane{border:1px solid var(--color-border);border-radius:4px;flex-direction:column;min-width:0;min-height:0;display:flex;overflow:hidden}.topbar-btn-sm{border:1px solid var(--color-border);color:var(--color-muted);cursor:pointer;background:0 0;border-radius:3px;padding:2px 6px;font-size:11px;font-weight:600;transition:all .15s}.topbar-btn-sm:hover{background:var(--color-list-hover);color:var(--color-ink);border-color:var(--color-accent)}.topbar-btn-sm.topbar-btn-claude{color:#d97757}.topbar-btn-sm.topbar-btn-claude:hover{background:#d9775726;border-color:#d97757}.topbar-btn-sm.topbar-btn-codex{color:#00a86b}.topbar-btn-sm.topbar-btn-codex:hover{background:#00a86b26;border-color:#00a86b}.drive-mini-btn{color:var(--color-muted);cursor:pointer;background:0 0;border:0;border-radius:3px;padding:1px 5px;font-size:11px;line-height:1.4}.drive-mini-btn:hover{background:var(--color-list-hover);color:var(--color-ink)}.drive-body.drive-drag-active{outline:2px dashed var(--color-accent);outline-offset:-6px;background:var(--color-list-hover)}.drive-tab{cursor:pointer;background:0 0;border:0;border-bottom:2px solid #0000}.code-server-frame{background:#1e1e1e;border:0;width:100%;height:100%;display:block}.drive-mobilebar{display:none}@media(max-width:720px){.drive-mobilebar{border-bottom:1px solid var(--color-border);background:var(--color-sidebar);flex-shrink:0;align-items:center;gap:8px;min-height:40px;padding:6px 10px;display:flex}.drive-rail{z-index:50;transition:transform .2s;position:fixed;top:0;bottom:0;left:0;transform:translate(-100%);box-shadow:2px 0 10px #00000059}.drive-rail.is-open{transform:translate(0)}.drive-rail-backdrop{z-index:49;background:#00000073;position:fixed;top:0;right:0;bottom:0;left:0}}.terminal-pane{overflow-anchor:none;flex-direction:column;flex:1;min-width:0;min-height:0;padding:4px;display:flex}.terminal-grid{flex:1;gap:4px;width:100%;min-width:0;min-height:0;display:grid;overflow:hidden}.terminal-tile-slot{display:contents}.terminal-switcher{display:none}.terminal-grid-single{flex-direction:column!important;flex:1!important;gap:0!important;min-height:0!important;padding:0!important;display:flex!important;overflow:hidden!important}.terminal-tile-slot-single-active{flex-direction:column;flex:1;min-height:0;overflow:hidden;display:flex!important}.terminal-tile-slot-single-active .terminal-tile{border:none;border-radius:0;flex:1;height:auto!important;min-height:0!important}.terminal-tile-slot-single-hidden{display:none!important}.deck-terminals-single .terminal-switcher{background:var(--color-bg-soft);min-width:120px;max-width:50%;color:var(--color-ink);border:1px solid var(--color-border);border-radius:3px;flex:0 auto;padding:2px 6px;font-size:11px;display:block}.terminal-empty{background:var(--color-bg-soft);border:1px dashed var(--color-border);color:var(--color-muted);border-radius:4px;flex:1;justify-content:center;align-items:center;font-size:12px;display:flex}.terminal-tile{border:1px solid var(--color-border);color:#d4d4d4;background:#1e1e1e;border-radius:4px;flex-direction:column;min-width:0;min-height:0;transition:background .15s ease-out,box-shadow .15s ease-out;display:flex;overflow:hidden}.terminal-tile.bell-flash{background:#2a2a3a;transition:none;box-shadow:inset 0 0 0 2px #78aaffb3}.terminal-tile-header{background:#2d2d2d;border-bottom:1px solid #404040;justify-content:space-between;align-items:center;gap:8px;padding:6px 10px;font-size:12px;display:flex}.terminal-tile-header span{text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-mono);flex:1;overflow:hidden}.terminal-close-btn{color:#858585;cursor:pointer;background:0 0;border:none;border-radius:3px;flex-shrink:0;justify-content:center;align-items:center;width:20px;height:20px;transition:background .1s,color .1s;display:flex}.terminal-close-btn:hover{color:#fff;background:#404040}.terminal-tile-body{overflow-anchor:none;overscroll-behavior:contain;touch-action:pan-y;flex:1;min-height:0;overflow:hidden}.terminal-tile-body .xterm,.terminal-tile-body .xterm-viewport,.terminal-tile-body .xterm-screen{overflow-anchor:none}.terminal-tile-body .xterm-helper-textarea{z-index:0!important}.terminal-tile-body .xterm-viewport{overscroll-behavior-y:contain;-webkit-overflow-scrolling:touch;touch-action:pan-y}.browser-layout{background:var(--color-panel);flex-direction:column;flex:1;min-width:0;min-height:0;display:flex;overflow:hidden}.browser-toolbar{background:var(--color-sidebar);border-bottom:1px solid var(--color-border);justify-content:space-between;align-items:center;gap:10px;min-height:38px;padding:4px 8px;display:flex}.browser-address-group{flex:1;align-items:center;gap:6px;min-width:0;display:flex}.browser-toolbar-button,.browser-go-button{border:1px solid var(--color-border);background:var(--color-bg-soft);width:28px;height:28px;color:var(--color-ink);cursor:pointer;border-radius:4px;justify-content:center;align-items:center;font-size:12px;line-height:1;display:flex}.browser-toolbar-button:hover,.browser-go-button:hover{background:var(--color-list-hover)}.browser-toolbar-button-active{border-color:var(--color-accent);color:var(--color-accent)}.browser-toolbar-button svg{width:16px;height:16px}.browser-toolbar-button:disabled,.browser-go-button:disabled{opacity:.45;cursor:not-allowed}.browser-address-form{flex:1;align-items:center;gap:6px;min-width:0;display:flex}.browser-address-input{border:1px solid var(--color-border);background:var(--color-panel);min-width:0;height:28px;color:var(--color-ink);font-family:var(--font-mono);border-radius:4px;flex:1;padding:0 9px;font-size:12px}.browser-status-line{color:var(--color-ink-muted);font-size:11px;font-family:var(--font-mono);text-overflow:ellipsis;white-space:nowrap;flex-shrink:0;align-items:center;gap:6px;max-width:180px;display:flex;overflow:hidden}.browser-dot{background:var(--color-muted);border-radius:50%;width:8px;height:8px}.browser-dot-running{background:var(--color-git-staged)}.browser-error{border-bottom:1px solid var(--color-border);color:var(--color-git-deleted);text-overflow:ellipsis;white-space:nowrap;background:#f14c4c1f;flex-shrink:0;padding:6px 10px;font-size:12px;overflow:hidden}.browser-tabs{background:var(--color-sidebar);border-bottom:1px solid var(--color-border);scrollbar-width:thin;flex-shrink:0;align-items:stretch;gap:4px;padding:4px 6px;display:flex;overflow-x:auto}.browser-tab{border:1px solid var(--color-border);background:var(--color-bg-soft);min-width:92px;max-width:180px;color:var(--color-ink-muted);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:6px;align-items:center;gap:6px;padding:4px 6px 4px 10px;font-size:12px;display:flex}.browser-tab:hover{background:var(--color-list-hover)}.browser-tab-active{background:var(--color-panel);color:var(--color-ink);border-color:var(--color-accent)}.browser-tab-title{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.browser-tab-close{width:16px;height:16px;color:inherit;cursor:pointer;opacity:.6;background:0 0;border:none;border-radius:4px;flex-shrink:0;justify-content:center;align-items:center;font-size:13px;line-height:1;display:flex}.browser-tab-close:hover{background:var(--color-list-hover);opacity:1}.browser-tab-new{border:1px solid var(--color-border);background:var(--color-bg-soft);width:28px;color:var(--color-ink);cursor:pointer;border-radius:6px;flex-shrink:0;font-size:16px;line-height:1}.browser-tab-new:hover{background:var(--color-list-hover)}.browser-audio{display:none}.browser-viewport{background:#111;outline:none;flex:1;justify-content:center;align-items:center;min-width:0;min-height:0;display:flex;overflow:hidden}.browser-viewport:focus-visible{box-shadow:inset 0 0 0 2px var(--color-focus)}.browser-frame{object-fit:contain;-webkit-user-select:none;user-select:none;cursor:default;width:100%;height:100%;display:block}.browser-state{text-align:center;color:#c8c8c8;font-family:var(--font-mono);flex-direction:column;align-items:center;gap:12px;padding:24px;display:flex}.browser-state-title{color:#e6e6e6;font-size:13px}.browser-state-hint{color:#9a9a9a;max-width:280px;font-size:12px;line-height:1.5}.browser-state-action{border:1px solid var(--color-border);background:var(--color-bg-soft);color:var(--color-ink);cursor:pointer;font-size:12px;font-family:var(--font-mono);border-radius:4px;padding:6px 16px}.browser-state-action:hover:not(:disabled){background:var(--color-list-hover)}.browser-state-action:disabled{opacity:.45;cursor:not-allowed}.browser-spinner{border:2px solid #ffffff2e;border-top-color:var(--color-accent);border-radius:50%;width:22px;height:22px;animation:.8s linear infinite browser-spin}@keyframes browser-spin{to{transform:rotate(360deg)}}.git-modified{color:var(--color-git-modified)}.git-untracked{color:var(--color-git-untracked)}.git-deleted{color:var(--color-git-deleted)}.git-staged{color:var(--color-git-staged)}.git-renamed{color:var(--color-git-renamed)}.git-conflicted{color:var(--color-git-conflicted)}.git-tabs{border-bottom:1px solid var(--color-border);background:var(--color-sidebar);flex-shrink:0;display:flex}.git-tab{color:var(--color-ink-muted);cursor:pointer;background:0 0;border:none;align-items:center;gap:6px;padding:6px 12px;font-size:12px;transition:color .1s,background .1s;display:flex;position:relative}.git-tab:hover{color:var(--color-ink);background:var(--color-list-hover)}.git-tab.active{color:var(--color-ink)}.git-file-row{align-items:center;gap:4px;transition:background .1s;display:flex}.git-file-row:hover{background:var(--color-list-hover)}.git-file-main{color:var(--color-ink);cursor:pointer;text-align:left;background:0 0;border:none;flex:1;align-items:center;gap:6px;min-width:0;min-height:22px;padding:4px 12px;display:flex}.git-status-badge{width:16px;height:16px;font-size:11px;font-weight:600;font-family:var(--font-mono);flex-shrink:0;justify-content:center;align-items:center;display:flex}.git-file-path{text-overflow:ellipsis;white-space:nowrap;font-size:13px;overflow:hidden}.git-file-actions{opacity:0;gap:2px;padding-right:8px;transition:opacity .1s;display:flex}.git-action-btn{width:22px;height:22px;color:var(--color-ink-muted);cursor:pointer;background:0 0;border:none;border-radius:3px;justify-content:center;align-items:center;padding:0;transition:background .1s,color .1s;display:flex}.git-action-btn:hover{background:var(--color-list-hover);color:var(--color-ink)}.git-action-btn svg{fill:currentColor;width:14px;height:14px}.status-float{right:20px;bottom:calc(40px + env(safe-area-inset-bottom,0px));background:var(--color-panel);border:1px solid var(--color-border);color:var(--color-ink);border-radius:4px;max-width:min(400px,100vw - 40px);padding:8px 14px;font-size:12px;position:fixed;box-shadow:0 4px 16px #0003}.sidebar-toggle-btn,.sidebar-overlay{display:none}@media(max-width:1024px){.workspace-editor-grid{grid-template-rows:200px minmax(0,1fr);grid-template-columns:48px 1fr}.workspace-editor-grid>.activity-bar{grid-row:1/-1}.sidebar-panel{border-right:none;border-bottom:1px solid var(--color-border)}}@media(max-width:720px){.app{padding-bottom:env(safe-area-inset-bottom);grid-template-rows:minmax(0,1fr) 48px 22px;grid-template-columns:1fr}.app>nav.activity-bar{width:auto;height:48px;padding:0 max(8px,env(safe-area-inset-right,0px)) 0 max(8px,env(safe-area-inset-left,0px));border-top:1px solid var(--color-border);flex-direction:row;grid-row:2;justify-content:space-between;gap:8px}.activity-bar-top,.activity-bar-bottom{flex-direction:row;align-items:center;gap:4px}.activity-bar-bottom{margin-top:0;margin-left:0}.main{grid-row:1;min-width:0;overflow:hidden}.sidebar-toggle-btn{justify-content:center;align-items:center;display:flex}.activity-bar-item{min-width:44px;min-height:44px}.deck-tab{min-height:40px;padding:0 8px 0 14px;font-size:13px}.topbar-btn-sm{min-width:44px;min-height:40px;padding:0 10px}.tree-row,.editor-tab{min-height:36px}.modal-close-btn{min-width:44px;min-height:44px}.modal{border-radius:8px;max-width:calc(100vw - 16px);max-height:90dvh;margin:8px}.deck-tabs{-webkit-overflow-scrolling:touch;scrollbar-width:none;flex-wrap:nowrap;overflow-x:auto}.deck-tabs::-webkit-scrollbar{display:none}.terminal-split-container{scroll-snap-type:none;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain;touch-action:auto;scrollbar-width:none;width:100%;max-width:100%;overflow:scroll hidden;flex-direction:row!important;gap:0!important;padding:0!important;display:flex!important}.terminal-split-container::-webkit-scrollbar{display:none}.deck-split-pane{scroll-snap-align:start;border-left:none;border-right:none;border-radius:0;flex:0 0 100%;width:100%;max-width:100%;overflow:hidden}.terminal-pane{flex:auto;width:100%;max-width:100%;min-height:0;overflow:hidden;padding:0!important}.terminal-grid-mobile{flex-direction:column!important;flex:1!important;gap:0!important;min-height:0!important;padding:0!important;display:flex!important;overflow:hidden!important}.terminal-tile-slot-mobile-active{flex-direction:column;flex:1;min-height:0;overflow:hidden;display:flex!important}.terminal-tile-slot-mobile-active .terminal-tile{border:none;border-radius:0;flex:1;height:auto!important;min-height:0!important}.terminal-tile-slot-mobile-hidden{display:none!important}.terminal-switcher{background:var(--color-bg-soft);min-width:0;max-width:60%;height:28px;color:var(--color-ink);border:1px solid var(--color-border);font-size:12px;font-family:var(--font-mono);border-radius:4px;flex:auto;padding:0 8px;display:block}.status-float{right:12px;bottom:calc(78px + env(safe-area-inset-bottom,0px));max-width:calc(100vw - 24px)}html.keyboard-open .app{grid-template-rows:minmax(0,1fr);padding-bottom:0}html.keyboard-open .app>nav.activity-bar{display:none}html.keyboard-open .status-float{bottom:calc(env(safe-area-inset-bottom,0px) + 8px)}.workspace-editor-grid{grid-template-rows:minmax(0,1fr);grid-template-columns:1fr;position:relative}.workspace-editor-grid>.activity-bar{z-index:101;border-right:1px solid var(--color-border);border-top:none;flex-direction:column;width:48px;height:auto;transition:transform .2s;position:absolute;top:0;bottom:0;left:0;transform:translate(-100%)}.sidebar-panel{z-index:100;border-bottom:none;border-right:1px solid var(--color-border);width:260px;transition:transform .2s;position:absolute;top:0;bottom:0;left:48px;overflow-y:auto;transform:translate(calc(-100% - 48px))}.drawer-open .workspace-editor-grid>.activity-bar,.drawer-open .sidebar-panel{transform:translate(0)}.sidebar-overlay{z-index:99;background:#0006;display:none;position:absolute;top:0;right:0;bottom:0;left:0}.drawer-open .sidebar-overlay{display:block}.workspace-editor-header{gap:8px;padding:0 8px}.workspace-editor-header .sidebar-toggle-btn{order:3;margin-left:auto}.workspace-editor-header .workspace-meta{text-align:left;min-width:0}}@media(pointer:coarse){.modal-close-btn:hover,.tree-row:hover,.editor-tab:hover,.deck-tab:hover,.deck-tab-add:hover,.topbar-btn-sm:hover,.terminal-close-btn:hover,.git-file-row:hover,.git-action-btn:hover,.git-tab:hover{border-color:inherit;color:inherit;opacity:1;background:0 0}.editor-tab:hover{color:var(--color-ink-muted);background:0 0}.git-file-actions{opacity:1}}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}