diffprism 0.39.0 → 0.41.0

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/dist/bin.js CHANGED
@@ -11,14 +11,14 @@ import {
11
11
  } from "./chunk-6J6PSBL2.js";
12
12
  import {
13
13
  demo
14
- } from "./chunk-UYZ3A2PB.js";
14
+ } from "./chunk-HEJVY4S7.js";
15
15
  import {
16
16
  ensureServer,
17
17
  isServerAlive,
18
18
  readServerFile,
19
19
  startGlobalServer,
20
20
  submitReviewToServer
21
- } from "./chunk-ITPHDFOS.js";
21
+ } from "./chunk-7UMTB6LW.js";
22
22
  import "./chunk-QGWYCEJN.js";
23
23
  import "./chunk-DHCVZGHE.js";
24
24
  import "./chunk-JSBRDJBE.js";
@@ -89,7 +89,7 @@ async function reviewPrFlow(pr, flags) {
89
89
  diffRef: `PR #${number}`
90
90
  });
91
91
  console.log(JSON.stringify(result, null, 2));
92
- if (flags.postToGithub || result.decision !== "dismissed" && await promptPostToGithub()) {
92
+ if (result && (flags.postToGithub || result.decision !== "dismissed" && await promptPostToGithub())) {
93
93
  console.log("Posting review to GitHub...");
94
94
  const posted = await submitGitHubReview(client, owner, repo, number, result);
95
95
  if (posted) {
@@ -379,7 +379,7 @@ async function setupInteractive(flags) {
379
379
  }
380
380
  async function runDemo(dev) {
381
381
  console.log("");
382
- const { demo: demo2 } = await import("./demo-JH5YOKTZ.js");
382
+ const { demo: demo2 } = await import("./demo-UIN5MTWR.js");
383
383
  await demo2({ dev });
384
384
  }
385
385
  async function setupBatch(flags) {
@@ -806,9 +806,64 @@ async function serverStop() {
806
806
  }
807
807
  }
808
808
 
809
+ // cli/src/commands/default.ts
810
+ import open from "open";
811
+ function formatUptime(seconds) {
812
+ if (seconds < 60) return `${Math.floor(seconds)}s`;
813
+ if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${Math.floor(seconds % 60)}s`;
814
+ const hours = Math.floor(seconds / 3600);
815
+ const mins = Math.floor(seconds % 3600 / 60);
816
+ return `${hours}h ${mins}m`;
817
+ }
818
+ async function fetchStatus(httpPort) {
819
+ const response = await fetch(`http://localhost:${httpPort}/api/status`, {
820
+ signal: AbortSignal.timeout(2e3)
821
+ });
822
+ return await response.json();
823
+ }
824
+ function printStatus(status, httpPort) {
825
+ const version = true ? "0.41.0" : "0.0.0-dev";
826
+ console.log(`
827
+ DiffPrism v${version}
828
+ `);
829
+ console.log(` Server: running (PID ${status.pid}, uptime ${formatUptime(status.uptime)})`);
830
+ if (status.uiUrl) {
831
+ console.log(` Dashboard: ${status.uiUrl.split("?")[0]}`);
832
+ } else {
833
+ console.log(` API: http://localhost:${httpPort}`);
834
+ }
835
+ console.log(` Sessions: ${status.sessions} active`);
836
+ console.log();
837
+ console.log(` Quick start:`);
838
+ console.log(` diffprism review Review local changes`);
839
+ console.log(` diffprism review --staged Review staged changes`);
840
+ console.log(` diffprism setup Set up Claude Code integration`);
841
+ console.log(` diffprism --help Show all commands`);
842
+ console.log();
843
+ }
844
+ async function defaultAction() {
845
+ let info = await isServerAlive();
846
+ if (!info) {
847
+ console.log("Starting DiffPrism...");
848
+ info = await ensureServer();
849
+ }
850
+ try {
851
+ const status = await fetchStatus(info.httpPort);
852
+ printStatus(status, info.httpPort);
853
+ if (status.uiUrl) {
854
+ await open(status.uiUrl);
855
+ }
856
+ } catch (err) {
857
+ const message = err instanceof Error ? err.message : String(err);
858
+ console.error(`Error fetching server status: ${message}`);
859
+ process.exit(1);
860
+ }
861
+ }
862
+
809
863
  // cli/src/index.ts
810
864
  var program = new Command();
811
- program.name("diffprism").description("Local-first code review tool for agent-generated changes").version(true ? "0.39.0" : "0.0.0-dev");
865
+ program.name("diffprism").description("Local-first code review tool for agent-generated changes").version(true ? "0.41.0" : "0.0.0-dev");
866
+ program.action(defaultAction);
812
867
  program.command("demo").description("Open a sample review to see DiffPrism in action").option("--dev", "Use Vite dev server").action(demo);
813
868
  program.command("review [ref]").description("Open a browser-based diff review (local git ref or GitHub PR ref like owner/repo#123)").option("--staged", "Review staged changes").option("--unstaged", "Review unstaged changes").option("-t, --title <title>", "Review title").option("--reasoning <text>", "Agent reasoning about the changes").option("--dev", "Use Vite dev server with HMR instead of static files").option("--post-to-github", "Automatically post review back to GitHub without prompting").action(review);
814
869
  program.command("review-pr <pr>", { hidden: true }).action((pr, flags) => review(pr, flags));
@@ -230,8 +230,11 @@ async function submitReviewToServer(serverInfo, diffRef, options = {}) {
230
230
  );
231
231
  }
