@saga-ai/cli 2.13.0 → 2.14.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/cli.cjs CHANGED
@@ -25,8 +25,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
 
26
26
  // src/cli.ts
27
27
  var import_commander = require("commander");
28
- var import_node_path8 = require("node:path");
29
- var import_node_fs7 = require("node:fs");
28
+ var import_node_path9 = require("node:path");
29
+ var import_node_fs8 = require("node:fs");
30
30
 
31
31
  // src/commands/init.ts
32
32
  var import_node_path2 = require("node:path");
@@ -1400,8 +1400,8 @@ function validateTaskStatus(status) {
1400
1400
  return "pending";
1401
1401
  }
1402
1402
  async function parseStory(storyPath, epicSlug) {
1403
- const { join: join13 } = await import("path");
1404
- const { stat: stat3 } = await import("fs/promises");
1403
+ const { join: join14 } = await import("path");
1404
+ const { stat: stat4 } = await import("fs/promises");
1405
1405
  let content;
1406
1406
  try {
1407
1407
  content = await (0, import_promises3.readFile)(storyPath, "utf-8");
@@ -1420,10 +1420,10 @@ async function parseStory(storyPath, epicSlug) {
1420
1420
  const title = frontmatter.title || dirName;
1421
1421
  const status = validateStatus(frontmatter.status);
1422
1422
  const tasks = parseTasks(frontmatter.tasks);
1423
- const journalPath = join13(storyDir, "journal.md");
1423
+ const journalPath = join14(storyDir, "journal.md");
1424
1424
  let hasJournal = false;
1425
1425
  try {
1426
- await stat3(journalPath);
1426
+ await stat4(journalPath);
1427
1427
  hasJournal = true;
1428
1428
  } catch {
1429
1429
  }
@@ -1887,6 +1887,290 @@ async function createSagaWatcher(sagaRoot) {
1887
1887
 
1888
1888
  // src/server/websocket.ts
1889
1889
  var import_path5 = require("path");
1890
+
1891
+ // src/lib/log-stream-manager.ts
1892
+ var import_chokidar2 = __toESM(require("chokidar"), 1);
1893
+ var import_node_fs6 = require("node:fs");
1894
+ var import_promises4 = require("node:fs/promises");
1895
+ var import_node_path6 = require("node:path");
1896
+ var LogStreamManager = class {
1897
+ /**
1898
+ * Active file watchers indexed by session name
1899
+ */
1900
+ watchers = /* @__PURE__ */ new Map();
1901
+ /**
1902
+ * Current file position (byte offset) per session for incremental reads
1903
+ */
1904
+ filePositions = /* @__PURE__ */ new Map();
1905
+ /**
1906
+ * Client subscriptions per session
1907
+ */
1908
+ subscriptions = /* @__PURE__ */ new Map();
1909
+ /**
1910
+ * Function to send messages to clients
1911
+ */
1912
+ sendToClient;
1913
+ /**
1914
+ * Create a new LogStreamManager instance
1915
+ *
1916
+ * @param sendToClient - Function to send log data messages to clients
1917
+ */
1918
+ constructor(sendToClient) {
1919
+ this.sendToClient = sendToClient;
1920
+ }
1921
+ /**
1922
+ * Get the number of subscriptions for a session
1923
+ *
1924
+ * @param sessionName - The session to check
1925
+ * @returns Number of subscribed clients
1926
+ */
1927
+ getSubscriptionCount(sessionName) {
1928
+ const subs = this.subscriptions.get(sessionName);
1929
+ return subs ? subs.size : 0;
1930
+ }
1931
+ /**
1932
+ * Check if a watcher exists for a session
1933
+ *
1934
+ * @param sessionName - The session to check
1935
+ * @returns True if a watcher exists
1936
+ */
1937
+ hasWatcher(sessionName) {
1938
+ return this.watchers.has(sessionName);
1939
+ }
1940
+ /**
1941
+ * Get the current file position for a session
1942
+ *
1943
+ * @param sessionName - The session to check
1944
+ * @returns The current byte offset, or 0 if not tracked
1945
+ */
1946
+ getFilePosition(sessionName) {
1947
+ return this.filePositions.get(sessionName) ?? 0;
1948
+ }
1949
+ /**
1950
+ * Subscribe a client to a session's log stream
1951
+ *
1952
+ * Reads the full file content and sends it as the initial message.
1953
+ * Adds the client to the subscription set for incremental updates.
1954
+ * Creates a file watcher if this is the first subscriber.
1955
+ *
1956
+ * @param sessionName - The session to subscribe to
1957
+ * @param ws - The WebSocket client to subscribe
1958
+ */
1959
+ async subscribe(sessionName, ws) {
1960
+ const outputFile = (0, import_node_path6.join)(OUTPUT_DIR, `${sessionName}.out`);
1961
+ if (!(0, import_node_fs6.existsSync)(outputFile)) {
1962
+ this.sendToClient(ws, {
1963
+ type: "logs:error",
1964
+ sessionName,
1965
+ error: `Output file not found: ${outputFile}`
1966
+ });
1967
+ return;
1968
+ }
1969
+ const content = await (0, import_promises4.readFile)(outputFile, "utf-8");
1970
+ this.sendToClient(ws, {
1971
+ type: "logs:data",
1972
+ sessionName,
1973
+ data: content,
1974
+ isInitial: true,
1975
+ isComplete: false
1976
+ });
1977
+ this.filePositions.set(sessionName, content.length);
1978
+ let subs = this.subscriptions.get(sessionName);
1979
+ if (!subs) {
1980
+ subs = /* @__PURE__ */ new Set();
1981
+ this.subscriptions.set(sessionName, subs);
1982
+ }
1983
+ subs.add(ws);
1984
+ if (!this.watchers.has(sessionName)) {
1985
+ this.createWatcher(sessionName, outputFile);
1986
+ }
1987
+ }
1988
+ /**
1989
+ * Create a chokidar file watcher for a session's output file
1990
+ *
1991
+ * The watcher detects changes and triggers incremental content delivery
1992
+ * to all subscribed clients.
1993
+ *
1994
+ * @param sessionName - The session name
1995
+ * @param outputFile - Path to the session output file
1996
+ */
1997
+ createWatcher(sessionName, outputFile) {
1998
+ const watcher = import_chokidar2.default.watch(outputFile, {
1999
+ persistent: true,
2000
+ awaitWriteFinish: false
2001
+ });
2002
+ watcher.on("change", async () => {
2003
+ await this.sendIncrementalContent(sessionName, outputFile);
2004
+ });
2005
+ this.watchers.set(sessionName, watcher);
2006
+ }
2007
+ /**
2008
+ * Clean up a watcher and associated state for a session
2009
+ *
2010
+ * Closes the file watcher and removes all tracking state for the session.
2011
+ * Should be called when the last subscriber unsubscribes or disconnects.
2012
+ *
2013
+ * @param sessionName - The session to clean up
2014
+ */
2015
+ cleanupWatcher(sessionName) {
2016
+ const watcher = this.watchers.get(sessionName);
2017
+ if (watcher) {
2018
+ watcher.close();
2019
+ this.watchers.delete(sessionName);
2020
+ }
2021
+ this.filePositions.delete(sessionName);
2022
+ this.subscriptions.delete(sessionName);
2023
+ }
2024
+ /**
2025
+ * Send incremental content to all subscribed clients for a session
2026
+ *
2027
+ * Reads from the last known position to the end of the file and sends
2028
+ * the new content to all subscribed clients.
2029
+ *
2030
+ * @param sessionName - The session name
2031
+ * @param outputFile - Path to the session output file
2032
+ */
2033
+ async sendIncrementalContent(sessionName, outputFile) {
2034
+ const lastPosition = this.filePositions.get(sessionName) ?? 0;
2035
+ const fileStat = await (0, import_promises4.stat)(outputFile);
2036
+ const currentSize = fileStat.size;
2037
+ if (currentSize <= lastPosition) {
2038
+ return;
2039
+ }
2040
+ const newContent = await this.readFromPosition(outputFile, lastPosition, currentSize);
2041
+ this.filePositions.set(sessionName, currentSize);
2042
+ const subs = this.subscriptions.get(sessionName);
2043
+ if (subs) {
2044
+ const message = {
2045
+ type: "logs:data",
2046
+ sessionName,
2047
+ data: newContent,
2048
+ isInitial: false,
2049
+ isComplete: false
2050
+ };
2051
+ for (const ws of subs) {
2052
+ this.sendToClient(ws, message);
2053
+ }
2054
+ }
2055
+ }
2056
+ /**
2057
+ * Read file content from a specific position
2058
+ *
2059
+ * @param filePath - Path to the file
2060
+ * @param start - Starting byte position
2061
+ * @param end - Ending byte position
2062
+ * @returns The content read from the file
2063
+ */
2064
+ readFromPosition(filePath, start, end) {
2065
+ return new Promise((resolve2, reject) => {
2066
+ let content = "";
2067
+ const stream = (0, import_node_fs6.createReadStream)(filePath, {
2068
+ start,
2069
+ end: end - 1,
2070
+ // createReadStream end is inclusive
2071
+ encoding: "utf-8"
2072
+ });
2073
+ stream.on("data", (chunk) => {
2074
+ content += chunk;
2075
+ });
2076
+ stream.on("end", () => {
2077
+ resolve2(content);
2078
+ });
2079
+ stream.on("error", reject);
2080
+ });
2081
+ }
2082
+ /**
2083
+ * Unsubscribe a client from a session's log stream
2084
+ *
2085
+ * Removes the client from the subscription set. If this was the last
2086
+ * subscriber, cleans up the watcher and associated state.
2087
+ *
2088
+ * @param sessionName - The session to unsubscribe from
2089
+ * @param ws - The WebSocket client to unsubscribe
2090
+ */
2091
+ unsubscribe(sessionName, ws) {
2092
+ const subs = this.subscriptions.get(sessionName);
2093
+ if (subs) {
2094
+ subs.delete(ws);
2095
+ if (subs.size === 0) {
2096
+ this.cleanupWatcher(sessionName);
2097
+ }
2098
+ }
2099
+ }
2100
+ /**
2101
+ * Handle client disconnect by removing from all subscriptions
2102
+ *
2103
+ * Should be called when a WebSocket connection closes to clean up
2104
+ * any subscriptions the client may have had. Also triggers watcher
2105
+ * cleanup for any sessions that no longer have subscribers.
2106
+ *
2107
+ * @param ws - The WebSocket client that disconnected
2108
+ */
2109
+ handleClientDisconnect(ws) {
2110
+ for (const [sessionName, subs] of this.subscriptions) {
2111
+ subs.delete(ws);
2112
+ if (subs.size === 0) {
2113
+ this.cleanupWatcher(sessionName);
2114
+ }
2115
+ }
2116
+ }
2117
+ /**
2118
+ * Notify that a session has completed
2119
+ *
2120
+ * Reads any remaining content from the file and sends it with isComplete=true
2121
+ * to all subscribed clients, then cleans up the watcher regardless of
2122
+ * subscription count. Called by session polling when it detects completion.
2123
+ *
2124
+ * @param sessionName - The session that has completed
2125
+ */
2126
+ async notifySessionCompleted(sessionName) {
2127
+ const subs = this.subscriptions.get(sessionName);
2128
+ if (!subs || subs.size === 0) {
2129
+ return;
2130
+ }
2131
+ const outputFile = (0, import_node_path6.join)(OUTPUT_DIR, `${sessionName}.out`);
2132
+ let finalContent = "";
2133
+ try {
2134
+ if ((0, import_node_fs6.existsSync)(outputFile)) {
2135
+ const lastPosition = this.filePositions.get(sessionName) ?? 0;
2136
+ const fileStat = await (0, import_promises4.stat)(outputFile);
2137
+ const currentSize = fileStat.size;
2138
+ if (currentSize > lastPosition) {
2139
+ finalContent = await this.readFromPosition(outputFile, lastPosition, currentSize);
2140
+ }
2141
+ }
2142
+ } catch {
2143
+ }
2144
+ const message = {
2145
+ type: "logs:data",
2146
+ sessionName,
2147
+ data: finalContent,
2148
+ isInitial: false,
2149
+ isComplete: true
2150
+ };
2151
+ for (const ws of subs) {
2152
+ this.sendToClient(ws, message);
2153
+ }
2154
+ this.cleanupWatcher(sessionName);
2155
+ }
2156
+ /**
2157
+ * Clean up all watchers and subscriptions
2158
+ *
2159
+ * Call this when shutting down the server.
2160
+ */
2161
+ async dispose() {
2162
+ const closePromises = [];
2163
+ for (const [, watcher] of this.watchers) {
2164
+ closePromises.push(watcher.close());
2165
+ }
2166
+ await Promise.all(closePromises);
2167
+ this.watchers.clear();
2168
+ this.filePositions.clear();
2169
+ this.subscriptions.clear();
2170
+ }
2171
+ };
2172
+
2173
+ // src/server/websocket.ts
1890
2174
  function makeStoryKey(epicSlug, storySlug) {
1891
2175
  return `${epicSlug}:${storySlug}`;
1892
2176
  }
@@ -1923,13 +2207,29 @@ async function createWebSocketServer(httpServer, sagaRoot) {
1923
2207
  ws.send(JSON.stringify(message));
1924
2208
  }
1925
2209
  }
2210
+ function sendLogMessage(ws, message) {
2211
+ if (ws.readyState === import_ws.WebSocket.OPEN) {
2212
+ ws.send(JSON.stringify({ event: message.type, data: message }));
2213
+ }
2214
+ }
2215
+ const logStreamManager = new LogStreamManager(sendLogMessage);
1926
2216
  function broadcast(message) {
1927
2217
  for (const [ws] of clients) {
1928
2218
  sendToClient(ws, message);
1929
2219
  }
1930
2220
  }
2221
+ let previousSessionStates = /* @__PURE__ */ new Map();
1931
2222
  startSessionPolling((msg) => {
1932
2223
  broadcast({ event: msg.type, data: msg.sessions });
2224
+ const currentStates = /* @__PURE__ */ new Map();
2225
+ for (const session of msg.sessions) {
2226
+ currentStates.set(session.name, session.status);
2227
+ const previousStatus = previousSessionStates.get(session.name);
2228
+ if (previousStatus === "running" && session.status === "completed") {
2229
+ logStreamManager.notifySessionCompleted(session.name);
2230
+ }
2231
+ }
2232
+ previousSessionStates = currentStates;
1933
2233
  });
1934
2234
  function broadcastToSubscribers(storyKey, message) {
1935
2235
  for (const [ws, state] of clients) {
@@ -1971,6 +2271,20 @@ async function createWebSocketServer(httpServer, sagaRoot) {
1971
2271
  }
1972
2272
  break;
1973
2273
  }
2274
+ case "subscribe:logs": {
2275
+ const { sessionName } = message.data || {};
2276
+ if (sessionName) {
2277
+ logStreamManager.subscribe(sessionName, ws);
2278
+ }
2279
+ break;
2280
+ }
2281
+ case "unsubscribe:logs": {
2282
+ const { sessionName } = message.data || {};
2283
+ if (sessionName) {
2284
+ logStreamManager.unsubscribe(sessionName, ws);
2285
+ }
2286
+ break;
2287
+ }
1974
2288
  default:
1975
2289
  break;
1976
2290
  }
@@ -1979,10 +2293,12 @@ async function createWebSocketServer(httpServer, sagaRoot) {
1979
2293
  });
1980
2294
  ws.on("close", () => {
1981
2295
  clients.delete(ws);
2296
+ logStreamManager.handleClientDisconnect(ws);
1982
2297
  });
1983
2298
  ws.on("error", (err) => {
1984
2299
  console.error("WebSocket error:", err);
1985
2300
  clients.delete(ws);
2301
+ logStreamManager.handleClientDisconnect(ws);
1986
2302
  });
1987
2303
  });
