failproofai 0.0.2-beta.2 → 0.0.2-beta.4

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.
Files changed (130) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  9. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  10. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  12. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  18. package/.next/standalone/.next/server/app/_not-found.rsc +17 -17
  19. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +17 -17
  20. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  21. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +11 -11
  22. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  24. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  25. package/.next/standalone/.next/server/app/index.html +1 -1
  26. package/.next/standalone/.next/server/app/index.rsc +16 -16
  27. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  28. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -16
  29. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  30. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +11 -11
  31. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  32. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  33. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  35. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  36. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  38. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  39. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  42. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  43. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  46. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/chunks/[root-of-the-server]__02nt~6d._.js +1 -1
  49. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
  50. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0103jwf._.js → [root-of-the-server]__05ib_c3._.js} +2 -2
  51. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
  52. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
  53. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
  54. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
  55. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ovwjau._.js → [root-of-the-server]__0od~yp1._.js} +2 -2
  56. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0okos0k._.js +2 -2
  57. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +5 -5
  58. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
  59. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
  60. package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +1 -1
  61. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
  62. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +1 -1
  63. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  64. package/.next/standalone/.next/server/pages/404.html +2 -2
  65. package/.next/standalone/.next/server/pages/500.html +1 -1
  66. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
  68. package/.next/standalone/.next/static/chunks/{0sm1iqi3m~xiz.js → 03qghe4e2_.ul.js} +1 -1
  69. package/.next/standalone/.next/static/chunks/{0jrzwsyo7wo26.js → 0_eej2~ju.yds.js} +1 -1
  70. package/.next/standalone/.next/static/chunks/{0tl2f-3yc.rqc.js → 0bc69j4t8njpq.js} +1 -1
  71. package/.next/standalone/.next/static/chunks/0nnxt7uoz_cvj.css +1 -0
  72. package/.next/standalone/.next/static/chunks/{0uftmw5od9kdz.js → 0qaojcc.nvqd8.js} +1 -1
  73. package/.next/standalone/.next/static/chunks/{001k0zayn2o.s.js → 0xg4wy053mmhs.js} +1 -1
  74. package/.next/standalone/.next/static/chunks/{0pdd7~yp8ytu6.js → 12mgwr8gh_kqo.js} +2 -2
  75. package/.next/standalone/.next/static/chunks/{0tbr0o7vwc~-s.js → 134~t05vpu75e.js} +1 -1
  76. package/.next/standalone/.next/static/chunks/{0wtcha31~i7rm.js → 17veghz_js0u3.js} +1 -1
  77. package/.next/standalone/Dockerfile.docs +12 -0
  78. package/.next/standalone/README.md +59 -46
  79. package/.next/standalone/app/components/session-hooks-panel.tsx +31 -6
  80. package/.next/standalone/app/policies/hooks-client.tsx +31 -6
  81. package/.next/standalone/dist/cli.mjs +234 -27
  82. package/.next/standalone/dist/index.js +2 -2
  83. package/.next/standalone/docs/{architecture.md → architecture.mdx} +40 -23
  84. package/.next/standalone/docs/{built-in-policies.md → built-in-policies.mdx} +134 -12
  85. package/.next/standalone/docs/cli/dashboard.mdx +28 -0
  86. package/.next/standalone/docs/cli/environment-variables.mdx +34 -0
  87. package/.next/standalone/docs/cli/hook.mdx +30 -0
  88. package/.next/standalone/docs/cli/install-policies.mdx +48 -0
  89. package/.next/standalone/docs/cli/list-policies.mdx +31 -0
  90. package/.next/standalone/docs/cli/remove-policies.mdx +44 -0
  91. package/.next/standalone/docs/cli/version.mdx +12 -0
  92. package/.next/standalone/docs/{configuration.md → configuration.mdx} +16 -16
  93. package/.next/standalone/docs/{custom-hooks.md → custom-policies.mdx} +80 -42
  94. package/.next/standalone/docs/{dashboard.md → dashboard.mdx} +26 -29
  95. package/.next/standalone/docs/docs.json +31 -4
  96. package/.next/standalone/docs/examples.mdx +253 -0
  97. package/.next/standalone/docs/for-agents.mdx +38 -0
  98. package/.next/standalone/docs/getting-started.mdx +134 -0
  99. package/.next/standalone/docs/introduction.mdx +57 -0
  100. package/.next/standalone/docs/logo/dark.svg +21 -0
  101. package/.next/standalone/docs/logo/light.svg +21 -0
  102. package/.next/standalone/docs/{package-aliases.md → package-aliases.mdx} +5 -5
  103. package/.next/standalone/docs/{testing.md → testing.mdx} +11 -11
  104. package/.next/standalone/package.json +6 -9
  105. package/.next/standalone/scripts/publish-aliases.mjs +4 -2
  106. package/.next/standalone/skills-lock.json +10 -0
  107. package/.next/standalone/src/hooks/builtin-policies.ts +271 -25
  108. package/.next/standalone/src/hooks/handler.ts +1 -0
  109. package/.next/standalone/src/hooks/hook-activity-store.ts +6 -1
  110. package/.next/standalone/src/hooks/policy-evaluator.ts +23 -2
  111. package/.next/standalone/src/hooks/policy-helpers.ts +2 -2
  112. package/.next/standalone/vitest.config.e2e.mts +3 -0
  113. package/.next/standalone/vitest.config.mts +3 -0
  114. package/README.md +59 -46
  115. package/dist/cli.mjs +234 -27
  116. package/dist/index.js +2 -2
  117. package/package.json +6 -9
  118. package/scripts/publish-aliases.mjs +4 -2
  119. package/src/hooks/builtin-policies.ts +271 -25
  120. package/src/hooks/handler.ts +1 -0
  121. package/src/hooks/hook-activity-store.ts +6 -1
  122. package/src/hooks/policy-evaluator.ts +23 -2
  123. package/src/hooks/policy-helpers.ts +2 -2
  124. package/.next/standalone/.next/static/chunks/15jpradyu_531.css +0 -1
  125. package/.next/standalone/docs/cli-reference.md +0 -175
  126. package/.next/standalone/docs/getting-started.md +0 -128
  127. package/.next/standalone/docs/introduction.md +0 -47
  128. /package/.next/standalone/.next/static/{JksWDLwDoPy6bcczVWlff → N7CmoNJD3b7hE1pCaP_Gs}/_buildManifest.js +0 -0
  129. /package/.next/standalone/.next/static/{JksWDLwDoPy6bcczVWlff → N7CmoNJD3b7hE1pCaP_Gs}/_clientMiddlewareManifest.js +0 -0
  130. /package/.next/standalone/.next/static/{JksWDLwDoPy6bcczVWlff → N7CmoNJD3b7hE1pCaP_Gs}/_ssgManifest.js +0 -0
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { resolve, join } from "node:path";
5
5
  import { readFile, writeFile, stat, open } from "node:fs/promises";
6
- import { execSync } from "node:child_process";
6
+ import { execSync, execFileSync } from "node:child_process";
7
7
  import { homedir } from "node:os";
8
8
  import type { BuiltinPolicyDefinition, PolicyContext, PolicyResult, PolicyParamsSchema } from "./policy-types";
9
9
  import { allow, deny, instruct } from "./policy-helpers";