232
232
  }
233
- const pollIntervalMs = 2e3;
234
233
  const maxWaitMs = options.timeoutMs ?? 6e5;
234
+ if (maxWaitMs <= 0) {
235
+ return { result: null, sessionId };
236
+ }
237
+ const pollIntervalMs = 2e3;
235
238
  const start = Date.now();
236
239
  while (Date.now() - start < maxWaitMs) {
237
240
  const resultResponse = await fetch(
@@ -479,6 +482,7 @@ var clientSessions = /* @__PURE__ */ new Map();
479
482
  var sessionWatchers = /* @__PURE__ */ new Map();
480
483
  var serverPollInterval = 2e3;
481
484
  var reopenBrowserIfNeeded = null;
485
+ var serverUiUrl = null;
482
486
  function toSummary(session) {
483
487
  const { payload } = session;
484
488
  const fileCount = payload.diffSet.files.length;
@@ -493,6 +497,7 @@ function toSummary(session) {
493
497
  projectPath: session.projectPath,
494
498
  branch: payload.metadata.currentBranch,
495
499
  title: payload.metadata.title,
500
+ reasoning: payload.metadata.reasoning,
496
501
  fileCount,
497
502
  additions,
498
503
  deletions,
@@ -680,7 +685,8 @@ async function handleApiRequest(req, res) {
680
685
  running: true,
681
686
  pid: process.pid,
682
687
  sessions: sessions.size,
683
- uptime: process.uptime()
688
+ uptime: process.uptime(),
689
+ uiUrl: serverUiUrl
684
690
  });
685
691
  return true;
686
692
  }
@@ -1239,6 +1245,7 @@ Waiting for reviews...
1239
1245
  `);
1240
1246
  }
1241
1247
  const uiUrl = `http://localhost:${uiPort}?wsPort=${wsPort}&httpPort=${httpPort}&serverMode=true`;
1248
+ serverUiUrl = uiUrl;
1242
1249
  if (openBrowser) {
1243
1250
  await open(uiUrl);
1244
1251
  }
@@ -1260,6 +1267,7 @@ Waiting for reviews...
1260
1267
  clientSessions.clear();
1261
1268
  sessions.clear();
1262
1269
  reopenBrowserIfNeeded = null;
1270
+ serverUiUrl = null;
1263
1271
  await new Promise((resolve) => {
1264
1272
  httpServer.close(() => resolve());
1265
1273
  });
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ensureServer,
3
3
  submitReviewToServer
4
- } from "./chunk-ITPHDFOS.js";
4
+ } from "./chunk-7UMTB6LW.js";
5
5
  import {
6
6
  parseDiff
7
7
  } from "./chunk-QGWYCEJN.js";
@@ -210,10 +210,14 @@ async function demo(flags) {
210
210
  projectPath: "demo",
211
211
  diffRef: "demo"
212
212
  });
