image-sprout 1.0.2 → 1.2.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/index.js CHANGED
@@ -5,11 +5,14 @@ import path from "node:path";
5
5
  import { createServer } from "node:http";
6
6
  import { fileURLToPath } from "node:url";
7
7
  const OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions";
8
- const ANALYSIS_MODEL = "google/gemini-3.1-flash-image-preview";
8
+ const DEFAULT_ANALYSIS_MODEL = "google/gemini-3.1-flash-image-preview";
9
9
  const REFERER = "https://image-sprout.app";
10
10
  const OPENAI_SIZE_MAP = {
11
11
  "1:1": "1024x1024",
12
+ "4:3": "1536x1024",
13
+ "3:2": "1536x1024",
12
14
  "16:9": "1536x1024",
15
+ "4:5": "1024x1536",
13
16
  "9:16": "1024x1536"
14
17
  };
15
18
  const MAX_REFERENCE_IMAGES = 14;
@@ -168,7 +171,7 @@ async function generateImages(request, apiKey, signal) {
168
171
  };
169
172
  });
170
173
  }
171
- async function analyzeReferenceImages(imageDataUrls, apiKey, signal) {
174
+ async function analyzeReferenceImages(imageDataUrls, apiKey, signal, analysisModel) {
172
175
  validateApiKey(apiKey);
173
176
  const cappedImageUrls = capImages(imageDataUrls);
174
177
  const imageParts = buildImageParts(cappedImageUrls);
@@ -187,18 +190,21 @@ visualStyle: Describe ONLY the visual rendering style. Cover color palette, line
187
190
  subjectGuide: Describe ONLY the recurring subject(s) that appear across images — their physical design, proportions, distinguishing features, and general personality or tone. Focus on who or what should stay consistent across generations. Exclude rendering style, medium, palette, composition, lighting, and other art-direction details, even if they are prominent in the images. Do NOT list specific scenes, actions, settings, or scenarios from the images. These will be provided separately by the user for each new image.`
188
191
  };
189
192
  const content = [...imageParts, textPart];
190
- const responseData = await sendRequest(content, ["text"], apiKey, ANALYSIS_MODEL, void 0);
193
+ const responseData = await sendRequest(content, ["text"], apiKey, analysisModel ?? DEFAULT_ANALYSIS_MODEL, void 0);
191
194
  const text = extractTextFromResponse(responseData);
192
195
  if (!text) {
193
196
  throw new Error("No text response received from reference image analysis");
194
197
  }
198
+ const jsonMatch = text.match(/\{[\s\S]*\}/);
199
+ const jsonCandidate = jsonMatch ? jsonMatch[0] : text;
195
200
  try {
196
- const parsed = JSON.parse(text);
201
+ const parsed = JSON.parse(jsonCandidate);
197
202
  return {
198
203
  visualStyle: sanitizeGuideText(parsed.visualStyle ?? parsed.styleDescription ?? ""),
199
204
  subjectGuide: sanitizeGuideText(parsed.subjectGuide ?? parsed.coreInstruction ?? "")
200
205
  };
201
206
  } catch {
207
+ console.warn("Warning: analysis model returned non-JSON response; using raw text as visualStyle");
202
208
  return { visualStyle: sanitizeGuideText(text), subjectGuide: "" };
203
209
  }
204
210
  }
@@ -220,7 +226,8 @@ const BUILTIN_IMAGE_MODELS = [
220
226
  }
221
227
  ];
222
228
  const DEFAULT_MODEL = BUILTIN_IMAGE_MODELS[0].id;
223
- const SUPPORTED_IMAGE_COUNTS = [2, 4, 6];
229
+ const SIZE_PRESETS = ["1:1", "4:3", "3:2", "16:9", "4:5", "9:16"];
230
+ const SUPPORTED_IMAGE_COUNTS = [1, 2, 4, 6];
224
231
  const EXIT_CODES = {
225
232
  SUCCESS: 0,
226
233
  NOT_FOUND: 1,
@@ -385,14 +392,18 @@ function parseBoolean(input, key) {
385
392
  const QUICK_HELP = `image-sprout <command> [options]
386
393
 
387
394
  Commands:
388
- project Manage projects and generation workflow
389
- ref Manage project reference images
390
- session Inspect project sessions
391
- run Inspect saved runs
392
- model Manage available image models
393
- config Manage local configuration
394
- web Launch the interactive local web app
395
- help Show command help
395
+ project Manage projects and generation workflow
396
+ ref Manage project reference images
397
+ session Inspect project sessions
398
+ run Inspect saved runs
399
+ model Manage available image models
400
+ config Manage local configuration
401
+ web Launch the interactive local web app
402
+ help Show command help
403
+
404
+ Aliases:
405
+ generate Shorthand for: project generate
406
+ analyze Shorthand for: project derive
396
407
 
397
408
  Options:
398
409
  --json Output JSON
@@ -438,16 +449,18 @@ Alias for:
438
449
  const GENERATE_HELP = `image-sprout generate [--project <name-or-id>] --prompt <text>|--prompt-file <path> [options]
439
450
 
440
451
  Alias for:
441
- image-sprout project generate <project> --prompt <text>|--prompt-file <path> [--session <id>] [--feedback <text>] [--model <id>] [--size <16:9|1:1|9:16>] [--count <2|4|6>] [--force]`;
452
+ image-sprout project generate <project> --prompt <text>|--prompt-file <path> [--session <id>] [--feedback <text>] [--model <id>] [--size <1:1|4:3|3:2|16:9|4:5|9:16>] [--count <1|2|4|6>] [--force]`;
442
453
  const SESSION_HELP = `image-sprout session <subcommand> [options]
443
454
 
444
455
  Subcommands:
445
456
  list List sessions for a project
446
457
  show Show one session
458
+ delete Delete a session and its runs
447
459
 
448
460
  Examples:
449
461
  image-sprout session list --project comic-hero
450
- image-sprout session show --project comic-hero <session-id>`;
462
+ image-sprout session show --project comic-hero <session-id>
463
+ image-sprout session delete --project comic-hero <session-id>`;
451
464
  const RUN_HELP = `image-sprout run <subcommand> [options]
452
465
 
453
466
  Subcommands:
@@ -459,9 +472,13 @@ Examples:
459
472
  image-sprout run list --project comic-hero --limit 5
460
473
  image-sprout run latest --project comic-hero
461
474
  image-sprout run show --project comic-hero <run-id>`;
462
- const WEB_HELP = `image-sprout web [--port <number>]
475
+ const WEB_HELP = `image-sprout web [--port <number>] [--open]
476
+
477
+ Launch the interactive local web app against the shared on-disk project store.
463
478
 
464
- Launch the interactive local web app against the shared on-disk project store.`;
479
+ Options:
480
+ --port <number> Port to listen on (default: 4310)
481
+ --open Open the app in the default browser`;
465
482
  const MODELS_HELP = `image-sprout model <subcommand> [options]
466
483
 
467
484
  Subcommands:
@@ -784,7 +801,7 @@ function restoreDefaultModels() {
784
801
  writeRegistry(registry);
785
802
  return registry;
786
803
  }
787
- const CONFIG_KEYS = /* @__PURE__ */ new Set(["apiKey", "model", "sizePreset", "imageCount"]);
804
+ const CONFIG_KEYS = /* @__PURE__ */ new Set(["apiKey", "model", "sizePreset", "imageCount", "analysisModel"]);
788
805
  function defaultConfig() {
789
806
  return {
790
807
  apiKey: "",
@@ -825,9 +842,9 @@ function readConfig() {
825
842
  writeConfig(healed);
826
843
  return healed;
827
844
  }
828
- if (!["16:9", "1:1", "9:16"].includes(config.sizePreset)) {
845
+ if (!SIZE_PRESETS.includes(config.sizePreset)) {
829
846
  throw new CliError("CONFIG_ERROR", `Invalid configured sizePreset: ${String(config.sizePreset)}`, [
830
- "Use one of: 16:9, 1:1, 9:16"
847
+ `Use one of: ${SIZE_PRESETS.join(", ")}`
831
848
  ]);
832
849
  }
833
850
  if (!SUPPORTED_IMAGE_COUNTS.includes(config.imageCount)) {
@@ -856,7 +873,7 @@ function normalizeKey(input) {
856
873
  return mapped;
857
874
  }
858
875
  throw new CliError("INVALID_ARGS", `Unknown config key: ${input}`, [
859
- "Valid keys: apiKey, model, sizePreset, imageCount"
876
+ "Valid keys: apiKey, model, sizePreset, imageCount, analysisModel"
860
877
  ]);
861
878
  }
862
879
  function validateSetValue(key, rawValue) {
@@ -872,9 +889,9 @@ function validateSetValue(key, rawValue) {
872
889
  return rawValue;
873
890
  }
874
891
  case "sizePreset": {
875
- if (rawValue !== "16:9" && rawValue !== "1:1" && rawValue !== "9:16") {
892
+ if (!SIZE_PRESETS.includes(rawValue)) {
876
893
  throw new CliError("INVALID_ARGS", `Invalid size preset: ${rawValue}`, [
877
- "Use one of: 16:9, 1:1, 9:16"
894
+ `Use one of: ${SIZE_PRESETS.join(", ")}`
878
895
  ]);
879
896
  }
880
897
  return rawValue;
@@ -882,12 +899,19 @@ function validateSetValue(key, rawValue) {
882
899
  case "imageCount": {
883
900
  const value = Number(rawValue);
884
901
  if (!SUPPORTED_IMAGE_COUNTS.includes(value)) {
885
- throw new CliError("INVALID_ARGS", "imageCount must be one of: 2, 4, 6", [
902
+ throw new CliError("INVALID_ARGS", `imageCount must be one of: ${SUPPORTED_IMAGE_COUNTS.join(", ")}`, [
886
903
  "Example: image-sprout config set imageCount 4"
887
904
  ]);
888
905
  }
889
906
  return value;
890
907
  }
908
+ case "analysisModel": {
909
+ const trimmed = rawValue.trim();
910
+ if (!trimmed) {
911
+ throw new CliError("INVALID_ARGS", "analysisModel must be a non-empty model ID");
912
+ }
913
+ return trimmed;
914
+ }
891
915
  default:
892
916
  throw new CliError("INVALID_ARGS", `Unsupported config key: ${String(key)}`);
893
917
  }
@@ -903,7 +927,8 @@ function publicConfig(config) {
903
927
  apiKeyConfigured: config.apiKey.trim().length > 0,
904
928
  model: config.model,
905
929
  sizePreset: config.sizePreset,
906
- imageCount: config.imageCount
930
+ imageCount: config.imageCount,
931
+ ...config.analysisModel ? { analysisModel: config.analysisModel } : {}
907
932
  };
908
933
  }
909
934
  function updateConfig(changes) {
@@ -1666,10 +1691,18 @@ function sendJson(res, status, payload) {
1666
1691
  res.writeHead(status, { "Content-Type": "application/json" });
1667
1692
  res.end(JSON.stringify(payload));
1668
1693
  }
1694
+ const CLI_ERROR_TO_HTTP = {
1695
+ NOT_FOUND: 404,
1696
+ AUTH_REQUIRED: 401,
1697
+ API_ERROR: 502,
1698
+ IO_ERROR: 500,
1699
+ INTERNAL_ERROR: 500,
1700
+ PROJECT_NOT_READY: 409
1701
+ };
1669
1702
  function toApiErrorResponse(error) {
1670
1703
  if (error instanceof CliError) {
1671
1704
  return {
1672
- status: error.exitCode === 1 ? 404 : 400,
1705
+ status: CLI_ERROR_TO_HTTP[error.code] ?? 400,
1673
1706
  payload: {
1674
1707
  error: {
1675
1708
  code: error.code,
@@ -1961,6 +1994,7 @@ async function routeApiRequest(method, urlInput, body = {}) {
1961
1994
  const requestBody = body;
1962
1995
  const target = parseTarget(requestBody.target);
1963
1996
  const persist = requestBody.persist !== false;
1997
+ const analysisModel = config.analysisModel;
1964
1998
  const styleRefs = target === "subject" ? [] : getProjectReferenceDataUrlsByTarget(projectId, "style");
1965
1999
  const subjectRefs = target === "style" ? [] : getProjectReferenceDataUrlsByTarget(projectId, "subject");
1966
2000
  if (target === "both" && (styleRefs.length === 0 || subjectRefs.length === 0)) {
@@ -1975,18 +2009,22 @@ async function routeApiRequest(method, urlInput, body = {}) {
1975
2009
  let visualStyle;
1976
2010
  let subjectGuide;
1977
2011
  if (target === "both" && JSON.stringify(styleRefs) === JSON.stringify(subjectRefs)) {
1978
- const result = await analyzeReferenceImages(styleRefs, apiKey);
2012
+ const result = await analyzeReferenceImages(styleRefs, apiKey, void 0, analysisModel);
1979
2013
  visualStyle = result.visualStyle;
1980
2014
  subjectGuide = result.subjectGuide;
2015
+ } else if (target === "both") {
2016
+ const [styleResult, subjectResult] = await Promise.all([
2017
+ analyzeReferenceImages(styleRefs, apiKey, void 0, analysisModel),
2018
+ analyzeReferenceImages(subjectRefs, apiKey, void 0, analysisModel)
2019
+ ]);
2020
+ visualStyle = styleResult.visualStyle;
2021
+ subjectGuide = subjectResult.subjectGuide;
2022
+ } else if (target === "style") {
2023
+ const result = await analyzeReferenceImages(styleRefs, apiKey, void 0, analysisModel);
2024
+ visualStyle = result.visualStyle;
1981
2025
  } else {
1982
- if (target === "style" || target === "both") {
1983
- const result = await analyzeReferenceImages(styleRefs, apiKey);
1984
- visualStyle = result.visualStyle;
1985
- }
1986
- if (target === "subject" || target === "both") {
1987
- const result = await analyzeReferenceImages(subjectRefs, apiKey);
1988
- subjectGuide = result.subjectGuide;
1989
- }
2026
+ const result = await analyzeReferenceImages(subjectRefs, apiKey, void 0, analysisModel);
2027
+ subjectGuide = result.subjectGuide;
1990
2028
  }
1991
2029
  if (persist) {
1992
2030
  updateProjectGuides(projectId, {
@@ -1994,7 +2032,7 @@ async function routeApiRequest(method, urlInput, body = {}) {
1994
2032
  ...subjectGuide !== void 0 ? { subjectGuide } : {}
1995
2033
  });
1996
2034
  }
1997
- const status = persist ? getProjectStatus(projectId) : getProjectStatus(projectId);
2035
+ const status = getProjectStatus(projectId);
1998
2036
  const project = showProject(projectId);
1999
2037
  return {
2000
2038
  status: 200,
@@ -2121,8 +2159,8 @@ async function startWebServer(options = {}) {
2121
2159
  }
2122
2160
  const GLOBAL_OPTIONS = /* @__PURE__ */ new Set(["json", "text", "help", "version", "value", "ids", "limit"]);
2123
2161
  function resolveVersion() {
2124
- if ("1.0.1".length > 0) {
2125
- return "1.0.1";
2162
+ if ("1.2.0".length > 0) {
2163
+ return "1.2.0";
2126
2164
  }
2127
2165
  return process.env.npm_package_version ?? "0.0.0";
2128
2166
  }
@@ -2304,10 +2342,10 @@ function parseSize(input, fallback) {
2304
2342
  if (!input) {
2305
2343
  return fallback;
2306
2344
  }
2307
- if (input === "16:9" || input === "1:1" || input === "9:16") {
2345
+ if (SIZE_PRESETS.includes(input)) {
2308
2346
  return input;
2309
2347
  }
2310
- throw new CliError("INVALID_ARGS", `Invalid size: ${input}`, ["Use one of: 16:9, 1:1, 9:16"]);
2348
+ throw new CliError("INVALID_ARGS", `Invalid size: ${input}`, [`Use one of: ${SIZE_PRESETS.join(", ")}`]);
2311
2349
  }
2312
2350
  function parseCount(input, fallback) {
2313
2351
  if (!input) {
@@ -2315,7 +2353,7 @@ function parseCount(input, fallback) {
2315
2353
  }
2316
2354
  const value = Number(input);
2317
2355
  if (!SUPPORTED_IMAGE_COUNTS.includes(value)) {
2318
- throw new CliError("INVALID_ARGS", "count must be one of: 2, 4, 6", [
2356
+ throw new CliError("INVALID_ARGS", `count must be one of: ${SUPPORTED_IMAGE_COUNTS.join(", ")}`, [
2319
2357
  "Example: image-sprout generate --count 4 ..."
2320
2358
  ]);
2321
2359
  }
@@ -2608,10 +2646,12 @@ function runRef(ctx, args, positionals) {
2608
2646
  }
2609
2647
  }
2610
2648
  async function runProjectDerive(ctx, args, projectInput) {
2611
- assertOnlyOptions(args, /* @__PURE__ */ new Set(["project", "api-key", "target"]));
2649
+ assertOnlyOptions(args, /* @__PURE__ */ new Set(["project", "api-key", "target", "analysis-model"]));
2650
+ const config = readConfig();
2612
2651
  const projectId = resolveProjectId(projectInput ?? projectFlag(args));
2613
2652
  const apiKey = requireApiKey(getStringOption(args, "api-key"));
2614
2653
  const target = parseDeriveTarget(getStringOption(args, "target"));
2654
+ const analysisModel = getStringOption(args, "analysis-model") ?? config.analysisModel;
2615
2655
  const styleRefDataUrls = target === "subject" ? [] : getProjectReferenceDataUrlsByTarget(projectId, "style");
2616
2656
  const subjectRefDataUrls = target === "style" ? [] : getProjectReferenceDataUrlsByTarget(projectId, "subject");
2617
2657
  if (target === "style" && styleRefDataUrls.length === 0) {
@@ -2636,18 +2676,22 @@ async function runProjectDerive(ctx, args, projectInput) {
2636
2676
  let nextStyle;
2637
2677
  let nextSubject;
2638
2678
  if (target === "both" && JSON.stringify(styleRefDataUrls) === JSON.stringify(subjectRefDataUrls)) {
2639
- const analysis = await analyzeReferenceImages(styleRefDataUrls, apiKey);
2679
+ const analysis = await analyzeReferenceImages(styleRefDataUrls, apiKey, void 0, analysisModel);
2640
2680
  nextStyle = analysis.visualStyle;
2641
2681
  nextSubject = analysis.subjectGuide;
2682
+ } else if (target === "both") {
2683
+ const [styleAnalysis, subjectAnalysis] = await Promise.all([
2684
+ analyzeReferenceImages(styleRefDataUrls, apiKey, void 0, analysisModel),
2685
+ analyzeReferenceImages(subjectRefDataUrls, apiKey, void 0, analysisModel)
2686
+ ]);
2687
+ nextStyle = styleAnalysis.visualStyle;
2688
+ nextSubject = subjectAnalysis.subjectGuide;
2689
+ } else if (target === "style") {
2690
+ const analysis = await analyzeReferenceImages(styleRefDataUrls, apiKey, void 0, analysisModel);
2691
+ nextStyle = analysis.visualStyle;
2642
2692
  } else {
2643
- if (target === "style" || target === "both") {
2644
- const analysis = await analyzeReferenceImages(styleRefDataUrls, apiKey);
2645
- nextStyle = analysis.visualStyle;
2646
- }
2647
- if (target === "subject" || target === "both") {
2648
- const analysis = await analyzeReferenceImages(subjectRefDataUrls, apiKey);
2649
- nextSubject = analysis.subjectGuide;
2650
- }
2693
+ const analysis = await analyzeReferenceImages(subjectRefDataUrls, apiKey, void 0, analysisModel);
2694
+ nextSubject = analysis.subjectGuide;
2651
2695
  }
2652
2696
  updateProjectGuides(projectId, {
2653
2697
  ...nextStyle !== void 0 ? { visualStyle: nextStyle } : {},
@@ -2758,7 +2802,7 @@ async function runProjectGenerate(ctx, args, projectInput) {
2758
2802
  function runSessions(ctx, args, positionals) {
2759
2803
  assertOnlyOptions(args, /* @__PURE__ */ new Set(["project"]));
2760
2804
  const projectId = resolveProjectId(projectFlag(args));
2761
- const sub = requireSubcommand("session", positionals[1] ?? "list", ["list", "show"]);
2805
+ const sub = requireSubcommand("session", positionals[1] ?? "list", ["list", "show", "delete"]);
2762
2806
  switch (sub) {
2763
2807
  case "list": {
2764
2808
  const data = limitItems(listSessions(projectId), ctx);
@@ -2787,6 +2831,15 @@ function runSessions(ctx, args, positionals) {
2787
2831
  });
2788
2832
  return;
2789
2833
  }
2834
+ case "delete": {
2835
+ const sessionId = positionals[2];
2836
+ if (!sessionId) {
2837
+ throw new CliError("INVALID_ARGS", "session delete requires <session-id>");
2838
+ }
2839
+ deleteSession(projectId, sessionId);
2840
+ emitSuccess(ctx, { projectId, sessionId }, (payload) => `ok project=${payload.projectId} deleted=${payload.sessionId}`);
2841
+ return;
2842
+ }
2790
2843
  }
2791
2844
  }
2792
2845
  function runRuns(ctx, args, positionals) {
@@ -2944,13 +2997,17 @@ function runConfig(ctx, args, positionals) {
2944
2997
  config: data
2945
2998
  },
2946
2999
  (payload) => {
2947
- return [
3000
+ const lines = [
2948
3001
  `ok path=${payload.path}`,
2949
3002
  `apiKey=${payload.config.apiKeyConfigured ? "[set]" : "[empty]"}`,
2950
3003
  `model=${payload.config.model}`,
2951
3004
  `sizePreset=${payload.config.sizePreset}`,
2952
3005
  `imageCount=${payload.config.imageCount}`
2953
- ].join("\n");
3006
+ ];
3007
+ if (payload.config.analysisModel) {
3008
+ lines.push(`analysisModel=${payload.config.analysisModel}`);
3009
+ }
3010
+ return lines.join("\n");
2954
3011
  }
2955
3012
  );
2956
3013
  return;
@@ -3021,14 +3078,24 @@ function runHelp(ctx, target) {
3021
3078
  function runVersion(ctx) {
3022
3079
  emitSuccess(ctx, { version: ctx.version }, (payload) => payload.version);
3023
3080
  }
3081
+ async function openInBrowser(url) {
3082
+ const { platform } = process;
3083
+ const { exec } = await import("node:child_process");
3084
+ const cmd = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
3085
+ exec(`${cmd} ${url}`);
3086
+ }
3024
3087
  async function runWeb(ctx, args) {
3025
- assertOnlyOptions(args, /* @__PURE__ */ new Set(["port"]));
3088
+ assertOnlyOptions(args, /* @__PURE__ */ new Set(["port", "open"]));
3026
3089
  const rawPort = getStringOption(args, "port");
3027
3090
  const parsedPort = rawPort ? Number(rawPort) : void 0;
3028
3091
  if (rawPort && (parsedPort === void 0 || !Number.isInteger(parsedPort) || parsedPort < 1 || parsedPort > 65535)) {
3029
3092
  throw new CliError("INVALID_ARGS", `Invalid port: ${rawPort}`);
3030
3093
  }
3094
+ const shouldOpen = getBooleanOption(args, "open") === true;
3031
3095
  const server = await startWebServer({ port: parsedPort });
3096
+ if (shouldOpen) {
3097
+ await openInBrowser(server.url);
3098
+ }
3032
3099
  emitSuccess(ctx, server, (payload) => `ok url=${payload.url}`);
3033
3100
  }
3034
3101
  async function dispatch(args, ctx) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "image-sprout",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "image-sprout": "dist/cli/index.js"
@@ -8,6 +8,10 @@
8
8
  "files": [
9
9
  "dist/"
10
10
  ],
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/tmchow/image-sprout"
14
+ },
11
15
  "publishConfig": {
12
16
  "access": "public"
13
17
  },
@@ -1 +0,0 @@
1
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:"Inter", ui-sans-serif, system-ui, sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-green-300:oklch(87.1% .15 154.449);--color-emerald-700:oklch(50.8% .118 165.612);--color-sky-50:oklch(97.7% .013 236.62);--color-sky-400:oklch(74.6% .16 232.661);--color-indigo-50:oklch(96.2% .018 272.314);--color-indigo-100:oklch(93% .034 272.788);--color-indigo-200:oklch(87% .065 274.039);--color-indigo-500:oklch(58.5% .233 277.117);--color-indigo-600:oklch(51.1% .262 276.966);--color-indigo-700:oklch(45.7% .24 277.023);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-slate-950:oklch(12.9% .042 264.695);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--container-3xl:48rem;--container-4xl:56rem;--container-5xl:64rem;--container-6xl:72rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-accent-50:#eef2ff;--color-accent-500:#6366f1;--color-accent-600:#4f46e5;--color-accent-700:#4338ca}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-2{top:calc(var(--spacing) * 2)}.top-3{top:calc(var(--spacing) * 3)}.right-0{right:calc(var(--spacing) * 0)}.right-1\.5{right:calc(var(--spacing) * 1.5)}.right-2{right:calc(var(--spacing) * 2)}.right-3{right:calc(var(--spacing) * 3)}.bottom-0{bottom:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.left-2{left:calc(var(--spacing) * 2)}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.z-\[60\]{z-index:60}.z-\[70\]{z-index:70}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-auto{margin-right:auto}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.aspect-square{aspect-ratio:1}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-\[44px\]{height:44px}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-\[80vh\]{max-height:80vh}.max-h-\[85vh\]{max-height:85vh}.max-h-\[88vh\]{max-height:88vh}.max-h-\[90vh\]{max-height:90vh}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-10{min-height:calc(var(--spacing) * 10)}.min-h-28{min-height:calc(var(--spacing) * 28)}.min-h-44{min-height:calc(var(--spacing) * 44)}.min-h-screen{min-height:100vh}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-32{width:calc(var(--spacing) * 32)}.w-44{width:calc(var(--spacing) * 44)}.w-auto{width:auto}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-64{max-width:calc(var(--spacing) * 64)}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.rotate-180{rotate:180deg}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.resize-y{resize:vertical}.appearance-none{appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}.self-start{align-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\[4px\]{border-radius:4px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-b-xl{border-bottom-right-radius:var(--radius-xl);border-bottom-left-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-r-2{border-right-style:var(--tw-border-style);border-right-width:2px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent-500{border-color:var(--color-accent-500)}.border-amber-200{border-color:var(--color-amber-200)}.border-amber-400{border-color:var(--color-amber-400)}.border-indigo-200{border-color:var(--color-indigo-200)}.border-indigo-500{border-color:var(--color-indigo-500)}.border-red-200{border-color:var(--color-red-200)}.border-sky-400{border-color:var(--color-sky-400)}.border-slate-100{border-color:var(--color-slate-100)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-300{border-color:var(--color-slate-300)}.border-t-indigo-600{border-top-color:var(--color-indigo-600)}.bg-accent-50{background-color:var(--color-accent-50)}.bg-accent-600{background-color:var(--color-accent-600)}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-50\/70{background-color:#fffbebb3}@supports (color:color-mix(in lab,red,red)){.bg-amber-50\/70{background-color:color-mix(in oklab,var(--color-amber-50) 70%,transparent)}}.bg-amber-600{background-color:var(--color-amber-600)}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab,red,red)){.bg-black\/40{background-color:color-mix(in oklab,var(--color-black) 40%,transparent)}}.bg-black\/45{background-color:#00000073}@supports (color:color-mix(in lab,red,red)){.bg-black\/45{background-color:color-mix(in oklab,var(--color-black) 45%,transparent)}}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab,red,red)){.bg-black\/50{background-color:color-mix(in oklab,var(--color-black) 50%,transparent)}}.bg-black\/60{background-color:#0009}@supports (color:color-mix(in lab,red,red)){.bg-black\/60{background-color:color-mix(in oklab,var(--color-black) 60%,transparent)}}.bg-black\/70{background-color:#000000b3}@supports (color:color-mix(in lab,red,red)){.bg-black\/70{background-color:color-mix(in oklab,var(--color-black) 70%,transparent)}}.bg-indigo-50{background-color:var(--color-indigo-50)}.bg-indigo-100{background-color:var(--color-indigo-100)}.bg-indigo-600{background-color:var(--color-indigo-600)}.bg-red-100{background-color:var(--color-red-100)}.bg-sky-50\/80{background-color:#f0f9ffcc}@supports (color:color-mix(in lab,red,red)){.bg-sky-50\/80{background-color:color-mix(in oklab,var(--color-sky-50) 80%,transparent)}}.bg-slate-50{background-color:var(--color-slate-50)}.bg-slate-100{background-color:var(--color-slate-100)}.bg-slate-200{background-color:var(--color-slate-200)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-slate-950{background-color:var(--color-slate-950)}.bg-slate-950\/75{background-color:#020618bf}@supports (color:color-mix(in lab,red,red)){.bg-slate-950\/75{background-color:color-mix(in oklab,var(--color-slate-950) 75%,transparent)}}.bg-white{background-color:var(--color-white)}.bg-white\/20{background-color:#fff3}@supports (color:color-mix(in lab,red,red)){.bg-white\/20{background-color:color-mix(in oklab,var(--color-white) 20%,transparent)}}.bg-white\/80{background-color:#fffc}@supports (color:color-mix(in lab,red,red)){.bg-white\/80{background-color:color-mix(in oklab,var(--color-white) 80%,transparent)}}.bg-white\/90{background-color:#ffffffe6}@supports (color:color-mix(in lab,red,red)){.bg-white\/90{background-color:color-mix(in oklab,var(--color-white) 90%,transparent)}}.bg-white\/96{background-color:#fffffff5}@supports (color:color-mix(in lab,red,red)){.bg-white\/96{background-color:color-mix(in oklab,var(--color-white) 96%,transparent)}}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-\[linear-gradient\(180deg\,\#fffdf7_0\%\,\#ffffff_18\%\,\#f8fafc_100\%\)\]{background-image:linear-gradient(#fffdf7,#fff 18%,#f8fafc)}.bg-\[url\(\'data\:image\/svg\+xml\;charset\=utf-8\,\%3Csvg\%20xmlns\%3D\%22http\%3A\%2F\%2Fwww\.w3\.org\%2F2000\%2Fsvg\%22\%20width\%3D\%2212\%22\%20height\%3D\%2212\%22\%20viewBox\%3D\%220\%200\%2024\%2024\%22\%20fill\%3D\%22none\%22\%20stroke\%3D\%22\%2364748b\%22\%20stroke-width\%3D\%222\%22\%3E\%3Cpath\%20d\%3D\%22M6\%209l6\%206\%206-6\%22\%2F\%3E\%3C\%2Fsvg\%3E\'\)\]{background-image:url(data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2212%22%20height%3D%2212%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%2364748b%22%20stroke-width%3D%222%22%3E%3Cpath%20d%3D%22M6%209l6%206%206-6%22%2F%3E%3C%2Fsvg%3E)}.from-slate-200{--tw-gradient-from:var(--color-slate-200);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.via-slate-100{--tw-gradient-via:var(--color-slate-100);--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.to-slate-200{--tw-gradient-to:var(--color-slate-200);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.bg-\[length\:12px\]{background-size:12px}.bg-\[right_8px_center\]{background-position:right 8px center}.bg-no-repeat{background-repeat:no-repeat}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-1{padding:calc(var(--spacing) * 1)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pr-6{padding-right:calc(var(--spacing) * 6)}.pb-1{padding-bottom:calc(var(--spacing) * 1)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.14em\]{--tw-tracking:.14em;letter-spacing:.14em}.tracking-\[0\.16em\]{--tw-tracking:.16em;letter-spacing:.16em}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent-600{color:var(--color-accent-600)}.text-amber-600{color:var(--color-amber-600)}.text-amber-700{color:var(--color-amber-700)}.text-amber-800{color:var(--color-amber-800)}.text-emerald-700{color:var(--color-emerald-700)}.text-green-300{color:var(--color-green-300)}.text-indigo-600{color:var(--color-indigo-600)}.text-indigo-700{color:var(--color-indigo-700)}.text-red-300{color:var(--color-red-300)}.text-red-600{color:var(--color-red-600)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-slate-700{color:var(--color-slate-700)}.text-slate-800{color:var(--color-slate-800)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.decoration-amber-300{-webkit-text-decoration-color:var(--color-amber-300);text-decoration-color:var(--color-amber-300)}.underline-offset-2{text-underline-offset:2px}.placeholder-slate-400::placeholder{color:var(--color-slate-400)}.opacity-0{opacity:0}.opacity-45{opacity:.45}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring,.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-indigo-600{--tw-ring-color:var(--color-indigo-600)}.ring-slate-200{--tw-ring-color:var(--color-slate-200)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.select-none{-webkit-user-select:none;user-select:none}.group-focus-within\:opacity-100:is(:where(.group):focus-within *){opacity:1}@media(hover:hover){.group-hover\:text-slate-700:is(:where(.group):hover *){color:var(--color-slate-700)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-slate-400::placeholder{color:var(--color-slate-400)}@media(hover:hover){.hover\:border-amber-400:hover{border-color:var(--color-amber-400)}.hover\:bg-accent-700:hover{background-color:var(--color-accent-700)}.hover\:bg-amber-700:hover{background-color:var(--color-amber-700)}.hover\:bg-black\/70:hover{background-color:#000000b3}@supports (color:color-mix(in lab,red,red)){.hover\:bg-black\/70:hover{background-color:color-mix(in oklab,var(--color-black) 70%,transparent)}}.hover\:bg-indigo-50:hover{background-color:var(--color-indigo-50)}.hover\:bg-indigo-700:hover{background-color:var(--color-indigo-700)}.hover\:bg-red-50:hover{background-color:var(--color-red-50)}.hover\:bg-slate-50:hover{background-color:var(--color-slate-50)}.hover\:bg-slate-100:hover{background-color:var(--color-slate-100)}.hover\:bg-slate-300:hover{background-color:var(--color-slate-300)}.hover\:bg-slate-800:hover{background-color:var(--color-slate-800)}.hover\:bg-white:hover{background-color:var(--color-white)}.hover\:bg-white\/40:hover{background-color:#fff6}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/40:hover{background-color:color-mix(in oklab,var(--color-white) 40%,transparent)}}.hover\:text-accent-600:hover{color:var(--color-accent-600)}.hover\:text-accent-700:hover{color:var(--color-accent-700)}.hover\:text-amber-600:hover{color:var(--color-amber-600)}.hover\:text-amber-900:hover{color:var(--color-amber-900)}.hover\:text-red-500:hover{color:var(--color-red-500)}.hover\:text-red-600:hover{color:var(--color-red-600)}.hover\:text-red-700:hover{color:var(--color-red-700)}.hover\:text-slate-600:hover{color:var(--color-slate-600)}.hover\:text-slate-700:hover{color:var(--color-slate-700)}.hover\:text-slate-800:hover{color:var(--color-slate-800)}}.focus\:border-amber-500:focus{border-color:var(--color-amber-500)}.focus\:border-indigo-500:focus{border-color:var(--color-indigo-500)}.focus\:border-transparent:focus{border-color:#0000}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-accent-500:focus{--tw-ring-color:var(--color-accent-500)}.focus\:ring-amber-500:focus{--tw-ring-color:var(--color-amber-500)}.focus\:ring-indigo-500:focus{--tw-ring-color:var(--color-indigo-500)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}@media(min-width:40rem){.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(min-width:48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-\[1\.8fr_1fr_auto\]{grid-template-columns:1.8fr 1fr auto}}@media(min-width:64rem){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media(min-width:80rem){.xl\:col-span-2{grid-column:span 2/span 2}.xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}body{font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0}#app{width:100%;min-height:100vh}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}