@@ -86,7 +86,7 @@ const PUBLISH_CMD_RE = /(?:npm\s+publish|bun\s+publish|pnpm\s+publish|yarn\s+npm
86
86
 
87
87
  // protectEnvVars
88
88
  const ENV_PRINTENV_RE = /(?:^|\s|;|&&|\|\|)(?:env|printenv)(?:\s|$|;|&&|\|)/;
89
- const ECHO_ENV_RE = /echo\s+.*\$[A-Za-z_]/;
89
+ const ECHO_ENV_RE = /echo\s+.*\$\{?[A-Za-z_]/;
90
90
  const EXPORT_RE = /(?:^|\s|;|&&|\|\|)export\s+\w+/;
91
91
  const PS_ENV_VAR_RE = /\$env:[A-Za-z_]/i;
92
92
  const PS_CHILDITEM_ENV_RE = /(?:Get-ChildItem|dir|gci|ls)\s+Env:/i;
@@ -103,7 +103,7 @@ const PS_ELEVATION_RE = /Start-Process\s+.*-Verb\s+RunAs/i;
103
103
  const RUNAS_RE = /(?:^|;|&&|\|\|)\s*runas\s/i;
104
104
 
105
105
  // blockCurlPipeSh
106
- const CURL_PIPE_SH_RE = /(?:curl|wget)\s.*\|\s*(?:sh|bash|zsh)/;
106
+ const CURL_PIPE_SH_RE = /(?:curl|wget)\s.*\|\s*(?:sh|bash|zsh|dash|ksh|csh|tcsh|fish|ash)\b/;
107
107
  const PS_WEB_PIPE_RE = /(?:Invoke-WebRequest|iwr|Invoke-RestMethod|irm)\s+.*\|\s*(?:Invoke-Expression|iex)/i;
108
108
 
109
109
  // blockForcePush
@@ -145,12 +145,29 @@ const TMUX_DETACH_RE = /\btmux\s+(?:new-session|new)\b[^|&;]*-d\b/;
145
145
  const DISOWN_RE = /\bdisown\b/;
146
146
  const BACKGROUND_AMPERSAND_RE = /(?<![&|])\s?&\s*(?:$|#|;)/;
147
147
 
148
- // blockWorkOnMain: caches the current branch per cwd to avoid repeated execSync calls.
148
+ // Caches the current branch per cwd to avoid repeated execSync calls.
149
149
  // Trade-off: if the user switches branches externally mid-session, the cache serves
150
150
  // the stale value until the process restarts. This is acceptable since branch switches
151
151
  // during an active Claude session are rare.
152
152
  const gitBranchCache = new Map<string, string>();
153
153
 
154
+ function getCurrentBranch(cwd: string): string | null {
155
+ try {
156
+ let branch = gitBranchCache.get(cwd);
157
+ if (branch === undefined) {
158
+ branch = execSync("git rev-parse --abbrev-ref HEAD", {
159
+ cwd,
160
+ encoding: "utf8",
161
+ timeout: 3000,
162
+ }).trim();
163
+ gitBranchCache.set(cwd, branch);
164
+ }
165
+ return branch || null;
166
+ } catch {
167
+ return null;
168
+ }
169
+ }
170
+
154
171
  /**
155
172
  * Check if a command matches an allow pattern using token-by-token comparison.
156
173
  * The "*" token is a wildcard. Extra command tokens beyond the pattern are allowed,
@@ -423,7 +440,8 @@ function rmTargetIsAllowed(cmd: string, allowPaths: string[]): boolean {
423
440
  if (rmIdx < 0) continue;
424
441
  // Only validate recursive rm segments — non-recursive rm has no catastrophic-deletion risk
425
442
  const flagTokens = tokens.slice(rmIdx + 1).filter((t) => /^-[^-]/.test(t));
426
- if (!/r/i.test(flagTokens.join(""))) continue;
443
+ const longFlagsInSeg = tokens.slice(rmIdx + 1).filter((t) => /^--/.test(t));
444
+ if (!/r/i.test(flagTokens.join("")) && !longFlagsInSeg.some(f => /^--recursive$/i.test(f))) continue;
427
445
  const pathArgs = tokens.slice(rmIdx + 1).filter((t) => !t.startsWith("-"));
428
446
  for (const target of pathArgs) {
429
447
  const normalized = target.replace(/\/\*$/, "").replace(/\/+$/, "") || "/";
@@ -448,7 +466,10 @@ function rmTargetIsAllowed(cmd: string, allowPaths: string[]): boolean {
448
466
  function blockRmRf(ctx: PolicyContext): PolicyResult {
449
467
  if (ctx.toolName !== "Bash") return allow();
450
468
  const cmd = getCommand(ctx);
451
- const hasDestructivePath = /(?:\/\s*$|\/\*|~)/.test(cmd);
469
+ const hasDestructivePath = parseArgvTokens(cmd).some((token) => {
470
+ const normalized = token.replace(/\/\*$/, "").replace(/\/+$/, "") || (token.startsWith("/") ? "/" : "");
471
+ return normalized === "/" || normalized === "~" || /^\/[A-Za-z_][\w.-]*$/.test(normalized);
472
+ });
452
473
 
453
474
  // Combined flags in one token: rm -rf /, rm -fr /
454
475
  if (hasDestructivePath && (
@@ -464,7 +485,10 @@ function blockRmRf(ctx: PolicyContext): PolicyResult {
464
485
  if (hasDestructivePath && /\brm\b/.test(cmd)) {
465
486
  const tokens = parseArgvTokens(cmd);
466
487
  const shortFlags = tokens.filter((t) => /^-[^-]/.test(t)).join("");
467
- if (/r/i.test(shortFlags) && /f/.test(shortFlags)) {
488
+ const longFlags = tokens.filter((t) => /^--/.test(t));
489
+ const hasRecursive = /r/i.test(shortFlags) || longFlags.some(f => /^--recursive$/i.test(f));
490
+ const hasForce = /f/.test(shortFlags) || longFlags.some(f => /^--force$/i.test(f));
491
+ if (hasRecursive && hasForce) {
468
492
  const allowPaths = ((ctx.params?.allowPaths ?? []) as string[]);
469
493
  if (rmTargetIsAllowed(cmd, allowPaths)) return allow();
470
494
  return deny("Catastrophic deletion blocked");
@@ -627,24 +651,14 @@ function blockWorkOnMain(ctx: PolicyContext): PolicyResult {
627
651
  const cwd = ctx.session?.cwd;
628
652
  if (!cwd) return allow();
629
653
 
630
- try {
631
- let branch = gitBranchCache.get(cwd);
632
- if (branch === undefined) {
633
- branch = execSync("git rev-parse --abbrev-ref HEAD", {
634
- cwd,
635
- encoding: "utf8",
636
- timeout: 3000,
637
- }).trim();
638
- gitBranchCache.set(cwd, branch);
639
- }
640
- const protectedBranches = ((ctx.params?.protectedBranches ?? ["main", "master"]) as string[]);
641
- if (protectedBranches.includes(branch)) {
642
- return deny(
643
- `Git ${cmd.match(/git\s+(\S+)/)?.[1] ?? "operation"} on ${branch} is blocked. Create a feature branch first.`,
644
- );
645
- }
646
- } catch {
647
- return allow();
654
+ const branch = getCurrentBranch(cwd);
655
+ if (!branch) return allow();
656
+
657
+ const protectedBranches = ((ctx.params?.protectedBranches ?? ["main", "master"]) as string[]);
658
+ if (protectedBranches.includes(branch)) {
659
+ return deny(
660
+ `Git ${cmd.match(/git\s+(\S+)/)?.[1] ?? "operation"} on ${branch} is blocked. Create a feature branch first.`,
661
+ );
648
662
  }
649
663
  return allow();
650
664
  }
@@ -786,6 +800,195 @@ function warnBackgroundProcess(ctx: PolicyContext): PolicyResult {
786
800
  return allow();
787
801
  }
788
802
 
803
+ // -- Workflow (Stop event) policies --
804
+
805
+ function requireCommitBeforeStop(ctx: PolicyContext): PolicyResult {
806
+ const cwd = ctx.session?.cwd;
807
+ if (!cwd) return allow("No working directory available, skipping commit check.");
808
+
809
+ try {
810
+ const status = execSync("git status --porcelain", {
811
+ cwd,
812
+ encoding: "utf8",
813
+ timeout: 5000,
814
+ }).trim();
815
+
816
+ if (status.length > 0) {
817
+ return deny(
818
+ "You have uncommitted changes in the working directory. Commit all changes before stopping.",
819
+ );
820
+ }
821
+ return allow("All changes are committed.");
822
+ } catch {
823
+ return allow("Not a git repository, skipping commit check.");
824
+ }
825
+ }
826
+
827
+ function requirePushBeforeStop(ctx: PolicyContext): PolicyResult {
828
+ const cwd = ctx.session?.cwd;
829
+ if (!cwd) return allow("No working directory available, skipping push check.");
830
+
831
+ try {
832
+ const remotes = execSync("git remote", {
833
+ cwd,
834
+ encoding: "utf8",
835
+ timeout: 3000,
836
+ }).trim();
837
+
838
+ if (!remotes) return allow("No git remote configured, skipping push check.");
839
+
840
+ const remote = (ctx.params?.remote as string) ?? "origin";
841
+
842
+ const branch = getCurrentBranch(cwd);
843
+ if (!branch || branch === "HEAD") return allow("Detached HEAD, skipping push check.");
844
+
845
+ // Check if remote tracking branch exists
846
+ let hasTracking = false;
847
+ try {
848
+ execFileSync("git", ["rev-parse", "--verify", `${remote}/${branch}`], {
849
+ cwd,
850
+ encoding: "utf8",
851
+ timeout: 3000,
852
+ });
853
+ hasTracking = true;
854
+ } catch {
855
+ // Remote tracking branch does not exist
856
+ }
857
+
858
+ if (!hasTracking) {
859
+ return deny(
860
+ `Branch "${branch}" has not been pushed to remote "${remote}". ` +
861
+ `Push your branch with: git push -u ${remote} ${branch}`,
862
+ );
863
+ }
864
+
865
+ // Check for unpushed commits
866
+ const unpushed = execFileSync("git", ["log", `${remote}/${branch}..HEAD`, "--oneline"], {
867
+ cwd,
868
+ encoding: "utf8",
869
+ timeout: 5000,
870
+ }).trim();
871
+
872
+ if (unpushed.length > 0) {
873
+ const commitCount = unpushed.split("\n").length;
874
+ return deny(
875
+ `You have ${commitCount} unpushed commit${commitCount > 1 ? "s" : ""} on branch "${branch}". ` +
876
+ `Push your changes with: git push`,
877
+ );
878
+ }
879
+
880
+ return allow(`All commits pushed to "${remote}".`);
881
+ } catch {
882
+ return allow("Could not check push status, skipping.");
883
+ }
884
+ }
885
+
886
+ function requirePrBeforeStop(ctx: PolicyContext): PolicyResult {
887
+ const cwd = ctx.session?.cwd;
888
+ if (!cwd) return allow("No working directory available, skipping PR check.");
889
+
890
+ try {
891
+ // Check if gh CLI is available
892
+ try {
893
+ execSync("gh --version", { cwd, encoding: "utf8", timeout: 3000 });
894
+ } catch {
895
+ return allow("GitHub CLI (gh) not installed, skipping PR check.");
896
+ }
897
+
898
+ const branch = getCurrentBranch(cwd);
899
+ if (!branch || branch === "HEAD") return allow("Detached HEAD, skipping PR check.");
900
+
901
+ // Check if a PR exists for this branch
902
+ let prJson: string;
903
+ try {
904
+ prJson = execSync("gh pr view --json number,url,state", {
905
+ cwd,
906
+ encoding: "utf8",
907
+ timeout: 15000,
908
+ }).trim();
909
+ } catch {
910
+ // gh pr view exits non-zero when no PR exists
911
+ return deny(
912
+ `No pull request found for branch "${branch}". ` +
913
+ `Create one with: gh pr create`,
914
+ );
915
+ }
916
+
917
+ const pr = JSON.parse(prJson) as { number: number; url: string; state: string };
918
+
919
+ if (pr.state === "OPEN") {
920
+ return allow(`PR #${pr.number} exists: ${pr.url}`);
921
+ }
922
+
923
+ return deny(
924
+ `Pull request for branch "${branch}" is ${pr.state.toLowerCase()}. Create a new PR with: gh pr create`,
925
+ );
926
+ } catch {
927
+ return allow("Could not check PR status, skipping.");
928
+ }
929
+ }
930
+
931
+ function requireCiGreenBeforeStop(ctx: PolicyContext): PolicyResult {
932
+ const cwd = ctx.session?.cwd;
933
+ if (!cwd) return allow("No working directory available, skipping CI check.");
934
+
935
+ try {
936
+ // Check if gh CLI is available
937
+ try {
938
+ execSync("gh --version", { cwd, encoding: "utf8", timeout: 3000 });
939
+ } catch {
940
+ return allow("GitHub CLI (gh) not installed, skipping CI check.");
941
+ }
942
+
943
+ const branch = getCurrentBranch(cwd);
944
+ if (!branch || branch === "HEAD") return allow("Detached HEAD, skipping CI check.");
945
+
946
+ const runsJson = execFileSync(
947
+ "gh",
948
+ ["run", "list", "--branch", branch, "--limit", "5", "--json", "status,conclusion,name"],
949
+ {
950
+ cwd,
951
+ encoding: "utf8",
952
+ timeout: 15000,
953
+ },
954
+ ).trim();
955
+
956
+ if (!runsJson || runsJson === "[]") return allow(`No CI runs found for branch "${branch}".`);
957
+
958
+ const runs = JSON.parse(runsJson) as Array<{
959
+ status: string;
960
+ conclusion: string;
961
+ name: string;
962
+ }>;
963
+
964
+ if (runs.length === 0) return allow(`No CI runs found for branch "${branch}".`);
965
+
966
+ const failing = runs.filter(
967
+ (r) => r.status === "completed" && r.conclusion !== "success" && r.conclusion !== "skipped",
968
+ );
969
+ if (failing.length > 0) {
970
+ const names = failing.map((r) => `"${r.name}"`).join(", ");
971
+ return deny(
972
+ `CI checks are failing on branch "${branch}": ${names}. Fix the failing checks before stopping.`,
973
+ );
974
+ }
975
+
976
+ const pending = runs.filter(
977
+ (r) => r.status === "in_progress" || r.status === "queued" || r.status === "waiting",
978
+ );
979
+ if (pending.length > 0) {
980
+ const names = pending.map((r) => `"${r.name}"`).join(", ");
981
+ return deny(
982
+ `CI checks are still running on branch "${branch}": ${names}. Wait for all checks to complete and verify they pass.`,
983
+ );
984
+ }
985
+
986
+ return allow(`All CI checks passed on branch "${branch}".`);
987
+ } catch {
988
+ return allow("Could not check CI status, skipping.");
989
+ }
990
+ }
991
+
789
992
  // -- Registry --
790
993
 
791
994
  export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
@@ -1053,6 +1256,49 @@ export const BUILTIN_POLICIES: BuiltinPolicyDefinition[] = [
1053
1256
  defaultEnabled: false,
1054
1257
  category: "AI Behavior",
1055
1258
  },
1259
+ {
1260
+ name: "require-commit-before-stop",
1261
+ description: "Require all changes to be committed before Claude stops",
1262
+ fn: requireCommitBeforeStop,
1263
+ match: { events: ["Stop"] },
1264
+ defaultEnabled: false,
1265
+ category: "Workflow",
1266
+ beta: true,
1267
+ },
1268
+ {
1269
+ name: "require-push-before-stop",
1270
+ description: "Require all commits to be pushed to remote before Claude stops",
1271
+ fn: requirePushBeforeStop,
1272
+ match: { events: ["Stop"] },
1273
+ defaultEnabled: false,
1274
+ category: "Workflow",
1275
+ beta: true,
1276
+ params: {
1277
+ remote: {
1278
+ type: "string",
1279
+ description: "Remote name to push to (default: origin)",
1280
+ default: "origin",
1281
+ },
1282
+ } satisfies PolicyParamsSchema,
1283
+ },
1284
+ {
1285
+ name: "require-pr-before-stop",
1286
+ description: "Require a pull request to exist for the current branch before Claude stops",
1287
+ fn: requirePrBeforeStop,
1288
+ match: { events: ["Stop"] },
1289
+ defaultEnabled: false,
1290
+ category: "Workflow",
1291
+ beta: true,
1292
+ },
1293
+ {
1294
+ name: "require-ci-green-before-stop",
1295
+ description: "Require CI checks to pass on the current branch before Claude stops",
1296
+ fn: requireCiGreenBeforeStop,
1297
+ match: { events: ["Stop"] },
1298
+ defaultEnabled: false,
1299
+ category: "Workflow",
1300
+ beta: true,
1301
+ },
1056
1302
  ];
1057
1303
 
1058
1304
  export function registerBuiltinPolicies(enabledNames: string[]): void {
@@ -134,6 +134,7 @@ export async function handleHookEvent(eventType: string): Promise<number> {
134
134
  eventType,
135
135
  toolName: (parsed.tool_name as string) ?? null,
136
136
  policyName: result.policyName,
137
+ policyNames: result.policyNames,
137
138
  decision: result.decision,
138
139
  reason: result.reason,
139
140
  durationMs,
@@ -43,6 +43,7 @@ export interface HookActivityEntry {
43
43
  eventType: string;
44
44
  toolName: string | null;
45
45
  policyName: string | null;
46
+ policyNames?: string[];
46
47
  decision: "allow" | "deny" | "instruct";
47
48
  reason: string | null;
48
49
  durationMs: number;
@@ -186,7 +187,11 @@ function updateStats(entry: HookActivityEntry): void {
186
187
  const s = readStoredStats();
187
188
  s.totalEvents += 1;
188
189
  if (entry.decision === "deny") s.denyCount += 1;
189
- if (entry.policyName) {
190
+ if (entry.policyNames && entry.policyNames.length > 0) {
191
+ for (const name of entry.policyNames) {
192
+ s.policyMap[name] = (s.policyMap[name] ?? 0) + 1;
193
+ }
194
+ } else if (entry.policyName) {
190
195
  s.policyMap[entry.policyName] = (s.policyMap[entry.policyName] ?? 0) + 1;
191
196
  }
192
197
  // Write atomically: write to a PID-unique temp file then rename — prevents partial reads.
@@ -13,6 +13,7 @@ export interface EvaluationResult {
13
13
  stdout: string;
14
14
  stderr: string;
15
15
  policyName: string | null;
16
+ policyNames?: string[];
16
17
  reason: string | null;
17
18
  decision: "allow" | "deny" | "instruct";
18
19
  }
@@ -51,6 +52,9 @@ export async function evaluatePolicies(
51
52
  let instructPolicyName: string | null = null;
52
53
  let instructReason: string | null = null;
53
54
 
55
+ // Track informational messages from allow decisions (with policy attribution)
56
+ const allowEntries: Array<{ policyName: string; reason: string }> = [];
57
+
54
58
  for (const policy of policies) {
55
59
  // Inject params: merge policyParams[policy.name] over schema defaults
56
60
  const schema = POLICY_PARAMS_MAP.get(policy.name);
@@ -120,7 +124,7 @@ export async function evaluatePolicies(
120
124
  return {
121
125
  exitCode: 2,
122
126
  stdout: "",
123
- stderr: "",
127
+ stderr: reason,
124
128
  policyName: policy.name,
125
129
  reason,
126
130
  decision: "deny",
@@ -133,6 +137,11 @@ export async function evaluatePolicies(
133
137
  instructReason = result.reason ?? `Instruction from policy: ${policy.name}`;
134
138
  hookLogInfo(`instruct by "${policy.name}": ${instructReason}`);
135
139
  }
140
+
141
+ // Accumulate informational messages from allow decisions
142
+ if (result.decision === "allow" && result.reason) {
143
+ allowEntries.push({ policyName: policy.name, reason: result.reason });
144
+ }
136
145
  }
137
146
 
138
147
  // No deny — check if we accumulated an instruct
@@ -166,6 +175,18 @@ export async function evaluatePolicies(
166
175
  };
167
176
  }
168
177
 
169
- // All policies allowed
178
+ // All policies allowed — pass along any informational messages
179
+ if (allowEntries.length > 0) {
180
+ const combined = allowEntries.map((e) => e.reason).join("\n");
181
+ const policyNames = allowEntries.map((e) => e.policyName);
182
+ const supportsHookSpecificOutput = eventType === "PreToolUse" || eventType === "PostToolUse" || eventType === "UserPromptSubmit";
183
+ const response = supportsHookSpecificOutput
184
+ ? { hookSpecificOutput: { hookEventName: eventType, additionalContext: `Note from failproofai: ${combined}` } }
185
+ : { reason: combined };
186
+ const stderrMsg = allowEntries
187
+ .map((e) => `[failproofai] ${e.policyName}: ${e.reason}`)
188
+ .join("\n");
189
+ return { exitCode: 0, stdout: JSON.stringify(response), stderr: stderrMsg + "\n", policyName: policyNames[0], policyNames, reason: combined, decision: "allow" };
190
+ }
170
191
  return { exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow" };
171
192
  }
@@ -3,8 +3,8 @@
3
3
  */
4
4
  import type { PolicyResult } from "./policy-types";
5
5
 
6
- export function allow(): PolicyResult {
7
- return { decision: "allow" };
6
+ export function allow(reason?: string): PolicyResult {
7
+ return reason ? { decision: "allow", reason } : { decision: "allow" };
8
8
  }
9
9
 
10
10
  export function deny(reason: string): PolicyResult {
@@ -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-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-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-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--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{--color-red-100:#ffe2e2;--color-red-200:#ffcaca;--color-red-400:#ff6568;--color-red-500:#fb2c36;--color-red-600:#e40014;--color-red-900:#82181a;--color-red-950:#460809;--color-amber-400:#fcbb00;--color-amber-500:#f99c00;--color-green-500:#00c758;--color-emerald-400:#00d294;--color-emerald-500:#00bb7f;--color-sky-400:#00bcfe;--color-sky-500:#00a5ef;--color-violet-400:#a685ff;--color-violet-500:#8d54ff;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--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-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-tight:1.25;--leading-snug:1.375;--leading-relaxed:1.625;--ease-out:cubic-bezier(0, 0, .2, 1);--animate-spin:spin 1s linear infinite;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) 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:system-ui, -apple-system, sans-serif;--default-mono-font-family:ui-monospace, monospace}@supports (color:lab(0% 0 0)){:root,:host{--color-red-100:lab(92.243% 10.2865 3.83865);--color-red-200:lab(86.017% 19.8815 7.75869);--color-red-400:lab(63.7053% 60.745 31.3109);--color-red-500:lab(55.4814% 75.0732 48.8528);--color-red-600:lab(48.4493% 77.4328 61.5452);--color-red-900:lab(28.5139% 44.5539 29.0463);--color-red-950:lab(13.003% 29.04 16.7519);--color-amber-400:lab(80.1641% 16.6016 99.2089);--color-amber-500:lab(72.7183% 31.8672 97.9407);--color-green-500:lab(70.5521% -66.5147 45.8073);--color-emerald-400:lab(75.0771% -60.7313 19.4147);--color-emerald-500:lab(66.9756% -58.27 19.5419);--color-sky-400:lab(70.687% -23.6078 -45.9483);--color-sky-500:lab(63.3038% -18.433 -51.0407);--color-violet-400:lab(62.8239% 34.9159 -60.0512);--color-violet-500:lab(49.9355% 55.1776 -81.8963)}}}@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;-webkit-text-decoration:inherit;-webkit-text-decoration: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}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){*{outline-color:color-mix(in oklab, var(--ring) 50%, transparent)}}html{font-size:120%}body{background-color:var(--background);color:var(--foreground);font-family:system-ui,-apple-system,sans-serif}input[type=checkbox]{accent-color:var(--primary)}select{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark}@media (prefers-color-scheme:dark){select{--lightningcss-light: ;--lightningcss-dark:initial}}.light select{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}select option{background-color:var(--popover);color:var(--popover-foreground)}input[type=date]{position:relative;overflow:visible}input[type=date]::-webkit-calendar-picker-indicator{opacity:0;cursor:pointer;width:0;height:0;display:none;position:absolute;right:0}input[type=date]::-webkit-datetime-edit{align-items:center;gap:0;width:100%;padding:0;display:inline-flex}input[type=date]::-webkit-datetime-edit-text{color:var(--muted-foreground);padding:0 .2rem}input[type=date]::-webkit-datetime-edit-month-field{color:var(--foreground);width:2.5ch;min-width:2.5ch;padding:0 .15rem}input[type=date]::-webkit-datetime-edit-day-field{color:var(--foreground);width:2.5ch;min-width:2.5ch;padding:0 .15rem}input[type=date]::-webkit-datetime-edit-year-field{color:var(--foreground);width:5ch;min-width:5ch;max-width:5ch;padding:0 .15rem;overflow:visible}input[type=date]::-webkit-datetime-edit-month-field:focus{background-color:var(--muted);color:var(--foreground);border-radius:.25rem}input[type=date]::-webkit-datetime-edit-day-field:focus{background-color:var(--muted);color:var(--foreground);border-radius:.25rem}input[type=date]::-webkit-datetime-edit-year-field:focus{background-color:var(--muted);color:var(--foreground);border-radius:.25rem}input[type=date]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}.light input[type=date]{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}#__loading{display:none!important}body>*{opacity:1!important}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-1{inset-inline:calc(var(--spacing) * 1)}.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.top-1\/2{top:50%}.top-4{top:calc(var(--spacing) * 4)}.right-0{right:calc(var(--spacing) * 0)}.right-2\.5{right:calc(var(--spacing) * 2.5)}.right-4{right:calc(var(--spacing) * 4)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-4{bottom:calc(var(--spacing) * 4)}.isolate{isolation:isolate}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.z-\[9999\]{z-index:9999}.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-1{margin-inline:calc(var(--spacing) * 1)}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.-mt-0\.5{margin-top:calc(var(--spacing) * -.5)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.-mr-0\.5{margin-right:calc(var(--spacing) * -.5)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.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-5{margin-bottom:calc(var(--spacing) * 5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.h-0\.5{height:calc(var(--spacing) * .5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3{height:calc(var(--spacing) * 3)}.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-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-11{height:calc(var(--spacing) * 11)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-24{height:calc(var(--spacing) * 24)}.h-\[1\.2rem\]{height:1.2rem}.h-\[2px\]{height:2px}.h-full{height:100%}.h-px{height:1px}.max-h-48{max-height:calc(var(--spacing) * 48)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-\[80vh\]{max-height:80vh}.min-h-screen{min-height:100vh}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-3{width:calc(var(--spacing) * 3)}.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-10{width:calc(var(--spacing) * 10)}.w-12{width:calc(var(--spacing) * 12)}.w-32{width:calc(var(--spacing) * 32)}.w-36{width:calc(var(--spacing) * 36)}.w-44{width:calc(var(--spacing) * 44)}.w-48{width:calc(var(--spacing) * 48)}.w-56{width:calc(var(--spacing) * 56)}.w-64{width:calc(var(--spacing) * 64)}.w-72{width:calc(var(--spacing) * 72)}.w-\[1\.2rem\]{width:1.2rem}.w-\[200px\]{width:200px}.w-\[250px\]{width:250px}.w-full{width:100%}.w-px{width:1px}.max-w-7xl{max-width:var(--container-7xl)}.max-w-\[120px\]{max-width:120px}.max-w-\[240px\]{max-width:240px}.max-w-\[400px\]{max-width:400px}.max-w-full{max-width:100%}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[2\.5rem\]{min-width:2.5rem}.flex-1{flex:1}.flex-shrink-0,.shrink-0{flex-shrink:0}.translate-x-0\.5{--tw-translate-x:calc(var(--spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-3\.5{--tw-translate-x:calc(var(--spacing) * 3.5);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-0{--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x) var(--tw-scale-y)}.scale-100{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}.-rotate-90{rotate:-90deg}.rotate-0{rotate:none}.rotate-90{rotate:90deg}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize-y{resize:vertical}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[repeat\(auto-fit\,minmax\(200px\,1fr\)\)\]{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}: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)))}.gap-x-8{column-gap:calc(var(--spacing) * 8)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border\/30>:not(:last-child)){border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){:where(.divide-border\/30>:not(:last-child)){border-color:color-mix(in oklab, var(--border) 30%, transparent)}}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-r-lg{border-top-right-radius:var(--radius);border-bottom-right-radius:var(--radius)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-\[color\:var\(--chart-1\)\]\/30{border-color:var(--chart-1)}@supports (color:color-mix(in lab, red, red)){.border-\[color\:var\(--chart-1\)\]\/30{border-color:color-mix(in oklab, var(--chart-1) 30%, transparent)}}.border-\[color\:var\(--chart-2\)\]\/30{border-color:var(--chart-2)}@supports (color:color-mix(in lab, red, red)){.border-\[color\:var\(--chart-2\)\]\/30{border-color:color-mix(in oklab, var(--chart-2) 30%, transparent)}}.border-\[color\:var\(--chart-3\)\]\/30{border-color:var(--chart-3)}@supports (color:color-mix(in lab, red, red)){.border-\[color\:var\(--chart-3\)\]\/30{border-color:color-mix(in oklab, var(--chart-3) 30%, transparent)}}.border-\[color\:var\(--chart-4\)\]\/30{border-color:var(--chart-4)}@supports (color:color-mix(in lab, red, red)){.border-\[color\:var\(--chart-4\)\]\/30{border-color:color-mix(in oklab, var(--chart-4) 30%, transparent)}}.border-\[color\:var\(--chart-5\)\]\/30{border-color:var(--chart-5)}@supports (color:color-mix(in lab, red, red)){.border-\[color\:var\(--chart-5\)\]\/30{border-color:color-mix(in oklab, var(--chart-5) 30%, transparent)}}.border-amber-500\/20{border-color:#f99c0033}@supports (color:color-mix(in lab, red, red)){.border-amber-500\/20{border-color:color-mix(in oklab, var(--color-amber-500) 20%, transparent)}}.border-border,.border-border\/20{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.border-border\/20{border-color:color-mix(in oklab, var(--border) 20%, transparent)}}.border-border\/30{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.border-border\/30{border-color:color-mix(in oklab, var(--border) 30%, transparent)}}.border-border\/40{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.border-border\/40{border-color:color-mix(in oklab, var(--border) 40%, transparent)}}.border-border\/50{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.border-border\/50{border-color:color-mix(in oklab, var(--border) 50%, transparent)}}.border-destructive\/50{border-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.border-destructive\/50{border-color:color-mix(in oklab, var(--destructive) 50%, transparent)}}.border-emerald-500\/20{border-color:#00bb7f33}@supports (color:color-mix(in lab, red, red)){.border-emerald-500\/20{border-color:color-mix(in oklab, var(--color-emerald-500) 20%, transparent)}}.border-primary\/20{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.border-primary\/20{border-color:color-mix(in oklab, var(--primary) 20%, transparent)}}.border-primary\/30{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.border-primary\/30{border-color:color-mix(in oklab, var(--primary) 30%, transparent)}}.border-primary\/50{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.border-primary\/50{border-color:color-mix(in oklab, var(--primary) 50%, transparent)}}.border-red-500\/20{border-color:#fb2c3633}@supports (color:color-mix(in lab, red, red)){.border-red-500\/20{border-color:color-mix(in oklab, var(--color-red-500) 20%, transparent)}}.border-red-500\/40{border-color:#fb2c3666}@supports (color:color-mix(in lab, red, red)){.border-red-500\/40{border-color:color-mix(in oklab, var(--color-red-500) 40%, transparent)}}.border-sky-500\/20{border-color:#00a5ef33}@supports (color:color-mix(in lab, red, red)){.border-sky-500\/20{border-color:color-mix(in oklab, var(--color-sky-500) 20%, transparent)}}.border-violet-500\/20{border-color:#8d54ff33}@supports (color:color-mix(in lab, red, red)){.border-violet-500\/20{border-color:color-mix(in oklab, var(--color-violet-500) 20%, transparent)}}.border-l-\[color\:var\(--chart-1\)\]{border-left-color:var(--chart-1)}.border-l-\[color\:var\(--chart-2\)\]{border-left-color:var(--chart-2)}.border-l-\[color\:var\(--chart-3\)\]{border-left-color:var(--chart-3)}.border-l-\[color\:var\(--chart-4\)\]{border-left-color:var(--chart-4)}.border-l-\[color\:var\(--chart-5\)\]{border-left-color:var(--chart-5)}.border-l-amber-500\/40{border-left-color:#f99c0066}@supports (color:color-mix(in lab, red, red)){.border-l-amber-500\/40{border-left-color:color-mix(in oklab, var(--color-amber-500) 40%, transparent)}}.border-l-primary{border-left-color:var(--primary)}.border-l-red-500\/40{border-left-color:#fb2c3666}@supports (color:color-mix(in lab, red, red)){.border-l-red-500\/40{border-left-color:color-mix(in oklab, var(--color-red-500) 40%, transparent)}}.bg-\[color\:var\(--chart-1\)\]\/20{background-color:var(--chart-1)}@supports (color:color-mix(in lab, red, red)){.bg-\[color\:var\(--chart-1\)\]\/20{background-color:color-mix(in oklab, var(--chart-1) 20%, transparent)}}.bg-\[color\:var\(--chart-2\)\]\/20{background-color:var(--chart-2)}@supports (color:color-mix(in lab, red, red)){.bg-\[color\:var\(--chart-2\)\]\/20{background-color:color-mix(in oklab, var(--chart-2) 20%, transparent)}}.bg-\[color\:var\(--chart-3\)\]\/20{background-color:var(--chart-3)}@supports (color:color-mix(in lab, red, red)){.bg-\[color\:var\(--chart-3\)\]\/20{background-color:color-mix(in oklab, var(--chart-3) 20%, transparent)}}.bg-\[color\:var\(--chart-4\)\]\/20{background-color:var(--chart-4)}@supports (color:color-mix(in lab, red, red)){.bg-\[color\:var\(--chart-4\)\]\/20{background-color:color-mix(in oklab, var(--chart-4) 20%, transparent)}}.bg-\[color\:var\(--chart-5\)\]\/5{background-color:var(--chart-5)}@supports (color:color-mix(in lab, red, red)){.bg-\[color\:var\(--chart-5\)\]\/5{background-color:color-mix(in oklab, var(--chart-5) 5%, transparent)}}.bg-\[color\:var\(--chart-5\)\]\/20{background-color:var(--chart-5)}@supports (color:color-mix(in lab, red, red)){.bg-\[color\:var\(--chart-5\)\]\/20{background-color:color-mix(in oklab, var(--chart-5) 20%, transparent)}}.bg-amber-500\/10{background-color:#f99c001a}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/10{background-color:color-mix(in oklab, var(--color-amber-500) 10%, transparent)}}.bg-amber-500\/15{background-color:#f99c0026}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/15{background-color:color-mix(in oklab, var(--color-amber-500) 15%, transparent)}}.bg-amber-500\/\[0\.03\]{background-color:#f99c0008}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/\[0\.03\]{background-color:color-mix(in oklab, var(--color-amber-500) 3%, transparent)}}.bg-background{background-color:var(--background)}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab, red, red)){.bg-black\/50{background-color:color-mix(in oklab, var(--color-black) 50%, transparent)}}.bg-border{background-color:var(--border)}.bg-card,.bg-card\/50{background-color:var(--card)}@supports (color:color-mix(in lab, red, red)){.bg-card\/50{background-color:color-mix(in oklab, var(--card) 50%, transparent)}}.bg-emerald-400{background-color:var(--color-emerald-400)}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-emerald-500\/10{background-color:#00bb7f1a}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/10{background-color:color-mix(in oklab, var(--color-emerald-500) 10%, transparent)}}.bg-emerald-500\/15{background-color:#00bb7f26}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/15{background-color:color-mix(in oklab, var(--color-emerald-500) 15%, transparent)}}.bg-input{background-color:var(--input)}.bg-muted{background-color:var(--muted)}.bg-muted-foreground\/30{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.bg-muted-foreground\/30{background-color:color-mix(in oklab, var(--muted-foreground) 30%, transparent)}}.bg-muted-foreground\/50{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.bg-muted-foreground\/50{background-color:color-mix(in oklab, var(--muted-foreground) 50%, transparent)}}.bg-muted\/5{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/5{background-color:color-mix(in oklab, var(--muted) 5%, transparent)}}.bg-muted\/10{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/10{background-color:color-mix(in oklab, var(--muted) 10%, transparent)}}.bg-muted\/20{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/20{background-color:color-mix(in oklab, var(--muted) 20%, transparent)}}.bg-muted\/30{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/30{background-color:color-mix(in oklab, var(--muted) 30%, transparent)}}.bg-muted\/40{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/40{background-color:color-mix(in oklab, var(--muted) 40%, transparent)}}.bg-muted\/50{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/50{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}.bg-muted\/\[0\.04\]{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/\[0\.04\]{background-color:color-mix(in oklab, var(--muted) 4%, transparent)}}.bg-primary,.bg-primary\/10{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/10{background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.bg-primary\/20{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/20{background-color:color-mix(in oklab, var(--primary) 20%, transparent)}}.bg-primary\/30{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/30{background-color:color-mix(in oklab, var(--primary) 30%, transparent)}}.bg-red-500{background-color:var(--color-red-500)}.bg-red-500\/10{background-color:#fb2c361a}@supports (color:color-mix(in lab, red, red)){.bg-red-500\/10{background-color:color-mix(in oklab, var(--color-red-500) 10%, transparent)}}.bg-red-500\/15{background-color:#fb2c3626}@supports (color:color-mix(in lab, red, red)){.bg-red-500\/15{background-color:color-mix(in oklab, var(--color-red-500) 15%, transparent)}}.bg-red-500\/\[0\.03\]{background-color:#fb2c3608}@supports (color:color-mix(in lab, red, red)){.bg-red-500\/\[0\.03\]{background-color:color-mix(in oklab, var(--color-red-500) 3%, transparent)}}.bg-red-950\/95{background-color:#460809f2}@supports (color:color-mix(in lab, red, red)){.bg-red-950\/95{background-color:color-mix(in oklab, var(--color-red-950) 95%, transparent)}}.bg-sky-500\/10{background-color:#00a5ef1a}@supports (color:color-mix(in lab, red, red)){.bg-sky-500\/10{background-color:color-mix(in oklab, var(--color-sky-500) 10%, transparent)}}.bg-transparent{background-color:#0000}.bg-violet-500\/10{background-color:#8d54ff1a}@supports (color:color-mix(in lab, red, red)){.bg-violet-500\/10{background-color:color-mix(in oklab, var(--color-violet-500) 10%, transparent)}}.bg-white{background-color:var(--color-white)}.bg-gradient-to-r{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-red-600{--tw-gradient-from:var(--color-red-600);--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-red-400{--tw-gradient-via:var(--color-red-400);--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-red-600{--tw-gradient-to:var(--color-red-600);--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))}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:calc(var(--spacing) * 1)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-0{padding-inline:calc(var(--spacing) * 0)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-0{padding-block:calc(var(--spacing) * 0)}.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-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-16{padding-block:calc(var(--spacing) * 16)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pl-3{padding-left:calc(var(--spacing) * 3)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:ui-monospace,monospace}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--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-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.6rem\]{font-size:.6rem}.text-\[0\.7rem\]{font-size:.7rem}.text-\[0\.65rem\]{font-size:.65rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.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-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[color\:var\(--chart-1\)\]{color:var(--chart-1)}.text-\[color\:var\(--chart-2\)\]{color:var(--chart-2)}.text-\[color\:var\(--chart-3\)\]{color:var(--chart-3)}.text-\[color\:var\(--chart-4\)\]{color:var(--chart-4)}.text-\[color\:var\(--chart-5\)\]{color:var(--chart-5)}.text-amber-400{color:var(--color-amber-400)}.text-card-foreground{color:var(--card-foreground)}.text-destructive{color:var(--destructive)}.text-emerald-400{color:var(--color-emerald-400)}.text-foreground,.text-foreground\/70{color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.text-foreground\/70{color:color-mix(in oklab, var(--foreground) 70%, transparent)}}.text-green-500{color:var(--color-green-500)}.text-muted-foreground,.text-muted-foreground\/30{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.text-muted-foreground\/30{color:color-mix(in oklab, var(--muted-foreground) 30%, transparent)}}.text-muted-foreground\/40{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.text-muted-foreground\/40{color:color-mix(in oklab, var(--muted-foreground) 40%, transparent)}}.text-muted-foreground\/50{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.text-muted-foreground\/50{color:color-mix(in oklab, var(--muted-foreground) 50%, transparent)}}.text-muted-foreground\/55{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.text-muted-foreground\/55{color:color-mix(in oklab, var(--muted-foreground) 55%, transparent)}}.text-muted-foreground\/60{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.text-muted-foreground\/60{color:color-mix(in oklab, var(--muted-foreground) 60%, transparent)}}.text-muted-foreground\/70{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.text-muted-foreground\/70{color:color-mix(in oklab, var(--muted-foreground) 70%, transparent)}}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-primary\/70{color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.text-primary\/70{color:color-mix(in oklab, var(--primary) 70%, transparent)}}.text-red-100{color:var(--color-red-100)}.text-red-400{color:var(--color-red-400)}.text-red-400\/60{color:#ff656899}@supports (color:color-mix(in lab, red, red)){.text-red-400\/60{color:color-mix(in oklab, var(--color-red-400) 60%, transparent)}}.text-sky-400{color:var(--color-sky-400)}.text-violet-400{color:var(--color-violet-400)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.opacity-75{opacity:.75}.opacity-100{opacity:1}.shadow{--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-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-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)}.shadow-red-900\/40{--tw-shadow-color:#82181a66}@supports (color:color-mix(in lab, red, red)){.shadow-red-900\/40{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--color-red-900) 40%, transparent) var(--tw-shadow-alpha), transparent)}}.ring-red-500\/30{--tw-ring-color:#fb2c364d}@supports (color:color-mix(in lab, red, red)){.ring-red-500\/30{--tw-ring-color:color-mix(in oklab, var(--color-red-500) 30%, transparent)}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-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,)}.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-shadow{transition-property:box-shadow;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-150{--tw-duration:.15s;transition-duration:.15s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.\[failproofai\:hook\]{failproofai:hook}.\[failproofai\:telemetry\]{failproofai:telemetry}@media (hover:hover){.group-hover\:bg-muted:is(:where(.group):hover *){background-color:var(--muted)}.group-hover\:bg-primary\/20:is(:where(.group):hover *){background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.group-hover\:bg-primary\/20:is(:where(.group):hover *){background-color:color-mix(in oklab, var(--primary) 20%, transparent)}}.group-hover\:text-primary\/80:is(:where(.group):hover *){color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.group-hover\:text-primary\/80:is(:where(.group):hover *){color:color-mix(in oklab, var(--primary) 80%, transparent)}}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}@media (hover:hover){.hover\:border-primary\/50:hover{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\:border-primary\/50:hover{border-color:color-mix(in oklab, var(--primary) 50%, transparent)}}.hover\:bg-amber-500\/\[0\.07\]:hover{background-color:#f99c0012}@supports (color:color-mix(in lab, red, red)){.hover\:bg-amber-500\/\[0\.07\]:hover{background-color:color-mix(in oklab, var(--color-amber-500) 7.0%, transparent)}}.hover\:bg-muted:hover,.hover\:bg-muted\/20:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-muted\/20:hover{background-color:color-mix(in oklab, var(--muted) 20%, transparent)}}.hover\:bg-muted\/30:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-muted\/30:hover{background-color:color-mix(in oklab, var(--muted) 30%, transparent)}}.hover\:bg-muted\/50:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-muted\/50:hover{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}.hover\:bg-muted\/80:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-muted\/80:hover{background-color:color-mix(in oklab, var(--muted) 80%, transparent)}}.hover\:bg-primary\/10:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/10:hover{background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.hover\:bg-primary\/20:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/20:hover{background-color:color-mix(in oklab, var(--primary) 20%, transparent)}}.hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--primary) 90%, transparent)}}.hover\:bg-red-400:hover{background-color:var(--color-red-400)}.hover\:bg-red-500\/10:hover{background-color:#fb2c361a}@supports (color:color-mix(in lab, red, red)){.hover\:bg-red-500\/10:hover{background-color:color-mix(in oklab, var(--color-red-500) 10%, transparent)}}.hover\:bg-red-500\/20:hover{background-color:#fb2c3633}@supports (color:color-mix(in lab, red, red)){.hover\:bg-red-500\/20:hover{background-color:color-mix(in oklab, var(--color-red-500) 20%, transparent)}}.hover\:bg-red-500\/\[0\.07\]:hover{background-color:#fb2c3612}@supports (color:color-mix(in lab, red, red)){.hover\:bg-red-500\/\[0\.07\]:hover{background-color:color-mix(in oklab, var(--color-red-500) 7.0%, transparent)}}.hover\:text-destructive:hover{color:var(--destructive)}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:text-muted-foreground:hover{color:var(--muted-foreground)}.hover\:text-primary:hover,.hover\:text-primary\/80:hover{color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\:text-primary\/80:hover{color:color-mix(in oklab, var(--primary) 80%, transparent)}}.hover\:text-red-200:hover{color:var(--color-red-200)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}}.focus\:border-primary\/40:focus{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.focus\:border-primary\/40:focus{border-color:color-mix(in oklab, var(--primary) 40%, transparent)}}.focus\:border-transparent:focus{border-color:#0000}.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-primary\/40:focus{--tw-ring-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.focus\:ring-primary\/40:focus{--tw-ring-color:color-mix(in oklab, var(--primary) 40%, transparent)}}.focus\:ring-ring:focus{--tw-ring-color:var(--ring)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-2:focus-visible{--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-visible\:ring-ring:focus-visible{--tw-ring-color:var(--ring)}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}@supports ((-webkit-backdrop-filter:var(--tw)) or (backdrop-filter:var(--tw))){.supports-\[backdrop-filter\]\:bg-card\/50{background-color:var(--card)}@supports (color:color-mix(in lab, red, red)){.supports-\[backdrop-filter\]\:bg-card\/50{background-color:color-mix(in oklab, var(--card) 50%, transparent)}}}@media (min-width:40rem){.sm\:block{display:block}.sm\:inline{display:inline}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.sm\:px-6{padding-inline:calc(var(--spacing) * 6)}}@media (min-width:48rem){.md\:table-cell{display:table-cell}}@media (min-width:64rem){.lg\:block{display:block}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.lg\:grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.lg\:px-8{padding-inline:calc(var(--spacing) * 8)}.lg\:px-10{padding-inline:calc(var(--spacing) * 10)}}}:root{--accent:#031035;--accent-light:#0a1a4a;--accent-lighter:#1a2a5a;--accent-lightest:#2a3a6a;--radius:.625rem;--background:#031035;--foreground:#f8fafc;--card:#0a1a4a;--card-foreground:#f8fafc;--popover:#0a1a4a;--popover-foreground:#f8fafc;--primary:#87ceeb;--primary-foreground:#031035;--secondary:#1a2a5a;--secondary-foreground:#f8fafc;--muted:#2a3a6a;--muted-foreground:#94a3b8;--accent-foreground:#f8fafc;--destructive:#ff6b8a;--border:#1a2a5a;--input:#1a2a5a;--ring:#87ceeb;--chart-1:#87ceeb;--chart-2:#66d1b5;--chart-3:#ffed9e;--chart-4:#ff6b8a;--chart-5:#a78bfa;--sidebar:#0a1a4a;--sidebar-foreground:#f8fafc;--sidebar-primary:#87ceeb;--sidebar-primary-foreground:#031035;--sidebar-accent:#1a2a5a;--sidebar-accent-foreground:#f8fafc;--sidebar-border:#1a2a5a;--sidebar-ring:#87ceeb}.light{--background:#fff;--foreground:#031035;--card:#f2f7fb;--card-foreground:#031035;--popover:#fff;--popover-foreground:#031035;--primary:#031035;--primary-foreground:#fff;--secondary:#f1f5f9;--secondary-foreground:#031035;--muted:#f1f5f9;--muted-foreground:#64748b;--accent:#031035;--accent-light:#0a1a4a;--accent-lighter:#1a2a5a;--accent-lightest:#2a3a6a;--accent-foreground:#fff;--destructive:#dc2626;--border:#e2e8f0;--input:#fff;--ring:#87ceeb;--chart-1:#87ceeb;--chart-2:#4ade80;--chart-3:#cca301;--chart-4:#ff6b8a;--chart-5:#a78bfa;--sidebar:#f8fafc;--sidebar-foreground:#031035;--sidebar-primary:#031035;--sidebar-primary-foreground:#fff;--sidebar-accent:#f1f5f9;--sidebar-accent-foreground:#031035;--sidebar-border:#e2e8f0;--sidebar-ring:#87ceeb}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--muted);border-radius:var(--radius)}::-webkit-scrollbar-thumb{background:var(--chart-1);border-radius:var(--radius);transition:background .2s}::-webkit-scrollbar-thumb:hover{background:var(--accent-lightest)}::-webkit-scrollbar-corner{background:var(--muted)}*{scrollbar-width:thin;scrollbar-color:var(--border) var(--muted)}@keyframes entry-highlight{0%{background-color:hsl(var(--primary) / .15)}to{background-color:#0000}}.entry-highlighted{outline:2px solid hsl(var(--primary) / .4);outline-offset:-1px;border-radius:.5rem;animation:3s ease-out forwards entry-highlight}@keyframes expand-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.animate-expand{animation:.15s ease-out expand-in}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-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-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@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 ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}