213
- console.log(`
213
+ if (result) {
214
+ console.log(`
214
215
  Review submitted: ${result.decision}`);
215
- if (result.comments.length > 0) {
216
- console.log(`${result.comments.length} comment(s)`);
216
+ if (result.comments.length > 0) {
217
+ console.log(`${result.comments.length} comment(s)`);
218
+ }
219
+ } else {
220
+ console.log("\nReview opened in browser.");
217
221
  }
218
222
  console.log("\nNext steps:");
219
223
  console.log(" Run `npx diffprism setup` to configure for Claude Code");
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  demo
3
- } from "./chunk-UYZ3A2PB.js";
4
- import "./chunk-ITPHDFOS.js";
3
+ } from "./chunk-HEJVY4S7.js";
4
+ import "./chunk-7UMTB6LW.js";
5
5
  import "./chunk-QGWYCEJN.js";
6
6
  import "./chunk-DHCVZGHE.js";
7
7
  import "./chunk-JSBRDJBE.js";
@@ -12,7 +12,7 @@ import {
12
12
  ensureServer,
13
13
  isServerAlive,
14
14
  submitReviewToServer
15
- } from "./chunk-ITPHDFOS.js";
15
+ } from "./chunk-7UMTB6LW.js";
16
16
  import {
17
17
  getDiff
18
18
  } from "./chunk-QGWYCEJN.js";
@@ -38,12 +38,29 @@ async function handleLocalReview(diffRef, options) {
38
38
  reasoning: options.reasoning,
39
39
  cwd: process.cwd(),
40
40
  annotations: options.annotations,
41
- diffRef
41
+ diffRef,
42
+ timeoutMs: options.timeoutMs ?? 0
42
43
  }
43
44
  );
45
+ if (result) {
46
+ return {
47
+ mcpResult: {
48
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
49
+ },
50
+ sessionId,
51
+ serverInfo
52
+ };
53
+ }
44
54
  return {
45
55
  mcpResult: {
46
- content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
56
+ content: [{
57
+ type: "text",
58
+ text: JSON.stringify({
59
+ status: "session_created",
60
+ sessionId,
61
+ message: "Review session opened in DiffPrism dashboard. Use get_review_result to check for a decision."
62
+ }, null, 2)
63
+ }]
47
64
  },
48
65
  sessionId,
49
66
  serverInfo
@@ -84,9 +101,27 @@ async function handlePrReview(pr, options) {
84
101
  {
85
102
  injectedPayload: payload,
86
103
  projectPath: `github:${owner}/${repo}`,
87
- diffRef: `PR #${number}`
104
+ diffRef: `PR #${number}`,
105
+ timeoutMs: options.timeoutMs ?? 0
88
106
  }
89
107
  );
