linkshell-cli 0.5.29 → 0.5.31

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.
@@ -1,5 +1,6 @@
1
1
  import { homedir } from "node:os";
2
- import { readdirSync, existsSync, readFileSync, statSync } from "node:fs";
2
+ import { readdirSync, existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
3
+ import { randomUUID } from "node:crypto";
3
4
  import { isAbsolute, join, relative, resolve } from "node:path";
4
5
  import type { AgentFraming, AgentProtocol } from "./provider-resolver.js";
5
6
 
@@ -403,16 +404,15 @@ export function parseClaudeJsonlSession(input: {
403
404
  * stale, the driver is gone → idle.
404
405
  * Verified against real transcripts: mid-turn+fresh→running, mid-turn+stale→
405
406
  * idle, end_turn+fresh→idle, half-written-line+fresh→running. */
406
- function deriveTranscriptStatus(text: string, mtimeMs: number, nowMs: number): "running" | "idle" {
407
- const FRESH_MS = 10_000;
408
- // A stale file is always idle: every non-fresh path below resolves to "idle"
409
- // (end_turn → idle, and the final `midTurn && fresh` is false when !fresh).
410
- // Short-circuit so the common case — most sessions in ~/.claude/projects are
411
- // old — costs one comparison and parses nothing.
412
- if (nowMs - mtimeMs >= FRESH_MS) return "idle";
413
- // Fresh file: find the last non-empty record by scanning backward from the
414
- // end of the string, instead of text.split() materializing every line of a
415
- // possibly-huge transcript just to read its tail.
407
+ const TRANSCRIPT_FRESH_MS = 10_000;
408
+
409
+ /** The structural half of the status verdict: does the LAST record of a
410
+ * transcript indicate an in-progress turn (awaiting/producing an assistant
411
+ * response, or a half-written trailing line)? This is purely content-derived
412
+ * — it does NOT depend on the clock — so it can be cached alongside the parsed
413
+ * metadata and reused across syncs until the file's (mtime,size) changes.
414
+ * Scans backward from the end to avoid split()-ing a possibly-huge transcript. */
415
+ function deriveTranscriptMidTurn(text: string): boolean {
416
416
  let last: Record<string, unknown> | undefined;
417
417
  let sawUnparseableTail = false;
418
418
  let end = text.length;
@@ -429,44 +429,76 @@ function deriveTranscriptStatus(text: string, mtimeMs: number, nowMs: number): "
429
429
  sawUnparseableTail = true;
430
430
  }
431
431
  }
432
- if (!last) return "idle";
432
+ if (!last) return false;
433
433
  const message = asRecord(last.message);
434
434
  const role = stringField(message, ["role"]) ?? stringField(last, ["type"]);
435
435
  const stop = message ? message.stop_reason ?? null : null;
436
- if (role === "assistant" && stop === "end_turn") return "idle";
437
- const midTurn =
436
+ if (role === "assistant" && stop === "end_turn") return false;
437
+ return (
438
438
  role === "user" ||
439
439
  last.type === "user" ||
440
440
  (role === "assistant" && (stop === "tool_use" || stop === null)) ||
441
- sawUnparseableTail;
442
- // fresh is implied here (we returned early when stale).
441
+ sawUnparseableTail
442
+ );
443
+ }
444
+
445
+ /** Combine the (clock-independent) structural verdict with the freshness signal.
446
+ * A stale file (no writes within FRESH_MS) is always idle; a mid-turn file that
447
+ * is still being appended to is running. Cheap: one comparison + one boolean. */
448
+ function statusFromMidTurn(midTurn: boolean, mtimeMs: number, nowMs: number): "running" | "idle" {
449
+ if (nowMs - mtimeMs >= TRANSCRIPT_FRESH_MS) return "idle";
443
450
  return midTurn ? "running" : "idle";
444
451
  }
445
452
 
446
- function claudeSessionMetadataFromFile(filePath: string, cwd: string, sessionId: string): Record<string, unknown> {
447
- const stat = statSync(filePath);
453
+ /** Derive whether an on-disk Claude transcript is being actively driven RIGHT
454
+ * NOW, purely from the file. See {@link deriveTranscriptMidTurn} /
455
+ * {@link statusFromMidTurn}; kept as a convenience wrapper for callers that
456
+ * hold the full text and the clock but no cache. */
457
+ function deriveTranscriptStatus(text: string, mtimeMs: number, nowMs: number): "running" | "idle" {
458
+ // Stale short-circuit: most sessions in ~/.claude/projects are old, so avoid
459
+ // the backward scan entirely when the file can't possibly be running.
460
+ if (nowMs - mtimeMs >= TRANSCRIPT_FRESH_MS) return "idle";
461
+ return statusFromMidTurn(deriveTranscriptMidTurn(text), mtimeMs, nowMs);
462
+ }
463
+
464
+ /** Parse a transcript into the clock-independent, cacheable half of its list
465
+ * metadata: everything except `status` (which depends on `now`). The caller
466
+ * layers status on via {@link statusFromMidTurn}, and can cache this result
467
+ * keyed by (path, mtime, size) so an unchanged transcript is never re-read. */
468
+ function claudeSessionBaseFromFile(
469
+ filePath: string,
470
+ cwd: string,
471
+ sessionId: string,
472
+ mtimeMs: number,
473
+ ): { base: Record<string, unknown>; midTurn: boolean } {
448
474
  const text = readFileSync(filePath, "utf8");
449
475
  const parsed = parseClaudeJsonlSession({
450
476
  text,
451
477
  cwd,
452
478
  sessionId,
453
- fallbackUpdatedAt: stat.mtimeMs,
479
+ fallbackUpdatedAt: mtimeMs,
454
480
  });
455
481
  const thread = asRecord(parsed.thread) ?? {};
456
- return {
482
+ const base: Record<string, unknown> = {
457
483
  id: sessionId,
458
484
  cwd: stringField(thread, ["cwd", "workingDirectory", "workspacePath"]) ?? cwd,
459
485
  title: stringField(thread, ["title", "preview"]),
460
486
  model: stringField(thread, ["model"]),
461
487
  createdAt: parseTimestamp(thread.createdAt),
462
- lastActivityAt: parseTimestamp(thread.updatedAt) ?? stat.mtimeMs,
463
- lastModified: stat.mtimeMs,
488
+ lastActivityAt: parseTimestamp(thread.updatedAt) ?? mtimeMs,
489
+ lastModified: mtimeMs,
464
490
  usage: asRecord(thread.usage),
465
- // Live status read straight from the transcript, so a session another
466
- // `claude` process is actively driving shows as "running" in the list
467
- // rather than the hardcoded "idle" the workspace would otherwise assign.
468
- status: deriveTranscriptStatus(text, stat.mtimeMs, Date.now()),
469
491
  };
492
+ return { base, midTurn: deriveTranscriptMidTurn(text) };
493
+ }
494
+
495
+ function claudeSessionMetadataFromFile(filePath: string, cwd: string, sessionId: string): Record<string, unknown> {
496
+ const stat = statSync(filePath);
497
+ const { base, midTurn } = claudeSessionBaseFromFile(filePath, cwd, sessionId, stat.mtimeMs);
498
+ // Live status read straight from the transcript, so a session another
499
+ // `claude` process is actively driving shows as "running" in the list
500
+ // rather than the hardcoded "idle" the workspace would otherwise assign.
501
+ return { ...base, status: statusFromMidTurn(midTurn, stat.mtimeMs, Date.now()) };
470
502
  }
471
503
 
472
504
  function isInsideCwd(cwd: string, candidate: string): boolean {
@@ -525,6 +557,13 @@ export class ClaudeSdkClient {
525
557
  private claudeSessionId: string | undefined;
526
558
  private abortController: AbortController | undefined;
527
559
  private permissionWaiters = new Map<string, (outcome: "allow" | "deny") => void>();
560
+ // Per-file cache for listSessions: an unchanged transcript (same mtime+size)
561
+ // is never re-read or re-parsed. fs.watch re-syncs fire every ~1.5s while any
562
+ // session is active, and ~/.claude/projects can hold hundreds of old
563
+ // transcripts — without this, each sync would readFileSync + fully parse
564
+ // every one of them (the "scan storm"). Only the file being actively appended
565
+ // to changes, so the steady-state cost drops to stat()+status per file.
566
+ private sessionMetaCache = new Map<string, { mtimeMs: number; size: number; base: Record<string, unknown>; midTurn: boolean }>();
528
567
 
529
568
  constructor(
530
569
  private readonly input: {
@@ -602,6 +641,61 @@ export class ClaudeSdkClient {
602
641
  .find((candidate) => existsSync(candidate));
603
642
  }
604
643
 
644
+ /** Fork a session: copy the source transcript into a NEW session file,
645
+ * truncated to include everything up to and including the turn `uptoTurnId`
646
+ * (omitted → full clone). Claude has no native fork primitive, so this
647
+ * simulates one by writing a fresh <uuid>.jsonl alongside the source. The
648
+ * source file is NEVER modified. Turn ids match the per-line uuid/id (or the
649
+ * `claude-history-<n>` fallback) that parseClaudeJsonlSession assigns, where
650
+ * <n> counts non-empty lines — replicated here so the cut lands exactly on
651
+ * the turn the client asked for. Returns the new session id, or undefined if
652
+ * the source can't be read or the new file can't be created. */
653
+ forkSession(input: { sourceSessionId: string; uptoTurnId?: string }): { sessionId: string } | undefined {
654
+ const sourceFile = this.resolveSessionFile(input.sourceSessionId);
655
+ if (!sourceFile) return undefined;
656
+ let text: string;
657
+ try {
658
+ text = readFileSync(sourceFile, "utf8");
659
+ } catch {
660
+ return undefined;
661
+ }
662
+ const lines = text.split("\n");
663
+ let cutIndex = lines.length - 1; // default: keep everything (full clone)
664
+ if (input.uptoTurnId) {
665
+ let nonEmpty = 0;
666
+ let found = -1;
667
+ for (let i = 0; i < lines.length; i += 1) {
668
+ const line = lines[i]?.trim();
669
+ if (!line) continue;
670
+ nonEmpty += 1;
671
+ let turnId: string;
672
+ try {
673
+ const rec = asRecord(JSON.parse(line));
674
+ turnId = stringField(rec, ["uuid", "id"]) ?? `claude-history-${nonEmpty}`;
675
+ } catch {
676
+ continue; // unparseable line — parser skips it too (index still bumped)
677
+ }
678
+ if (turnId === input.uptoTurnId) {
679
+ found = i;
680
+ break;
681
+ }
682
+ }
683
+ if (found < 0) return undefined; // turn not found — don't silently full-clone
684
+ cutIndex = found;
685
+ }
686
+ const truncated = lines.slice(0, cutIndex + 1).join("\n") + "\n";
687
+ const newId = randomUUID();
688
+ const dir = claudeProjectDir(this.input.cwd);
689
+ const newPath = join(dir, `${newId}.jsonl`);
690
+ try {
691
+ // wx: fail if it somehow already exists — never overwrite.
692
+ writeFileSync(newPath, truncated, { flag: "wx" });
693
+ } catch {
694
+ return undefined;
695
+ }
696
+ return { sessionId: newId };
697
+ }
698
+
605
699
  /** Read a session's last-known settings (permission mode, plan mode) straight
606
700
  * from its on-disk transcript, so opening a session LinkShell never drove
607
701
  * shows the config it actually ran with instead of UI defaults. Claude
@@ -837,6 +931,8 @@ export class ClaudeSdkClient {
837
931
  async listSessions(): Promise<unknown> {
838
932
  const sessions: Array<Record<string, unknown>> = [];
839
933
  const seen = new Set<string>();
934
+ const now = Date.now();
935
+ const liveKeys = new Set<string>();
840
936
  for (const projectDir of claudeProjectDirs(this.input.cwd)) {
841
937
  try {
842
938
  for (const entry of readdirSync(projectDir)) {
@@ -844,12 +940,36 @@ export class ClaudeSdkClient {
844
940
  const sessionId = entry.replace(".jsonl", "");
845
941
  if (seen.has(sessionId)) continue;
846
942
  seen.add(sessionId);
847
- sessions.push(claudeSessionMetadataFromFile(join(projectDir, entry), this.input.cwd, sessionId));
943
+ const filePath = join(projectDir, entry);
944
+ let stat;
945
+ try {
946
+ stat = statSync(filePath);
947
+ } catch {
948
+ continue; // vanished between readdir and stat
949
+ }
950
+ liveKeys.add(filePath);
951
+ let cached = this.sessionMetaCache.get(filePath);
952
+ if (!cached || cached.mtimeMs !== stat.mtimeMs || cached.size !== stat.size) {
953
+ // Miss or stale: re-read + re-parse this ONE file, refresh the cache.
954
+ const { base, midTurn } = claudeSessionBaseFromFile(filePath, this.input.cwd, sessionId, stat.mtimeMs);
955
+ cached = { mtimeMs: stat.mtimeMs, size: stat.size, base, midTurn };
956
+ this.sessionMetaCache.set(filePath, cached);
957
+ }
958
+ // status is clock-dependent, so recompute it every call (cheap) even
959
+ // on a cache hit — a running session goes idle purely by time passing.
960
+ sessions.push({ ...cached.base, status: statusFromMidTurn(cached.midTurn, stat.mtimeMs, now) });
848
961
  }
849
962
  } catch {
850
963
  // Ignore unreadable Claude project storage.
851
964
  }
852
965
  }
966
+ // Drop cache entries for transcripts that no longer exist so the map can't
967
+ // grow without bound across a long-lived process.
968
+ if (this.sessionMetaCache.size > liveKeys.size) {
969
+ for (const key of this.sessionMetaCache.keys()) {
970
+ if (!liveKeys.has(key)) this.sessionMetaCache.delete(key);
971
+ }
972
+ }
853
973
  return { sessions };
854
974
  }
855
975
 
@@ -895,6 +1015,16 @@ export class ClaudeSdkClient {
895
1015
  } catch {
896
1016
  // supportedCommands() unavailable or failed — fall back to static defaults.
897
1017
  }
1018
+ // Discover MCP server status the same best-effort way. Older SDKs
1019
+ // without mcpServerStatus() just leave mcpServers undefined; live
1020
+ // startupStatus events still populate it. Shape is passed through
1021
+ // verbatim to the workspace parser, which tolerates array/record forms.
1022
+ let mcpServers: unknown;
1023
+ try {
1024
+ mcpServers = await (q as unknown as { mcpServerStatus?: () => Promise<unknown> }).mcpServerStatus?.();
1025
+ } catch {
1026
+ // mcpServerStatus() unavailable or failed — rely on live events.
1027
+ }
898
1028
  if (sdkModels.length > 0) {
899
1029
  // Filter to admin-configured allowlist if present, then map to our format.
900
1030
  const allow = availableModels;
@@ -905,16 +1035,18 @@ export class ClaudeSdkClient {
905
1035
  defaultModel,
906
1036
  models: filtered.map((m) => ({ id: m.value, label: m.displayName || m.value })),
907
1037
  ...(commands ? { commands } : {}),
1038
+ ...(mcpServers ? { mcpServers } : {}),
908
1039
  };
909
1040
  }
910
1041
  // No models surfaced, but commands may still be present — return them
911
1042
  // so the command palette stays in sync even when the model list is empty.
912
- if (commands) {
1043
+ if (commands || mcpServers) {
913
1044
  const fallbackModels = availableModels ?? DEFAULT_FALLBACK_MODELS;
914
1045
  return {
915
1046
  defaultModel,
916
1047
  models: toModelEntries(fallbackModels),
917
- commands,
1048
+ ...(commands ? { commands } : {}),
1049
+ ...(mcpServers ? { mcpServers } : {}),
918
1050
  };
919
1051
  }
920
1052
  } catch {
@@ -124,6 +124,10 @@ export class ClaudeStreamJsonClient {
124
124
  private child: ChildProcessWithoutNullStreams | undefined;
125
125
  private claudeSessionId: string | undefined;
126
126
  private pendingCancel = false;
127
+ // Per-file cache for listSessions: skip re-reading/parsing an unchanged
128
+ // transcript (same mtime+size). fs.watch re-syncs fire every ~1.5s, so
129
+ // without this each sync would re-parse every transcript in ~/.claude/projects.
130
+ private sessionMetaCache = new Map<string, { mtimeMs: number; size: number; entry: Record<string, unknown> }>();
127
131
 
128
132
  constructor(
129
133
  private readonly input: {
@@ -537,6 +541,7 @@ export class ClaudeStreamJsonClient {
537
541
  async listSessions(): Promise<unknown> {
538
542
  const sessions: Array<Record<string, unknown>> = [];
539
543
  const seen = new Set<string>();
544
+ const liveKeys = new Set<string>();
540
545
  for (const projectDir of claudeProjectDirs(this.input.cwd)) {
541
546
  try {
542
547
  for (const entry of readdirSync(projectDir)) {
@@ -545,30 +550,48 @@ export class ClaudeStreamJsonClient {
545
550
  if (seen.has(sessionId)) continue;
546
551
  seen.add(sessionId);
547
552
  const filePath = join(projectDir, entry);
548
- const stat = statSync(filePath);
549
- const parsed = parseClaudeJsonlSession({
550
- text: readFileSync(filePath, "utf8"),
551
- cwd: this.input.cwd,
552
- sessionId,
553
- fallbackUpdatedAt: stat.mtimeMs,
554
- });
555
- const thread = parsed.thread && typeof parsed.thread === "object"
556
- ? parsed.thread as Record<string, unknown>
557
- : {};
558
- sessions.push({
559
- id: sessionId,
560
- cwd: stringField(thread, ["cwd", "workingDirectory", "workspacePath"]) ?? this.input.cwd,
561
- title: stringField(thread, ["title", "preview"]),
562
- model: stringField(thread, ["model"]),
563
- createdAt: thread.createdAt,
564
- lastActivityAt: thread.updatedAt ?? stat.mtimeMs,
565
- lastModified: stat.mtimeMs,
566
- });
553
+ let stat;
554
+ try {
555
+ stat = statSync(filePath);
556
+ } catch {
557
+ continue; // vanished between readdir and stat
558
+ }
559
+ liveKeys.add(filePath);
560
+ let cached = this.sessionMetaCache.get(filePath);
561
+ if (!cached || cached.mtimeMs !== stat.mtimeMs || cached.size !== stat.size) {
562
+ const parsed = parseClaudeJsonlSession({
563
+ text: readFileSync(filePath, "utf8"),
564
+ cwd: this.input.cwd,
565
+ sessionId,
566
+ fallbackUpdatedAt: stat.mtimeMs,
567
+ });
568
+ const thread = parsed.thread && typeof parsed.thread === "object"
569
+ ? parsed.thread as Record<string, unknown>
570
+ : {};
571
+ const item: Record<string, unknown> = {
572
+ id: sessionId,
573
+ cwd: stringField(thread, ["cwd", "workingDirectory", "workspacePath"]) ?? this.input.cwd,
574
+ title: stringField(thread, ["title", "preview"]),
575
+ model: stringField(thread, ["model"]),
576
+ createdAt: thread.createdAt,
577
+ lastActivityAt: thread.updatedAt ?? stat.mtimeMs,
578
+ lastModified: stat.mtimeMs,
579
+ };
580
+ cached = { mtimeMs: stat.mtimeMs, size: stat.size, entry: item };
581
+ this.sessionMetaCache.set(filePath, cached);
582
+ }
583
+ sessions.push(cached.entry);
567
584
  }
568
585
  } catch {
569
586
  // directory read failed
570
587
  }
571
588
  }
589
+ // Prune cache entries for transcripts that no longer exist.
590
+ if (this.sessionMetaCache.size > liveKeys.size) {
591
+ for (const key of this.sessionMetaCache.keys()) {
592
+ if (!liveKeys.has(key)) this.sessionMetaCache.delete(key);
593
+ }
594
+ }
572
595
 
573
596
  return { sessions };
574
597
  }
@@ -2027,6 +2027,42 @@ export class BridgeSession {
2027
2027
  }));
2028
2028
  }
2029
2029
 
2030
+ /** Determine which provider a session id belongs to by which on-disk store
2031
+ * holds its transcript — Claude writes ~/.claude/projects/<proj>/<id>.jsonl,
2032
+ * Codex writes ~/.codex/sessions/**​/rollout-*-<id>.jsonl. Deterministic and
2033
+ * needed because an external session's provider is NOT the spawned PTY's
2034
+ * provider. best-effort; returns undefined if not found (caller falls back).
2035
+ * Only hit on a permission request (human-in-loop, rare), so the directory
2036
+ * scan cost is fine. */
2037
+ private providerForExternalSession(sessionId: string): "claude" | "codex" | undefined {
2038
+ try {
2039
+ const claudeRoot = join(homedir(), ".claude", "projects");
2040
+ if (existsSync(claudeRoot)) {
2041
+ for (const proj of readdirSync(claudeRoot)) {
2042
+ if (existsSync(join(claudeRoot, proj, `${sessionId}.jsonl`))) return "claude";
2043
+ }
2044
+ }
2045
+ } catch { /* ignore */ }
2046
+ try {
2047
+ const codexRoot = join(homedir(), ".codex", "sessions");
2048
+ if (existsSync(codexRoot)) {
2049
+ const suffix = `-${sessionId}.jsonl`;
2050
+ const walk = (dir: string): boolean => {
2051
+ for (const name of readdirSync(dir)) {
2052
+ const p = join(dir, name);
2053
+ let st;
2054
+ try { st = statSync(p); } catch { continue; }
2055
+ if (st.isDirectory()) { if (walk(p)) return true; }
2056
+ else if (name.startsWith("rollout-") && name.endsWith(suffix)) return true;
2057
+ }
2058
+ return false;
2059
+ };
2060
+ if (walk(codexRoot)) return "codex";
2061
+ }
2062
+ } catch { /* ignore */ }
2063
+ return undefined;
2064
+ }
2065
+
2030
2066
  private sendHookPermissionRequest(
2031
2067
  terminalId: string,
2032
2068
  event: Record<string, unknown>,
@@ -2064,7 +2100,14 @@ export class BridgeSession {
2064
2100
  // resolvePendingPermission check in the agent.v2.permission.respond path).
2065
2101
  const sessionId = (event.session_id ?? event.sessionId) as string | undefined;
2066
2102
  if (sessionId) {
2067
- const agentProvider = provider === "codex" ? "codex" : provider === "claude" ? "claude" : "custom";
2103
+ // Derive the provider from the SESSION, not the spawned PTY's provider.
2104
+ // The same curl hook is written to both ~/.claude and ~/.codex, and the
2105
+ // HTTP server is created with a single provider — so an external Codex
2106
+ // session's request could arrive on a "claude" server and get the wrong
2107
+ // conversationId prefix, landing the card on a phantom conversation.
2108
+ // Look up which store the id lives in (deterministic; verified).
2109
+ const agentProvider = this.providerForExternalSession(sessionId)
2110
+ ?? (provider === "codex" ? "codex" : provider === "claude" ? "claude" : "custom");
2068
2111
  const conversationId = makeAgentV2RemoteConversationId(agentProvider, sessionId);
2069
2112
  const permission = { requestId, toolName, toolInput, context, options };
2070
2113
  // The web store only renders a clickable allow/deny card when the request
@@ -0,0 +1,33 @@
1
+ @import"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono: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;-moz-user-select:none;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) *::-moz-selection{color:transparent}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;-moz-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{-webkit-text-decoration:double underline;text-decoration:double underline}.xterm-underline-3{-webkit-text-decoration:wavy underline;text-decoration:wavy underline}.xterm-underline-4{-webkit-text-decoration:dotted underline;text-decoration:dotted underline}.xterm-underline-5{-webkit-text-decoration:dashed underline;text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{-webkit-text-decoration:overline double underline;text-decoration:overline double underline}.xterm-overline.xterm-underline-3{-webkit-text-decoration:overline wavy underline;text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{-webkit-text-decoration:overline dotted underline;text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{-webkit-text-decoration:overline dashed underline;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}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com
33
+ */*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,system-ui,-apple-system,Segoe UI,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root,[data-theme=dark]{color-scheme:dark;--c-canvas: 11 13 15;--c-surface: 22 24 28;--c-surface-raised: 28 31 36;--c-surface-overlay: 35 38 44;--c-border: 42 46 53;--c-border-strong: 56 62 70;--c-content-primary: 233 235 238;--c-content-secondary: 158 165 173;--c-content-muted: 112 118 126;--c-content-faint: 78 83 90;--c-brand: 59 107 97;--c-brand-light: 78 138 126;--c-brand-dark: 42 79 71;--c-accent: 45 212 191;--c-accent-dim: 31 148 136;--c-diff-add: 31 61 43;--c-diff-add-text: 95 211 138;--c-diff-remove: 61 31 36;--c-diff-remove-text: 240 112 127;--c-success: 16 185 129;--c-warning: 245 158 11;--c-danger: 239 68 68;--glass-bg: 18 20 23;--body-wash-1: rgba(45, 212, 191, .05);--body-wash-2: rgba(59, 107, 97, .04)}[data-theme=light]{color-scheme:light;--c-canvas: 255 255 255;--c-surface: 255 255 255;--c-surface-raised: 248 248 247;--c-surface-overlay: 241 241 239;--c-border: 229 229 226;--c-border-strong: 212 212 208;--c-content-primary: 33 33 33;--c-content-secondary: 90 90 88;--c-content-muted: 130 130 126;--c-content-faint: 168 168 163;--c-brand: 47 92 83;--c-brand-light: 62 120 109;--c-brand-dark: 36 70 63;--c-accent: 17 122 110;--c-accent-dim: 15 105 95;--c-diff-add: 230 246 235;--c-diff-add-text: 30 120 78;--c-diff-remove: 252 230 232;--c-diff-remove-text: 188 50 64;--c-success: 22 128 84;--c-warning: 176 110 20;--c-danger: 196 48 48;--glass-bg: 255 255 255;--body-wash-1: transparent;--body-wash-2: transparent}html,body,#root{height:100%}body{--tw-bg-opacity: 1;background-color:rgb(var(--c-canvas) / var(--tw-bg-opacity, 1));font-family:Inter,system-ui,-apple-system,Segoe UI,sans-serif;--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-image:radial-gradient(120% 80% at 50% -10%,var(--body-wash-1),transparent 60%),radial-gradient(100% 60% at 100% 100%,var(--body-wash-2),transparent 55%);background-attachment:fixed}::-moz-selection{background:rgb(var(--c-accent) / .25)}::selection{background:rgb(var(--c-accent) / .25)}*{scrollbar-width:thin;scrollbar-color:rgb(var(--c-border-strong)) transparent}*::-webkit-scrollbar{width:8px;height:8px}*::-webkit-scrollbar-thumb{background:rgb(var(--c-border-strong));border-radius:9999px;border:2px solid transparent;background-clip:content-box}*::-webkit-scrollbar-thumb:hover{background:rgb(var(--c-content-faint));background-clip:content-box}*::-webkit-scrollbar-track{background:transparent}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.codex-card{border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface) / var(--tw-bg-opacity, 1));box-shadow:0 1px rgb(var(--c-content-primary) / .03) inset,0 1px 2px #0000002e}.codex-card-raised{border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-raised) / var(--tw-bg-opacity, 1));box-shadow:0 1px rgb(var(--c-content-primary) / .04) inset,0 8px 28px -8px #00000047}.glass-bar{background:rgb(var(--glass-bg) / .6);backdrop-filter:saturate(140%) blur(12px);-webkit-backdrop-filter:saturate(140%) blur(12px)}.codex-input{width:100%;border-radius:.75rem;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-raised) / var(--tw-bg-opacity, 1));padding:.625rem .875rem;font-size:.875rem;line-height:1.25rem;--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.codex-input::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(var(--c-content-muted) / var(--tw-placeholder-opacity, 1))}.codex-input::placeholder{--tw-placeholder-opacity: 1;color:rgb(var(--c-content-muted) / var(--tw-placeholder-opacity, 1))}.codex-input{outline:2px solid transparent;outline-offset:2px;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.codex-input:focus{--tw-border-opacity: 1;border-color:rgb(var(--c-accent-dim) / var(--tw-border-opacity, 1));--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-color: rgb(var(--c-accent) / .2)}.codex-btn-primary{display:inline-flex;height:2.25rem;cursor:pointer;align-items:center;justify-content:center;gap:.375rem;border-radius:.5rem;padding-left:.875rem;padding-right:.875rem;font-size:.875rem;line-height:1.25rem;font-weight:500;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.codex-btn-primary:focus-visible{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-color: rgb(var(--c-accent) / .4)}.codex-btn-primary:disabled{pointer-events:none;opacity:.4}.codex-btn-primary{--tw-bg-opacity: 1;background-color:rgb(var(--c-accent-dim) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.codex-btn-primary:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-accent) / var(--tw-bg-opacity, 1))}.codex-btn-primary{box-shadow:0 1px 2px #0000001f}.codex-btn-ghost{display:inline-flex;height:2.25rem;cursor:pointer;align-items:center;justify-content:center;gap:.375rem;border-radius:.5rem;padding-left:.875rem;padding-right:.875rem;font-size:.875rem;line-height:1.25rem;font-weight:500;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.codex-btn-ghost:focus-visible{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-color: rgb(var(--c-accent) / .4)}.codex-btn-ghost:disabled{pointer-events:none;opacity:.4}.codex-btn-ghost{--tw-text-opacity: 1;color:rgb(var(--c-content-secondary) / var(--tw-text-opacity, 1))}.codex-btn-ghost:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.codex-btn-outline{display:inline-flex;height:2.25rem;cursor:pointer;align-items:center;justify-content:center;gap:.375rem;border-radius:.5rem;padding-left:.875rem;padding-right:.875rem;font-size:.875rem;line-height:1.25rem;font-weight:500;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.codex-btn-outline:focus-visible{outline:2px solid transparent;outline-offset:2px;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000);--tw-ring-color: rgb(var(--c-accent) / .4)}.codex-btn-outline:disabled{pointer-events:none;opacity:.4}.codex-btn-outline{border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--c-content-secondary) / var(--tw-text-opacity, 1))}.codex-btn-outline:hover{--tw-border-opacity: 1;border-color:rgb(var(--c-border-strong) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.tree-row{display:flex;width:100%;cursor:pointer;align-items:center;gap:.625rem;border-radius:.5rem;padding:.5rem .75rem;text-align:left;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.tree-row:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1))}.tree-row-active{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.codex-chip{display:inline-flex;align-items:center;gap:.25rem;border-radius:9999px;border-width:1px;--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1));--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-raised) / var(--tw-bg-opacity, 1));padding:.125rem .5rem;font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.6875rem;line-height:1rem;--tw-text-opacity: 1;color:rgb(var(--c-content-secondary) / var(--tw-text-opacity, 1))}.xterm-host,.xterm-host .xterm,.xterm-host .xterm-viewport{height:100%;width:100%}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-y-0{top:0;bottom:0}.-right-1\.5{right:-.375rem}.-top-1\.5{top:-.375rem}.bottom-4{bottom:1rem}.bottom-full{bottom:100%}.left-0{left:0}.right-0{right:0}.right-1\.5{right:.375rem}.right-2{right:.5rem}.right-4{right:1rem}.top-0{top:0}.top-1\.5{top:.375rem}.top-2{top:.5rem}.top-9{top:2.25rem}.top-full{top:100%}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[60\]{z-index:60}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.-mt-1{margin-top:-.25rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-2\.5{margin-top:.625rem}.mt-3{margin-top:.75rem}.line-clamp-1{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-\[100dvh\]{height:100dvh}.h-full{height:100%}.h-px{height:1px}.max-h-32{max-height:8rem}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.max-h-60{max-height:15rem}.max-h-72{max-height:18rem}.max-h-\[50vh\]{max-height:50vh}.max-h-\[80vh\]{max-height:80vh}.min-h-0{min-height:0px}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-2\.5{width:.625rem}.w-28{width:7rem}.w-3{width:.75rem}.w-36{width:9rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-80{width:20rem}.w-9{width:2.25rem}.w-\[390px\]{width:390px}.w-\[82\%\]{width:82%}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[13rem\]{min-width:13rem}.min-w-\[8rem\]{min-width:8rem}.max-w-3xl{max-width:48rem}.max-w-5xl{max-width:64rem}.max-w-\[200px\]{max-width:200px}.max-w-\[46rem\]{max-width:46rem}.max-w-\[7rem\]{max-width:7rem}.max-w-\[85\%\]{max-width:85%}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.basis-full{flex-basis:100%}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes drawer-in{0%{transform:translate(-100%)}to{transform:translate(0)}}.animate-drawer-in{animation:drawer-in .24s cubic-bezier(.16,1,.3,1)}@keyframes fade-in{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.animate-fade-in{animation:fade-in .2s ease-out}@keyframes panel-in-right{0%{opacity:0;transform:translate(30px)}to{opacity:1;transform:translate(0)}}.animate-panel-in-right{animation:panel-in-right .22s cubic-bezier(.16,1,.3,1) both}@keyframes panel-in-up{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}.animate-panel-in-up{animation:panel-in-up .24s cubic-bezier(.16,1,.3,1) both}@keyframes panel-out-down{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(100%)}}.animate-panel-out-down{animation:panel-out-down .24s cubic-bezier(.16,1,.3,1) both}@keyframes panel-out-right{0%{opacity:1;transform:translate(0)}to{opacity:0;transform:translate(30px)}}.animate-panel-out-right{animation:panel-out-right .22s cubic-bezier(.16,1,.3,1) both}@keyframes pulse-dot{0%,to{opacity:.4}50%{opacity:1}}.animate-pulse-dot{animation:pulse-dot 1.2s ease-in-out infinite}@keyframes slide-in{0%{opacity:0;transform:translate(8px)}to{opacity:1;transform:translate(0)}}.animate-slide-in{animation:slide-in .22s cubic-bezier(.16,1,.3,1)}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-col-resize{cursor:col-resize}.cursor-crosshair{cursor:crosshair}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.cursor-row-resize{cursor:row-resize}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize{resize:both}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-y-1\.5{row-gap:.375rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.divide-x>:not([hidden])~:not([hidden]){--tw-divide-x-reverse: 0;border-right-width:calc(1px * var(--tw-divide-x-reverse));border-left-width:calc(1px * calc(1 - var(--tw-divide-x-reverse)))}.divide-border>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-divide-opacity, 1))}.self-start{align-self:flex-start}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[3px\]{border-radius:3px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-x{border-left-width:1px;border-right-width:1px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-accent{--tw-border-opacity: 1;border-color:rgb(var(--c-accent) / var(--tw-border-opacity, 1))}.border-accent-dim\/40{border-color:rgb(var(--c-accent-dim) / .4)}.border-accent\/30{border-color:rgb(var(--c-accent) / .3)}.border-border{--tw-border-opacity: 1;border-color:rgb(var(--c-border) / var(--tw-border-opacity, 1))}.border-border-strong{--tw-border-opacity: 1;border-color:rgb(var(--c-border-strong) / var(--tw-border-opacity, 1))}.border-content-faint{--tw-border-opacity: 1;border-color:rgb(var(--c-content-faint) / var(--tw-border-opacity, 1))}.border-danger\/30{border-color:rgb(var(--c-danger) / .3)}.border-danger\/40{border-color:rgb(var(--c-danger) / .4)}.border-success\/30{border-color:rgb(var(--c-success) / .3)}.border-warning\/40{border-color:rgb(var(--c-warning) / .4)}.border-t-accent{--tw-border-opacity: 1;border-top-color:rgb(var(--c-accent) / var(--tw-border-opacity, 1))}.bg-accent{--tw-bg-opacity: 1;background-color:rgb(var(--c-accent) / var(--tw-bg-opacity, 1))}.bg-accent-dim{--tw-bg-opacity: 1;background-color:rgb(var(--c-accent-dim) / var(--tw-bg-opacity, 1))}.bg-accent\/10{background-color:rgb(var(--c-accent) / .1)}.bg-black\/60{background-color:#0009}.bg-border{--tw-bg-opacity: 1;background-color:rgb(var(--c-border) / var(--tw-bg-opacity, 1))}.bg-canvas{--tw-bg-opacity: 1;background-color:rgb(var(--c-canvas) / var(--tw-bg-opacity, 1))}.bg-canvas\/60{background-color:rgb(var(--c-canvas) / .6)}.bg-canvas\/80{background-color:rgb(var(--c-canvas) / .8)}.bg-canvas\/95{background-color:rgb(var(--c-canvas) / .95)}.bg-content-faint{--tw-bg-opacity: 1;background-color:rgb(var(--c-content-faint) / var(--tw-bg-opacity, 1))}.bg-current{background-color:currentColor}.bg-danger{--tw-bg-opacity: 1;background-color:rgb(var(--c-danger) / var(--tw-bg-opacity, 1))}.bg-danger\/10{background-color:rgb(var(--c-danger) / .1)}.bg-diff-add{--tw-bg-opacity: 1;background-color:rgb(var(--c-diff-add) / var(--tw-bg-opacity, 1))}.bg-diff-remove{--tw-bg-opacity: 1;background-color:rgb(var(--c-diff-remove) / var(--tw-bg-opacity, 1))}.bg-success{--tw-bg-opacity: 1;background-color:rgb(var(--c-success) / var(--tw-bg-opacity, 1))}.bg-success\/10{background-color:rgb(var(--c-success) / .1)}.bg-surface{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface) / var(--tw-bg-opacity, 1))}.bg-surface-overlay{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1))}.bg-surface-raised{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-raised) / var(--tw-bg-opacity, 1))}.bg-surface-raised\/60{background-color:rgb(var(--c-surface-raised) / .6)}.bg-transparent{background-color:transparent}.bg-warning{--tw-bg-opacity: 1;background-color:rgb(var(--c-warning) / var(--tw-bg-opacity, 1))}.bg-warning\/10{background-color:rgb(var(--c-warning) / .1)}.bg-warning\/15{background-color:rgb(var(--c-warning) / .15)}.bg-warning\/30{background-color:rgb(var(--c-warning) / .3)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-3\.5{padding:.875rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.px-0{padding-left:0;padding-right:0}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-20{padding-top:5rem;padding-bottom:5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pl-1{padding-left:.25rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pl-7{padding-left:1.75rem}.pr-1{padding-right:.25rem}.pr-3{padding-right:.75rem}.pr-9{padding-right:2.25rem}.pt-1\.5{padding-top:.375rem}.pt-2{padding-top:.5rem}.pt-2\.5{padding-top:.625rem}.pt-\[12vh\]{padding-top:12vh}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.text-2xs{font-size:.6875rem;line-height:1rem}.text-\[10px\]{font-size:10px}.text-\[13px\]{font-size:13px}.text-\[15px\]{font-size:15px}.text-base{font-size:1rem;line-height:1.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-6{line-height:1.5rem}.leading-7{line-height:1.75rem}.leading-\[1\.6\]{line-height:1.6}.leading-relaxed{line-height:1.625}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-accent{--tw-text-opacity: 1;color:rgb(var(--c-accent) / var(--tw-text-opacity, 1))}.text-accent-dim{--tw-text-opacity: 1;color:rgb(var(--c-accent-dim) / var(--tw-text-opacity, 1))}.text-content-faint{--tw-text-opacity: 1;color:rgb(var(--c-content-faint) / var(--tw-text-opacity, 1))}.text-content-muted{--tw-text-opacity: 1;color:rgb(var(--c-content-muted) / var(--tw-text-opacity, 1))}.text-content-primary{--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.text-content-secondary{--tw-text-opacity: 1;color:rgb(var(--c-content-secondary) / var(--tw-text-opacity, 1))}.text-danger{--tw-text-opacity: 1;color:rgb(var(--c-danger) / var(--tw-text-opacity, 1))}.text-diff-addText{--tw-text-opacity: 1;color:rgb(var(--c-diff-add-text) / var(--tw-text-opacity, 1))}.text-diff-removeText{--tw-text-opacity: 1;color:rgb(var(--c-diff-remove-text) / var(--tw-text-opacity, 1))}.text-success{--tw-text-opacity: 1;color:rgb(var(--c-success) / var(--tw-text-opacity, 1))}.text-warning{--tw-text-opacity: 1;color:rgb(var(--c-warning) / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.underline-offset-2{text-underline-offset:2px}.placeholder-content-muted::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(var(--c-content-muted) / var(--tw-placeholder-opacity, 1))}.placeholder-content-muted::placeholder{--tw-placeholder-opacity: 1;color:rgb(var(--c-content-muted) / var(--tw-placeholder-opacity, 1))}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-150{transition-duration:.15s}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}@media(hover:none)and (pointer:coarse){[class*="group-hover:opacity-100"]{opacity:1!important}}.focus-within\:border-border-strong:focus-within{--tw-border-opacity: 1;border-color:rgb(var(--c-border-strong) / var(--tw-border-opacity, 1))}.hover\:border-border-strong:hover{--tw-border-opacity: 1;border-color:rgb(var(--c-border-strong) / var(--tw-border-opacity, 1))}.hover\:border-danger:hover{--tw-border-opacity: 1;border-color:rgb(var(--c-danger) / var(--tw-border-opacity, 1))}.hover\:bg-accent:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-accent) / var(--tw-bg-opacity, 1))}.hover\:bg-accent-dim\/50:hover{background-color:rgb(var(--c-accent-dim) / .5)}.hover\:bg-danger\/10:hover{background-color:rgb(var(--c-danger) / .1)}.hover\:bg-surface-overlay:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1))}.hover\:bg-surface-overlay\/60:hover{background-color:rgb(var(--c-surface-overlay) / .6)}.hover\:bg-surface-raised:hover{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-raised) / var(--tw-bg-opacity, 1))}.hover\:text-accent:hover{--tw-text-opacity: 1;color:rgb(var(--c-accent) / var(--tw-text-opacity, 1))}.hover\:text-content-primary:hover{--tw-text-opacity: 1;color:rgb(var(--c-content-primary) / var(--tw-text-opacity, 1))}.hover\:text-content-secondary:hover{--tw-text-opacity: 1;color:rgb(var(--c-content-secondary) / var(--tw-text-opacity, 1))}.hover\:text-danger:hover{--tw-text-opacity: 1;color:rgb(var(--c-danger) / var(--tw-text-opacity, 1))}.focus\:border-accent-dim:focus{--tw-border-opacity: 1;border-color:rgb(var(--c-accent-dim) / var(--tw-border-opacity, 1))}.disabled\:cursor-default:disabled{cursor:default}.disabled\:bg-surface-overlay:disabled{--tw-bg-opacity: 1;background-color:rgb(var(--c-surface-overlay) / var(--tw-bg-opacity, 1))}.disabled\:text-content-faint:disabled{--tw-text-opacity: 1;color:rgb(var(--c-content-faint) / var(--tw-text-opacity, 1))}.disabled\:opacity-40:disabled{opacity:.4}.group\/code:hover .group-hover\/code\:opacity-100,.group\/out:hover .group-hover\/out\:opacity-100,.group:hover .group-hover\:opacity-100{opacity:1}@media(min-width:640px){.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.sm\:gap-3{gap:.75rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}}@media(min-width:768px){.md\:text-\[15px\]{font-size:15px}}