1988
2304
  if (watcher) {
@@ -2054,6 +2370,7 @@ async function createWebSocketServer(httpServer, sagaRoot) {
2054
2370
  async close() {
2055
2371
  clearInterval(heartbeatInterval);
2056
2372
  stopSessionPolling();
2373
+ await logStreamManager.dispose();
2057
2374
  for (const [ws] of clients) {
2058
2375
  ws.close();
2059
2376
  }
@@ -2159,7 +2476,7 @@ async function dashboardCommand(options) {
2159
2476
  }
2160
2477
 
2161
2478
  // src/commands/scope-validator.ts
2162
- var import_node_path6 = require("node:path");
2479
+ var import_node_path7 = require("node:path");
2163
2480
  function getFilePathFromInput(hookInput) {
2164
2481
  try {
2165
2482
  const data = JSON.parse(hookInput);
@@ -2179,10 +2496,10 @@ function isArchiveAccess(path) {
2179
2496
  return path.includes(".saga/archive");
2180
2497
  }
2181
2498
  function isWithinWorktree(filePath, worktreePath) {
2182
- const absoluteFilePath = (0, import_node_path6.resolve)(filePath);
2183
- const absoluteWorktree = (0, import_node_path6.resolve)(worktreePath);
2184
- const relativePath = (0, import_node_path6.relative)(absoluteWorktree, absoluteFilePath);
2185
- if (relativePath.startsWith("..") || (0, import_node_path6.resolve)(relativePath) === relativePath) {
2499
+ const absoluteFilePath = (0, import_node_path7.resolve)(filePath);
2500
+ const absoluteWorktree = (0, import_node_path7.resolve)(worktreePath);
2501
+ const relativePath = (0, import_node_path7.relative)(absoluteWorktree, absoluteFilePath);
2502
+ if (relativePath.startsWith("..") || (0, import_node_path7.resolve)(relativePath) === relativePath) {
2186
2503
  return false;
2187
2504
  }
2188
2505
  return true;
@@ -2297,8 +2614,8 @@ async function findCommand(query, options) {
2297
2614
  }
2298
2615
 
2299
2616
  // src/commands/worktree.ts
2300
- var import_node_path7 = require("node:path");
2301
- var import_node_fs6 = require("node:fs");
2617
+ var import_node_path8 = require("node:path");
2618
+ var import_node_fs7 = require("node:fs");
2302
2619
  var import_node_child_process3 = require("node:child_process");
2303
2620
  function runGitCommand(args, cwd) {
2304
2621
  try {
@@ -2329,7 +2646,7 @@ function getMainBranch(cwd) {
2329
2646
  }
2330
2647
  function createWorktree(projectPath, epicSlug, storySlug) {
2331
2648
  const branchName = `story-${storySlug}-epic-${epicSlug}`;
2332
- const worktreePath = (0, import_node_path7.join)(
2649
+ const worktreePath = (0, import_node_path8.join)(
2333
2650
  projectPath,
2334
2651
  ".saga",
2335
2652
  "worktrees",
@@ -2342,7 +2659,7 @@ function createWorktree(projectPath, epicSlug, storySlug) {
2342
2659
  error: `Branch already exists: ${branchName}`
2343
2660
  };
2344
2661
  }
2345
- if ((0, import_node_fs6.existsSync)(worktreePath)) {
2662
+ if ((0, import_node_fs7.existsSync)(worktreePath)) {
2346
2663
  return {
2347
2664
  success: false,
2348
2665
  error: `Worktree directory already exists: ${worktreePath}`
@@ -2360,8 +2677,8 @@ function createWorktree(projectPath, epicSlug, storySlug) {
2360
2677
  error: `Failed to create branch: ${createBranchResult.output}`
2361
2678
  };
2362
2679
  }
2363
- const worktreeParent = (0, import_node_path7.join)(projectPath, ".saga", "worktrees", epicSlug);
2364
- (0, import_node_fs6.mkdirSync)(worktreeParent, { recursive: true });
2680
+ const worktreeParent = (0, import_node_path8.join)(projectPath, ".saga", "worktrees", epicSlug);
2681
+ (0, import_node_fs7.mkdirSync)(worktreeParent, { recursive: true });
2365
2682
  const createWorktreeResult = runGitCommand(
2366
2683
  ["worktree", "add", worktreePath, branchName],
2367
2684
  projectPath
@@ -2417,8 +2734,8 @@ async function sessionsKillCommand(sessionName) {
2417
2734
  }
2418
2735
 
2419
2736
  // src/cli.ts
2420
- var packageJsonPath = (0, import_node_path8.join)(__dirname, "..", "package.json");
2421
- var packageJson = JSON.parse((0, import_node_fs7.readFileSync)(packageJsonPath, "utf-8"));
2737
+ var packageJsonPath = (0, import_node_path9.join)(__dirname, "..", "package.json");
2738
+ var packageJson = JSON.parse((0, import_node_fs8.readFileSync)(packageJsonPath, "utf-8"));
2422
2739
  var program = new import_commander.Command();
2423
2740
  program.name("saga").description("CLI for SAGA - Structured Autonomous Goal Achievement").version(packageJson.version).addHelpCommand("help [command]", "Display help for a command");
2424
2741
  program.option("-p, --path <dir>", "Path to SAGA project directory (overrides auto-discovery)");
@@ -0,0 +1 @@
1
+ *,: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}:root{--bg-dark: oklch(.1 .025 264);--bg: oklch(.15 .025 264);--bg-light: oklch(.2 .025 264);--text: oklch(.96 .05 264);--text-muted: oklch(.76 .05 264);--highlight: oklch(.5 .05 264);--border: oklch(.4 .05 264);--border-muted: oklch(.3 .05 264);--primary: oklch(.76 .1 264);--secondary: oklch(.76 .1 84);--danger: oklch(.7 .05 30);--warning: oklch(.7 .05 100);--success: oklch(.7 .05 160);--info: oklch(.7 .05 260);--background: var(--bg);--foreground: var(--text);--card: var(--bg-dark);--card-foreground: var(--text);--popover: var(--bg-dark);--popover-foreground: var(--text);--primary-foreground: var(--bg-dark);--secondary-foreground: var(--bg-dark);--muted: var(--bg-light);--muted-foreground: var(--text-muted);--accent: var(--bg-light);--accent-foreground: var(--text);--destructive: var(--danger);--destructive-foreground: var(--text);--input: var(--border-muted);--ring: var(--primary);--radius: .5rem}*{border-color:var(--border)}body{background-color:var(--bg);color:var(--text);font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;min-height:100vh}.\!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}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"“""”""‘""’";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px var(--tw-prose-kbd-shadows),0 3px 0 var(--tw-prose-kbd-shadows);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body: #374151;--tw-prose-headings: #111827;--tw-prose-lead: #4b5563;--tw-prose-links: #111827;--tw-prose-bold: #111827;--tw-prose-counters: #6b7280;--tw-prose-bullets: #d1d5db;--tw-prose-hr: #e5e7eb;--tw-prose-quotes: #111827;--tw-prose-quote-borders: #e5e7eb;--tw-prose-captions: #6b7280;--tw-prose-kbd: #111827;--tw-prose-kbd-shadows: rgb(17 24 39 / 10%);--tw-prose-code: #111827;--tw-prose-pre-code: #e5e7eb;--tw-prose-pre-bg: #1f2937;--tw-prose-th-borders: #d1d5db;--tw-prose-td-borders: #e5e7eb;--tw-prose-invert-body: #d1d5db;--tw-prose-invert-headings: #fff;--tw-prose-invert-lead: #9ca3af;--tw-prose-invert-links: #fff;--tw-prose-invert-bold: #fff;--tw-prose-invert-counters: #9ca3af;--tw-prose-invert-bullets: #4b5563;--tw-prose-invert-hr: #374151;--tw-prose-invert-quotes: #f3f4f6;--tw-prose-invert-quote-borders: #374151;--tw-prose-invert-captions: #9ca3af;--tw-prose-invert-kbd: #fff;--tw-prose-invert-kbd-shadows: rgb(255 255 255 / 10%);--tw-prose-invert-code: #fff;--tw-prose-invert-pre-code: #d1d5db;--tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);--tw-prose-invert-th-borders: #4b5563;--tw-prose-invert-td-borders: #374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.7142857}.prose-sm :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-top:.8888889em;margin-bottom:.8888889em}.prose-sm :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em;padding-inline-start:1.1111111em}.prose-sm :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.1428571em;margin-top:0;margin-bottom:.8em;line-height:1.2}.prose-sm :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.4285714em;margin-top:1.6em;margin-bottom:.8em;line-height:1.4}.prose-sm :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;margin-top:1.5555556em;margin-bottom:.4444444em;line-height:1.5555556}.prose-sm :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.4285714em;margin-bottom:.5714286em;line-height:1.4285714}.prose-sm :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;border-radius:.3125rem;padding-top:.1428571em;padding-inline-end:.3571429em;padding-bottom:.1428571em;padding-inline-start:.3571429em}.prose-sm :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em}.prose-sm :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.prose-sm :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.6666667;margin-top:1.6666667em;margin-bottom:1.6666667em;border-radius:.25rem;padding-top:.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;margin-bottom:.2857143em}.prose-sm :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(.prose-sm>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm :where(.prose-sm>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;padding-inline-start:1.5714286em}.prose-sm :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2.8571429em;margin-bottom:2.8571429em}.prose-sm :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.3333333;margin-top:.6666667em}.prose-sm :where(.prose-sm>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose-sm>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-invert{--tw-prose-body: var(--tw-prose-invert-body);--tw-prose-headings: var(--tw-prose-invert-headings);--tw-prose-lead: var(--tw-prose-invert-lead);--tw-prose-links: var(--tw-prose-invert-links);--tw-prose-bold: var(--tw-prose-invert-bold);--tw-prose-counters: var(--tw-prose-invert-counters);--tw-prose-bullets: var(--tw-prose-invert-bullets);--tw-prose-hr: var(--tw-prose-invert-hr);--tw-prose-quotes: var(--tw-prose-invert-quotes);--tw-prose-quote-borders: var(--tw-prose-invert-quote-borders);--tw-prose-captions: var(--tw-prose-invert-captions);--tw-prose-kbd: var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows: var(--tw-prose-invert-kbd-shadows);--tw-prose-code: var(--tw-prose-invert-code);--tw-prose-pre-code: var(--tw-prose-invert-pre-code);--tw-prose-pre-bg: var(--tw-prose-invert-pre-bg);--tw-prose-th-borders: var(--tw-prose-invert-th-borders);--tw-prose-td-borders: var(--tw-prose-invert-td-borders)}.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}.left-0{left:0}.right-2{right:.5rem}.top-0{top:0}.top-2{top:.5rem}.z-\[100\]{z-index:100}.mx-auto{margin-left:auto;margin-right:auto}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.block{display:block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-20{height:5rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-96{height:24rem}.h-full{height:100%}.max-h-screen{max-height:100vh}.min-h-screen{min-height:100vh}.w-1\/2{width:50%}.w-10{width:2.5rem}.w-16{width:4rem}.w-2\/3{width:66.666667%}.w-20{width:5rem}.w-24{width:6rem}.w-3\.5{width:.875rem}.w-3\/4{width:75%}.w-32{width:8rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-5\/6{width:83.333333%}.w-64{width:16rem}.w-full{width:100%}.max-w-none{max-width:none}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.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 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-default{cursor:default}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-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-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-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.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:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-t-lg{border-top-left-radius:var(--radius);border-top-right-radius:var(--radius)}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-dashed{border-style:dashed}.border-bg-light{border-color:var(--bg-light)}.border-border{border-color:var(--border)}.border-destructive{border-color:var(--destructive)}.border-input{border-color:var(--input)}.border-transparent{border-color:transparent}.bg-background{background-color:var(--background)}.bg-bg{background-color:var(--bg)}.bg-bg-dark{background-color:var(--bg-dark)}.bg-bg-light{background-color:var(--bg-light)}.bg-card{background-color:var(--card)}.bg-danger{background-color:var(--danger)}.bg-destructive{background-color:var(--destructive)}.bg-muted{background-color:var(--muted)}.bg-primary{background-color:var(--primary)}.bg-secondary{background-color:var(--secondary)}.bg-success{background-color:var(--success)}.bg-transparent{background-color:transparent}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.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-12{padding-top:3rem;padding-bottom:3rem}.py-2{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-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.pr-8{padding-right:2rem}.pt-0{padding-top:0}.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-base{font-size:1rem;line-height:1.5rem}.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}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.text-card-foreground{color:var(--card-foreground)}.text-danger{color:var(--danger)}.text-destructive-foreground{color:var(--destructive-foreground)}.text-foreground{color:var(--foreground)}.text-muted{color:var(--muted)}.text-muted-foreground{color:var(--muted-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-success{color:var(--success)}.text-text{color:var(--text)}.text-text-muted{color:var(--text-muted)}.line-through{text-decoration-line:line-through}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-90{opacity:.9}.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-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)}.outline{outline-style:solid}.ring-offset-background{--tw-ring-offset-color: var(--background)}.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}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}.running{animation-play-state:running}.hover\:bg-accent:hover{background-color:var(--accent)}.hover\:bg-secondary:hover{background-color:var(--secondary)}.hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:text-primary:hover{color:var(--primary)}.hover\:text-text:hover{color:var(--text)}.hover\:underline:hover{text-decoration-line:underline}.focus\:opacity-100:focus{opacity:1}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2: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(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)}.focus\:ring-ring:focus{--tw-ring-color: var(--ring)}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--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)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: var(--ring)}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:opacity-100{opacity:1}.group.destructive .group-\[\.destructive\]\:text-red-300{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.group.destructive .group-\[\.destructive\]\:hover\:bg-destructive:hover{background-color:var(--destructive)}.group.destructive .group-\[\.destructive\]\:hover\:text-destructive-foreground:hover{color:var(--destructive-foreground)}.group.destructive .group-\[\.destructive\]\:hover\:text-red-50:hover{--tw-text-opacity: 1;color:rgb(254 242 242 / var(--tw-text-opacity, 1))}.group.destructive .group-\[\.destructive\]\:focus\:ring-destructive:focus{--tw-ring-color: var(--destructive)}.group.destructive .group-\[\.destructive\]\:focus\:ring-red-400:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(248 113 113 / var(--tw-ring-opacity, 1))}.group.destructive .group-\[\.destructive\]\:focus\:ring-offset-red-600:focus{--tw-ring-offset-color: #dc2626}.data-\[swipe\=cancel\]\:translate-x-0[data-swipe=cancel]{--tw-translate-x: 0px;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))}.data-\[swipe\=end\]\:translate-x-\[var\(--radix-toast-swipe-end-x\)\][data-swipe=end]{--tw-translate-x: var(--radix-toast-swipe-end-x);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))}.data-\[swipe\=move\]\:translate-x-\[var\(--radix-toast-swipe-move-x\)\][data-swipe=move]{--tw-translate-x: var(--radix-toast-swipe-move-x);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))}.data-\[state\=active\]\:bg-background[data-state=active]{background-color:var(--background)}.data-\[state\=active\]\:text-foreground[data-state=active]{color:var(--foreground)}.data-\[state\=active\]\:shadow-sm[data-state=active]{--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)}.data-\[swipe\=move\]\:transition-none[data-swipe=move]{transition-property:none}.data-\[state\=open\]\:animate-in[data-state=open]{animation-name:enter;animation-duration:.15s;--tw-enter-opacity: initial;--tw-enter-scale: initial;--tw-enter-rotate: initial;--tw-enter-translate-x: initial;--tw-enter-translate-y: initial}.data-\[state\=closed\]\:animate-out[data-state=closed],.data-\[swipe\=end\]\:animate-out[data-swipe=end]{animation-name:exit;animation-duration:.15s;--tw-exit-opacity: initial;--tw-exit-scale: initial;--tw-exit-rotate: initial;--tw-exit-translate-x: initial;--tw-exit-translate-y: initial}.data-\[state\=closed\]\:fade-out-80[data-state=closed]{--tw-exit-opacity: .8}.data-\[state\=closed\]\:slide-out-to-right-full[data-state=closed]{--tw-exit-translate-x: 100%}.data-\[state\=open\]\:slide-in-from-top-full[data-state=open]{--tw-enter-translate-y: -100%}.prose-headings\:text-text :is(:where(h1,h2,h3,h4,h5,h6,th):not(:where([class~=not-prose],[class~=not-prose] *))){color:var(--text)}.prose-p\:text-text-muted :is(:where(p):not(:where([class~=not-prose],[class~=not-prose] *))){color:var(--text-muted)}.prose-a\:text-primary :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){color:var(--primary)}.prose-a\:no-underline :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){text-decoration-line:none}.hover\:prose-a\:underline :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))):hover{text-decoration-line:underline}.prose-strong\:text-text :is(:where(strong):not(:where([class~=not-prose],[class~=not-prose] *))){color:var(--text)}.prose-code\:rounded :is(:where(code):not(:where([class~=not-prose],[class~=not-prose] *))){border-radius:.25rem}.prose-code\:bg-bg-dark :is(:where(code):not(:where([class~=not-prose],[class~=not-prose] *))){background-color:var(--bg-dark)}.prose-code\:px-1 :is(:where(code):not(:where([class~=not-prose],[class~=not-prose] *))){padding-left:.25rem;padding-right:.25rem}.prose-code\:py-0\.5 :is(:where(code):not(:where([class~=not-prose],[class~=not-prose] *))){padding-top:.125rem;padding-bottom:.125rem}.prose-code\:text-primary :is(:where(code):not(:where([class~=not-prose],[class~=not-prose] *))){color:var(--primary)}.prose-code\:before\:content-none :is(:where(code):not(:where([class~=not-prose],[class~=not-prose] *))):before{--tw-content: none;content:var(--tw-content)}.prose-code\:after\:content-none :is(:where(code):not(:where([class~=not-prose],[class~=not-prose] *))):after{--tw-content: none;content:var(--tw-content)}.prose-pre\:border :is(:where(pre):not(:where([class~=not-prose],[class~=not-prose] *))){border-width:1px}.prose-pre\:bg-bg-dark :is(:where(pre):not(:where([class~=not-prose],[class~=not-prose] *))){background-color:var(--bg-dark)}.prose-li\:text-text-muted :is(:where(li):not(:where([class~=not-prose],[class~=not-prose] *))){color:var(--text-muted)}.prose-table\:border :is(:where(table):not(:where([class~=not-prose],[class~=not-prose] *))){border-width:1px}.prose-th\:bg-bg-dark :is(:where(th):not(:where([class~=not-prose],[class~=not-prose] *))){background-color:var(--bg-dark)}.prose-th\:px-3 :is(:where(th):not(:where([class~=not-prose],[class~=not-prose] *))){padding-left:.75rem;padding-right:.75rem}.prose-th\:py-2 :is(:where(th):not(:where([class~=not-prose],[class~=not-prose] *))){padding-top:.5rem;padding-bottom:.5rem}.prose-th\:text-text :is(:where(th):not(:where([class~=not-prose],[class~=not-prose] *))){color:var(--text)}.prose-td\:border-t :is(:where(td):not(:where([class~=not-prose],[class~=not-prose] *))){border-top-width:1px}.prose-td\:px-3 :is(:where(td):not(:where([class~=not-prose],[class~=not-prose] *))){padding-left:.75rem;padding-right:.75rem}.prose-td\:py-2 :is(:where(td):not(:where([class~=not-prose],[class~=not-prose] *))){padding-top:.5rem;padding-bottom:.5rem}@media(min-width:640px){.sm\:bottom-0{bottom:0}.sm\:right-0{right:0}.sm\:top-auto{top:auto}.sm\:flex-col{flex-direction:column}.data-\[state\=open\]\:sm\:slide-in-from-bottom-full[data-state=open]{--tw-enter-translate-y: 100%}}@media(min-width:768px){.md\:max-w-\[420px\]{max-width:420px}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(min-width:1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:1rem;height:1rem}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}