108
+ if (!result) {
109
+ return {
110
+ mcpResult: {
111
+ content: [{
112
+ type: "text",
113
+ text: JSON.stringify({
114
+ status: "session_created",
115
+ sessionId,
116
+ pr: `${owner}/${repo}#${number}`,
117
+ message: "Review session opened in DiffPrism dashboard. Use get_review_result to check for a decision."
118
+ }, null, 2)
119
+ }]
120
+ },
121
+ sessionId,
122
+ serverInfo
123
+ };
124
+ }
90
125
  if ((options.post_to_github || result.postToGithub) && result.decision !== "dismissed") {
91
126
  const posted = await submitGitHubReview(client, owner, repo, number, result);
92
127
  if (posted) {
@@ -117,19 +152,20 @@ async function handlePrReview(pr, options) {
117
152
  async function startMcpServer() {
118
153
  const server = new McpServer({
119
154
  name: "diffprism",
120
- version: true ? "0.39.0" : "0.0.0-dev"
155
+ version: true ? "0.41.0" : "0.0.0-dev"
121
156
  });
122
157
  server.tool(
123
158
  "open_review",
124
- "Open a browser-based code review for local git changes or a GitHub pull request. Blocks until the engineer submits their review decision. The result may include a `postReviewAction` field ('commit' or 'commit_and_pr') if the reviewer requested a post-review action.",
159
+ "Open a review session in the DiffPrism dashboard for local git changes or a GitHub pull request. Returns immediately with the session ID after registering the session. Use `get_review_result` with `wait: true` when you need the reviewer's decision before proceeding.",
125
160
  {
126
161
  diff_ref: z.string().describe(
127
162
  'Git diff reference: "staged", "unstaged", "working-copy" (staged+unstaged grouped), a ref range like "HEAD~3..HEAD", or a GitHub PR ref like "owner/repo#123" or a GitHub PR URL'
128
163
  ),
129
164
  title: z.string().optional().describe("Title for the review"),
130
165
  description: z.string().optional().describe("Description of the changes"),
131
- reasoning: z.string().optional().describe("Agent reasoning about why these changes were made"),
166
+ reasoning: z.string().optional().describe("Summarize what you were trying to accomplish in this session in plain English. This is displayed as the session subtitle in the DiffPrism dashboard and is the primary way users identify sessions at a glance. Always populate this."),
132
167
  post_to_github: z.boolean().optional().describe("Post the review back to GitHub after submission (only for PR refs, default: false)"),
168
+ timeout_ms: z.number().optional().describe("How long to wait for a review decision (ms). Defaults to 0 (non-blocking, returns immediately after session creation). Set to a positive value to poll for a result up to that duration before returning."),
133
169
  annotations: z.array(
134
170
  z.object({
135
171
  file: z.string().describe("File path within the diff to annotate"),
@@ -151,7 +187,7 @@ async function startMcpServer() {
151
187
  })
152
188
  ).optional().describe("Initial annotations to attach to the review")
153
189
  },
154
- async ({ diff_ref, title, description, reasoning, post_to_github, annotations }) => {
190
+ async ({ diff_ref, title, description, reasoning, post_to_github, timeout_ms, annotations }) => {
155
191
  try {
156
192
  let mcpResult;
157
193
  let sessionId;
@@ -160,14 +196,16 @@ async function startMcpServer() {
160
196
  ({ mcpResult, sessionId, serverInfo } = await handlePrReview(diff_ref, {
161
197
  title,
162
198
  reasoning,
163
- post_to_github
199
+ post_to_github,
200
+ timeoutMs: timeout_ms
164
201
  }));
165
202
  } else {
166
203
  ({ mcpResult, sessionId, serverInfo } = await handleLocalReview(diff_ref, {
167
204
  title,
168
205
  description,
169
206
  reasoning,
170
- annotations
207
+ annotations,
208
+ timeoutMs: timeout_ms
171
209
  }));
172
210
  }
173
211
  if (sessionId) {
@@ -249,7 +287,7 @@ async function startMcpServer() {
249
287
  );
250
288
  server.tool(
251
289
  "get_review_result",
252
- "Fetch the most recent review result from a DiffPrism session. Returns the reviewer's decision and comments if a review has been submitted, or a message indicating no pending result. Use wait=true to block until a result is available. Note: `open_review` already blocks and returns the result \u2014 this tool is only needed for advanced workflows where you want to check results separately.",
290
+ "Fetch the most recent review result from a DiffPrism session. Returns the reviewer's decision and comments if a review has been submitted, or a message indicating no pending result. Use wait=true to block until a result is available \u2014 this is the standard way to wait for a reviewer's decision after calling open_review.",
253
291
  {
254
292
  wait: z.boolean().optional().describe("If true, poll until a review result is available (blocks up to timeout)"),
255
293
  timeout: z.number().optional().describe("Max wait time in seconds when wait=true (default: 300, max: 600)")
@@ -705,43 +743,6 @@ async function startMcpServer() {
705
743
  }
706
744
  }
707
745
  );
708
- server.tool(
709
- "review_pr",
710
- "Alias for open_review with a GitHub PR ref. Prefer using open_review with a PR ref in diff_ref instead.",
711
- {
712
- pr: z.string().describe(
713
- 'GitHub PR reference: "owner/repo#123" or "https://github.com/owner/repo/pull/123"'
714
- ),
715
- title: z.string().optional().describe("Override review title"),
716
- reasoning: z.string().optional().describe("Agent reasoning about the PR changes"),
717
- post_to_github: z.boolean().optional().describe("Post the review back to GitHub after submission (default: false)")
718
- },
719
- async ({ pr, title, reasoning, post_to_github }) => {
720
- try {
721
- const { mcpResult, sessionId, serverInfo } = await handlePrReview(pr, {
722
- title,
723
- reasoning,
724
- post_to_github
725
- });
726
- if (sessionId) {
727
- lastGlobalSessionId = sessionId;
728
- lastGlobalServerInfo = serverInfo;
729
- }
730
- return mcpResult;
731
- } catch (err) {
732
- const message = err instanceof Error ? err.message : String(err);
733
- return {
734
- content: [
735
- {
736
- type: "text",
737
- text: `Error: ${message}`
738
- }
739
- ],
740
- isError: true
741
- };
742
- }
743
- }
744
- );
745
746
  const transport = new StdioServerTransport();
746
747
  await server.connect(transport);
747
748
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "diffprism",
3
- "version": "0.39.0",
3
+ "version": "0.41.0",
4
4
  "type": "module",
5
5
  "description": "Local-first code review tool for agent-generated code changes",
6
6
  "bin": {
@@ -0,0 +1 @@
1
+ :root{--diff-background-color:initial;--diff-text-color:initial;--diff-font-family:Consolas,Courier,monospace;--diff-selection-background-color:#b3d7ff;--diff-selection-text-color:var(--diff-text-color);--diff-gutter-insert-background-color:#d6fedb;--diff-gutter-insert-text-color:var(--diff-text-color);--diff-gutter-delete-background-color:#fadde0;--diff-gutter-delete-text-color:var(--diff-text-color);--diff-gutter-selected-background-color:#fffce0;--diff-gutter-selected-text-color:var(--diff-text-color);--diff-code-insert-background-color:#eaffee;--diff-code-insert-text-color:var(--diff-text-color);--diff-code-delete-background-color:#fdeff0;--diff-code-delete-text-color:var(--diff-text-color);--diff-code-insert-edit-background-color:#c0dc91;--diff-code-insert-edit-text-color:var(--diff-text-color);--diff-code-delete-edit-background-color:#f39ea2;--diff-code-delete-edit-text-color:var(--diff-text-color);--diff-code-selected-background-color:#fffce0;--diff-code-selected-text-color:var(--diff-text-color);--diff-omit-gutter-line-color:#cb2a1d}.diff{background-color:var(--diff-background-color);border-collapse:collapse;color:var(--diff-text-color);table-layout:fixed;width:100%}.diff::-moz-selection{background-color:#b3d7ff;background-color:var(--diff-selection-background-color);color:var(--diff-text-color);color:var(--diff-selection-text-color)}.diff::selection{background-color:#b3d7ff;background-color:var(--diff-selection-background-color);color:var(--diff-text-color);color:var(--diff-selection-text-color)}.diff td{padding-bottom:0;padding-top:0;vertical-align:top}.diff-line{font-family:Consolas,Courier,monospace;font-family:var(--diff-font-family);line-height:1.5}.diff-gutter>a{color:inherit;display:block}.diff-gutter{cursor:pointer;padding:0 1ch;text-align:right;-webkit-user-select:none;-moz-user-select:none;user-select:none}.diff-gutter-insert{background-color:#d6fedb;background-color:var(--diff-gutter-insert-background-color);color:var(--diff-text-color);color:var(--diff-gutter-insert-text-color)}.diff-gutter-delete{background-color:#fadde0;background-color:var(--diff-gutter-delete-background-color);color:var(--diff-text-color);color:var(--diff-gutter-delete-text-color)}.diff-gutter-omit{cursor:default}.diff-gutter-selected{background-color:#fffce0;background-color:var(--diff-gutter-selected-background-color);color:var(--diff-text-color);color:var(--diff-gutter-selected-text-color)}.diff-code{word-wrap:break-word;padding:0 0 0 .5em;white-space:pre-wrap;word-break:break-all}.diff-code-edit{color:inherit}.diff-code-insert{background-color:#eaffee;background-color:var(--diff-code-insert-background-color);color:var(--diff-text-color);color:var(--diff-code-insert-text-color)}.diff-code-insert .diff-code-edit{background-color:#c0dc91;background-color:var(--diff-code-insert-edit-background-color);color:var(--diff-text-color);color:var(--diff-code-insert-edit-text-color)}.diff-code-delete{background-color:#fdeff0;background-color:var(--diff-code-delete-background-color);color:var(--diff-text-color);color:var(--diff-code-delete-text-color)}.diff-code-delete .diff-code-edit{background-color:#f39ea2;background-color:var(--diff-code-delete-edit-background-color);color:var(--diff-text-color);color:var(--diff-code-delete-edit-text-color)}.diff-code-selected{background-color:#fffce0;background-color:var(--diff-code-selected-background-color);color:var(--diff-text-color);color:var(--diff-code-selected-text-color)}.diff-widget-content{vertical-align:top}.diff-gutter-col{width:7ch}.diff-gutter-omit{height:0}.diff-gutter-omit:before{background-color:#cb2a1d;background-color:var(--diff-omit-gutter-line-color);content:" ";display:block;height:100%;margin-left:4.6ch;overflow:hidden;white-space:pre;width:2px}.diff-decoration{line-height:1.5;-webkit-user-select:none;-moz-user-select:none;user-select:none}.diff-decoration-content{font-family:Consolas,Courier,monospace;font-family:var(--diff-font-family);padding:0}*,: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: }*,: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:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";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:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,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}.\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.right-0{right:0}.right-1\.5{right:.375rem}.right-2{right:.5rem}.top-1\.5{top:.375rem}.top-2{top:.5rem}.top-full{top:100%}.z-50{z-index:50}.col-span-2{grid-column:span 2 / span 2}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-0\.5{margin-bottom:.125rem}.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}.mb-5{margin-bottom:1.25rem}.mb-8{margin-bottom:2rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-1\.5{margin-right:.375rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.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-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-64{max-height:16rem}.max-h-\[80vh\]{max-height:80vh}.min-h-0{min-height:0px}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-52{width:13rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-80{width:20rem}.w-\[260px\]{width:260px}.w-\[280px\]{width:280px}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.max-w-\[180px\]{max-width:180px}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}@keyframes ping{75%,to{transform:scale(2);opacity:0}}.animate-ping{animation:ping 1s cubic-bezier(0,0,.2,1) infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.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-3{gap:.75rem}.gap-4{gap:1rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.gap-y-3{row-gap:.75rem}.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\.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-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))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-accent{border-color:var(--color-accent)}.border-border{border-color:var(--color-border)}.border-transparent{border-color:transparent}.border-l-accent{border-left-color:var(--color-accent)}.border-l-transparent{border-left-color:transparent}.border-l-warning{border-left-color:var(--color-warning)}.border-r-border{border-right-color:var(--color-border)}.border-t-accent{border-top-color:var(--color-accent)}.bg-accent{background-color:var(--color-accent)}.bg-background{background-color:var(--color-background)}.bg-black\/50{background-color:#00000080}.bg-border{background-color:var(--color-border)}.bg-info{background-color:var(--color-info)}.bg-success{background-color:var(--color-success)}.bg-surface{background-color:var(--color-surface)}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.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-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.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-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.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}.pb-3{padding-bottom:.75rem}.pl-6{padding-left:1.5rem}.pr-6{padding-right:1.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-lg{font-size:1.125rem;line-height:1.75rem}.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-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-accent{color:var(--color-accent)}.text-danger{color:var(--color-danger)}.text-info{color:var(--color-info)}.text-neutral{color:var(--color-neutral)}.text-perf{color:var(--color-perf)}.text-success{color:var(--color-success)}.text-text-primary{color:var(--color-text-primary)}.text-text-secondary{color:var(--color-text-secondary)}.text-warning{color:var(--color-warning)}.text-white{--tw-text-opacity:1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.accent-accent{accent-color:var(--color-accent)}.opacity-0{opacity:0}.opacity-40{opacity:.4}.opacity-75{opacity:.75}.shadow-lg{--tw-shadow:0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px 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)}.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)}.transition-all{transition-property:all;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}.duration-100{transition-duration:.1s}:root{--color-background: #e5e9f2;--color-surface: #d8dde9;--color-border: #b3bbd0;--color-text-primary: #141828;--color-text-secondary: #434e65;--color-accent: #4f3fba;--color-diff-bg: #e5e9f2;--color-diff-text: #141828;--color-gutter-bg: #d8dde9;--color-gutter-text: #434e65;--color-gutter-border: #b3bbd0;--color-diff-insert-bg: rgba(30, 160, 120, .15);--color-diff-insert-gutter-bg: rgba(30, 160, 120, .22);--color-diff-insert-gutter-text: #14704f;--color-diff-delete-bg: rgba(210, 75, 65, .15);--color-diff-delete-gutter-bg: rgba(210, 75, 65, .22);--color-diff-delete-gutter-text: #b02e26;--color-hunk-bg: rgba(90, 72, 201, .1);--color-hunk-border: #b3bbd0;--color-hunk-gutter-bg: rgba(79, 63, 186, .15);--color-hunk-gutter-text: #4f3fba;--color-hunk-content-text: #434e65;--color-diff-edit-insert: rgba(30, 160, 120, .42);--color-diff-edit-delete: rgba(210, 75, 65, .42);--color-split-divider: #b3bbd0;--color-widget-bg: #d8dde9;--color-comment-btn-bg: #167a5c;--color-comment-indicator: #4f3fba;--color-annotation-indicator: #c07820;--color-scrollbar-track: #e5e9f2;--color-scrollbar-thumb: #b3bbd0;--color-scrollbar-thumb-hover: #98a2b8;--color-token-comment: #6b7a8f;--color-token-punctuation: #1a1f2e;--color-token-property: #0b6e82;--color-token-string: #0e7a5c;--color-token-operator: #c93c33;--color-token-keyword: #6e45c9;--color-token-function: #2870c9;--color-token-variable: #b06e18;--color-success: #0e7a5c;--color-danger: #c93c33;--color-warning: #b06e18;--color-info: #2870c9;--color-neutral: #6b7a8f;--color-perf: #c07820;--color-added: rgba(30, 160, 120, .4);--color-deleted: rgba(210, 75, 65, .4)}.dark{--color-background: #0b0f1a;--color-surface: #131829;--color-border: #252d3f;--color-text-primary: #dfe5f1;--color-text-secondary: #7585a3;--color-accent: #7c6bf0;--color-diff-bg: #0b0f1a;--color-diff-text: #dfe5f1;--color-gutter-bg: #111623;--color-gutter-text: #7585a3;--color-gutter-border: #252d3f;--color-diff-insert-bg: rgba(45, 185, 140, .12);--color-diff-insert-gutter-bg: rgba(45, 185, 140, .18);--color-diff-insert-gutter-text: #5ee0b2;--color-diff-delete-bg: rgba(235, 100, 90, .12);--color-diff-delete-gutter-bg: rgba(235, 100, 90, .18);--color-diff-delete-gutter-text: #f07068;--color-hunk-bg: rgba(124, 107, 240, .08);--color-hunk-border: #252d3f;--color-hunk-gutter-bg: rgba(124, 107, 240, .12);--color-hunk-gutter-text: #9688f0;--color-hunk-content-text: #7585a3;--color-diff-edit-insert: rgba(45, 185, 140, .35);--color-diff-edit-delete: rgba(235, 100, 90, .35);--color-split-divider: #252d3f;--color-widget-bg: #131829;--color-comment-btn-bg: #2db98c;--color-comment-indicator: #7c6bf0;--color-annotation-indicator: #e0a050;--color-scrollbar-track: #0b0f1a;--color-scrollbar-thumb: #252d3f;--color-scrollbar-thumb-hover: #3a4560;--color-token-comment: #5f6f8a;--color-token-punctuation: #bec8db;--color-token-property: #56c8e0;--color-token-string: #42c9a2;--color-token-operator: #f07a6e;--color-token-keyword: #b08df0;--color-token-function: #6aabf7;--color-token-variable: #e0a050;--color-success: #42c9a2;--color-danger: #f07a6e;--color-warning: #e0a050;--color-info: #6aabf7;--color-neutral: #5f6f8a;--color-perf: #e89040;--color-added: rgba(45, 185, 140, .4);--color-deleted: rgba(235, 100, 90, .4)}.diff-unified,.diff-split{background-color:var(--color-diff-bg);color:var(--color-diff-text);font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:13px;line-height:20px}.diff-unified .diff-gutter,.diff-split .diff-gutter{background-color:var(--color-gutter-bg);color:var(--color-gutter-text);border-right:1px solid var(--color-gutter-border);padding:0 8px;min-width:50px;text-align:right;-webkit-user-select:none;-moz-user-select:none;user-select:none;cursor:default}.diff-unified .diff-gutter-col,.diff-split .diff-gutter-col{width:60px;min-width:60px}.diff-unified .diff-code,.diff-split .diff-code{padding:0 12px;white-space:pre}.diff-unified .diff-code-insert,.diff-split .diff-code-insert{background-color:var(--color-diff-insert-bg)}.diff-unified .diff-code-insert .diff-code-text,.diff-split .diff-code-insert .diff-code-text{background-color:transparent}.diff-unified .diff-gutter-insert,.diff-split .diff-gutter-insert{background-color:var(--color-diff-insert-gutter-bg);color:var(--color-diff-insert-gutter-text)}.diff-unified .diff-code-delete,.diff-split .diff-code-delete{background-color:var(--color-diff-delete-bg)}.diff-unified .diff-code-delete .diff-code-text,.diff-split .diff-code-delete .diff-code-text{background-color:transparent}.diff-unified .diff-gutter-delete,.diff-split .diff-gutter-delete{background-color:var(--color-diff-delete-gutter-bg);color:var(--color-diff-delete-gutter-text)}.diff-unified .diff-code-normal,.diff-split .diff-code-normal{background-color:transparent}.diff-unified .diff-gutter-normal,.diff-split .diff-gutter-normal{background-color:var(--color-gutter-bg)}.diff-unified .diff-hunk-header,.diff-split .diff-hunk-header{background-color:var(--color-hunk-bg);border-top:1px solid var(--color-hunk-border);border-bottom:1px solid var(--color-hunk-border)}.diff-unified .diff-hunk-header-gutter,.diff-split .diff-hunk-header-gutter{background-color:var(--color-hunk-gutter-bg);color:var(--color-hunk-gutter-text)}.diff-unified .diff-hunk-header-content,.diff-split .diff-hunk-header-content{color:var(--color-hunk-content-text);padding:4px 12px;font-style:italic}.diff-unified .diff-code-edit .diff-code-text .diff-code-edit-text,.diff-split .diff-code-edit .diff-code-text .diff-code-edit-text{background-color:var(--color-diff-edit-insert);border-radius:2px}.diff-unified .diff-code-delete .diff-code-text .diff-code-edit-text,.diff-split .diff-code-delete .diff-code-text .diff-code-edit-text{background-color:var(--color-diff-edit-delete);border-radius:2px}.diff-unified table,.diff-split table{width:100%;border-collapse:collapse;table-layout:fixed}.diff-unified td,.diff-split td{vertical-align:top}.diff-split .diff-split-side-new .diff-gutter{border-left:1px solid var(--color-split-divider)}.diff-unified .token.comment,.diff-unified .token.prolog,.diff-unified .token.doctype,.diff-unified .token.cdata,.diff-split .token.comment,.diff-split .token.prolog,.diff-split .token.doctype,.diff-split .token.cdata{color:var(--color-token-comment)}.diff-unified .token.punctuation,.diff-split .token.punctuation{color:var(--color-token-punctuation)}.diff-unified .token.property,.diff-unified .token.tag,.diff-unified .token.boolean,.diff-unified .token.number,.diff-unified .token.constant,.diff-unified .token.symbol,.diff-split .token.property,.diff-split .token.tag,.diff-split .token.boolean,.diff-split .token.number,.diff-split .token.constant,.diff-split .token.symbol{color:var(--color-token-property)}.diff-unified .token.selector,.diff-unified .token.attr-name,.diff-unified .token.string,.diff-unified .token.char,.diff-unified .token.builtin,.diff-split .token.selector,.diff-split .token.attr-name,.diff-split .token.string,.diff-split .token.char,.diff-split .token.builtin{color:var(--color-token-string)}.diff-unified .token.operator,.diff-unified .token.entity,.diff-unified .token.url,.diff-split .token.operator,.diff-split .token.entity,.diff-split .token.url{color:var(--color-token-operator)}.diff-unified .token.atrule,.diff-unified .token.attr-value,.diff-unified .token.keyword,.diff-split .token.atrule,.diff-split .token.attr-value,.diff-split .token.keyword{color:var(--color-token-keyword)}.diff-unified .token.function,.diff-unified .token.class-name,.diff-split .token.function,.diff-split .token.class-name{color:var(--color-token-function)}.diff-unified .token.regex,.diff-unified .token.important,.diff-unified .token.variable,.diff-split .token.regex,.diff-split .token.important,.diff-split .token.variable{color:var(--color-token-variable)}.diff-unified .token.string,.diff-split .token.string{color:var(--color-token-string)}.diff-hunk-focused{outline:2px solid var(--color-accent);outline-offset:-2px}.diff-unified .diff-gutter,.diff-split .diff-gutter{cursor:pointer;position:relative}.diff-gutter-add-comment{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;background-color:var(--color-comment-btn-bg);color:#fff;font-size:12px;font-weight:700;line-height:1;position:absolute;left:2px;top:50%;transform:translateY(-50%)}.diff-comment-indicator{display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-comment-indicator);position:absolute;left:4px;top:50%;transform:translateY(-50%)}.diff-annotation-indicator{display:inline-block;width:6px;height:6px;border-radius:50%;background-color:var(--color-annotation-indicator);position:absolute;left:4px;top:50%;transform:translateY(-50%)}.diff-widget{background-color:var(--color-widget-bg)}.diff-widget-content{padding:0}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--color-scrollbar-track)}::-webkit-scrollbar-thumb{background:var(--color-scrollbar-thumb);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--color-scrollbar-thumb-hover)}.placeholder\:text-text-secondary::-moz-placeholder{color:var(--color-text-secondary)}.placeholder\:text-text-secondary::placeholder{color:var(--color-text-secondary)}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-danger:hover{color:var(--color-danger)}.hover\:text-text-primary:hover{color:var(--color-text-primary)}.hover\:underline:hover{text-decoration-line:underline}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--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(1px + 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)}.focus\:ring-accent:focus{--tw-ring-color:var(--color-accent)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:text-text-primary{color:var(--color-text-primary)}.group\/annotation:hover .group-hover\/annotation\:opacity-100,.group\/comment:hover .group-hover\/comment\:opacity-100,.group:hover .group-hover\:opacity-100{opacity:1}.group:hover .group-hover\:opacity-40{opacity:.4}