@hasna/contacts 0.6.32 → 0.6.34

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 (205) hide show
  1. package/THIRD_PARTY_NOTICES.md +5 -0
  2. package/dist/cli/index.js +22033 -5522
  3. package/dist/index.js +3 -0
  4. package/dist/mcp/index.js +27401 -11286
  5. package/dist/server/cloud-index.js +9187 -0
  6. package/dist/server/index.js +198 -60
  7. package/migrations/0013_remote_delete_tombstones.sql +15 -0
  8. package/migrations/0014_contact_tag_filter_index.sql +9 -0
  9. package/package.json +9 -4
  10. package/vendor/fast-uri/LICENSE +30 -0
  11. package/dashboard/dist/assets/index-0l6aQb1t.css +0 -1
  12. package/dashboard/dist/assets/index-opnZdkVD.js +0 -229
  13. package/dashboard/dist/index.html +0 -13
  14. package/dist/cli/commands/advanced.d.ts +0 -3
  15. package/dist/cli/commands/advanced.d.ts.map +0 -1
  16. package/dist/cli/commands/audience.d.ts +0 -18
  17. package/dist/cli/commands/audience.d.ts.map +0 -1
  18. package/dist/cli/commands/core.d.ts +0 -3
  19. package/dist/cli/commands/core.d.ts.map +0 -1
  20. package/dist/cli/commands/crm.d.ts +0 -3
  21. package/dist/cli/commands/crm.d.ts.map +0 -1
  22. package/dist/cli/index.d.ts +0 -3
  23. package/dist/cli/index.d.ts.map +0 -1
  24. package/dist/cli/storage.d.ts +0 -3
  25. package/dist/cli/storage.d.ts.map +0 -1
  26. package/dist/cli/utils.d.ts +0 -10
  27. package/dist/cli/utils.d.ts.map +0 -1
  28. package/dist/cloud/http-storage.d.ts +0 -88
  29. package/dist/cloud/http-storage.d.ts.map +0 -1
  30. package/dist/db/activity.d.ts +0 -15
  31. package/dist/db/activity.d.ts.map +0 -1
  32. package/dist/db/applications.d.ts +0 -10
  33. package/dist/db/applications.d.ts.map +0 -1
  34. package/dist/db/audiences.d.ts +0 -51
  35. package/dist/db/audiences.d.ts.map +0 -1
  36. package/dist/db/companies.d.ts +0 -19
  37. package/dist/db/companies.d.ts.map +0 -1
  38. package/dist/db/contact-tasks.d.ts +0 -19
  39. package/dist/db/contact-tasks.d.ts.map +0 -1
  40. package/dist/db/contacts.d.ts +0 -30
  41. package/dist/db/contacts.d.ts.map +0 -1
  42. package/dist/db/coordination.d.ts +0 -30
  43. package/dist/db/coordination.d.ts.map +0 -1
  44. package/dist/db/database.d.ts +0 -8
  45. package/dist/db/database.d.ts.map +0 -1
  46. package/dist/db/deals.d.ts +0 -14
  47. package/dist/db/deals.d.ts.map +0 -1
  48. package/dist/db/documents.d.ts +0 -38
  49. package/dist/db/documents.d.ts.map +0 -1
  50. package/dist/db/events.d.ts +0 -14
  51. package/dist/db/events.d.ts.map +0 -1
  52. package/dist/db/field-history.d.ts +0 -17
  53. package/dist/db/field-history.d.ts.map +0 -1
  54. package/dist/db/freshness.d.ts +0 -24
  55. package/dist/db/freshness.d.ts.map +0 -1
  56. package/dist/db/graph.d.ts +0 -21
  57. package/dist/db/graph.d.ts.map +0 -1
  58. package/dist/db/groups.d.ts +0 -22
  59. package/dist/db/groups.d.ts.map +0 -1
  60. package/dist/db/health.d.ts +0 -40
  61. package/dist/db/health.d.ts.map +0 -1
  62. package/dist/db/identity.d.ts +0 -32
  63. package/dist/db/identity.d.ts.map +0 -1
  64. package/dist/db/job-history.d.ts +0 -29
  65. package/dist/db/job-history.d.ts.map +0 -1
  66. package/dist/db/learnings.d.ts +0 -43
  67. package/dist/db/learnings.d.ts.map +0 -1
  68. package/dist/db/notes.d.ts +0 -8
  69. package/dist/db/notes.d.ts.map +0 -1
  70. package/dist/db/org-chart.d.ts +0 -37
  71. package/dist/db/org-chart.d.ts.map +0 -1
  72. package/dist/db/org-members.d.ts +0 -9
  73. package/dist/db/org-members.d.ts.map +0 -1
  74. package/dist/db/paths.d.ts +0 -3
  75. package/dist/db/paths.d.ts.map +0 -1
  76. package/dist/db/pg-migrations.d.ts +0 -8
  77. package/dist/db/pg-migrations.d.ts.map +0 -1
  78. package/dist/db/relationships.d.ts +0 -30
  79. package/dist/db/relationships.d.ts.map +0 -1
  80. package/dist/db/signals.d.ts +0 -18
  81. package/dist/db/signals.d.ts.map +0 -1
  82. package/dist/db/sqlite-adapter.d.ts +0 -15
  83. package/dist/db/sqlite-adapter.d.ts.map +0 -1
  84. package/dist/db/storage.d.ts +0 -15
  85. package/dist/db/storage.d.ts.map +0 -1
  86. package/dist/db/tags.d.ts +0 -14
  87. package/dist/db/tags.d.ts.map +0 -1
  88. package/dist/db/tombstones.d.ts +0 -19
  89. package/dist/db/tombstones.d.ts.map +0 -1
  90. package/dist/db/vendor-comms.d.ts +0 -15
  91. package/dist/db/vendor-comms.d.ts.map +0 -1
  92. package/dist/generated/storage-kit/health.d.ts +0 -20
  93. package/dist/generated/storage-kit/health.d.ts.map +0 -1
  94. package/dist/generated/storage-kit/index.d.ts +0 -8
  95. package/dist/generated/storage-kit/index.d.ts.map +0 -1
  96. package/dist/generated/storage-kit/migrations.d.ts +0 -48
  97. package/dist/generated/storage-kit/migrations.d.ts.map +0 -1
  98. package/dist/generated/storage-kit/mode.d.ts +0 -48
  99. package/dist/generated/storage-kit/mode.d.ts.map +0 -1
  100. package/dist/generated/storage-kit/pool.d.ts +0 -34
  101. package/dist/generated/storage-kit/pool.d.ts.map +0 -1
  102. package/dist/generated/storage-kit/query.d.ts +0 -36
  103. package/dist/generated/storage-kit/query.d.ts.map +0 -1
  104. package/dist/generated/storage-kit/tls.d.ts +0 -26
  105. package/dist/generated/storage-kit/tls.d.ts.map +0 -1
  106. package/dist/index.d.ts +0 -7
  107. package/dist/index.d.ts.map +0 -1
  108. package/dist/lib/apple-contacts.d.ts +0 -3
  109. package/dist/lib/apple-contacts.d.ts.map +0 -1
  110. package/dist/lib/audience-contract.d.ts +0 -215
  111. package/dist/lib/audience-contract.d.ts.map +0 -1
  112. package/dist/lib/audit.d.ts +0 -12
  113. package/dist/lib/audit.d.ts.map +0 -1
  114. package/dist/lib/brief.d.ts +0 -3
  115. package/dist/lib/brief.d.ts.map +0 -1
  116. package/dist/lib/config.d.ts +0 -7
  117. package/dist/lib/config.d.ts.map +0 -1
  118. package/dist/lib/connector.d.ts +0 -44
  119. package/dist/lib/connector.d.ts.map +0 -1
  120. package/dist/lib/context.d.ts +0 -5
  121. package/dist/lib/context.d.ts.map +0 -1
  122. package/dist/lib/dedup.d.ts +0 -10
  123. package/dist/lib/dedup.d.ts.map +0 -1
  124. package/dist/lib/document-scanner.d.ts +0 -8
  125. package/dist/lib/document-scanner.d.ts.map +0 -1
  126. package/dist/lib/embeddings.d.ts +0 -9
  127. package/dist/lib/embeddings.d.ts.map +0 -1
  128. package/dist/lib/export.d.ts +0 -8
  129. package/dist/lib/export.d.ts.map +0 -1
  130. package/dist/lib/freshness.d.ts +0 -19
  131. package/dist/lib/freshness.d.ts.map +0 -1
  132. package/dist/lib/gmail-import.d.ts +0 -51
  133. package/dist/lib/gmail-import.d.ts.map +0 -1
  134. package/dist/lib/google-contacts.d.ts +0 -115
  135. package/dist/lib/google-contacts.d.ts.map +0 -1
  136. package/dist/lib/images.d.ts +0 -30
  137. package/dist/lib/images.d.ts.map +0 -1
  138. package/dist/lib/import.d.ts +0 -10
  139. package/dist/lib/import.d.ts.map +0 -1
  140. package/dist/lib/learning-maintenance.d.ts +0 -8
  141. package/dist/lib/learning-maintenance.d.ts.map +0 -1
  142. package/dist/lib/mailery-sync.d.ts +0 -46
  143. package/dist/lib/mailery-sync.d.ts.map +0 -1
  144. package/dist/lib/meeting-capture.d.ts +0 -15
  145. package/dist/lib/meeting-capture.d.ts.map +0 -1
  146. package/dist/lib/package-version.d.ts +0 -6
  147. package/dist/lib/package-version.d.ts.map +0 -1
  148. package/dist/lib/signals.d.ts +0 -9
  149. package/dist/lib/signals.d.ts.map +0 -1
  150. package/dist/lib/signature-parser.d.ts +0 -36
  151. package/dist/lib/signature-parser.d.ts.map +0 -1
  152. package/dist/lib/stats.d.ts +0 -24
  153. package/dist/lib/stats.d.ts.map +0 -1
  154. package/dist/lib/timeline.d.ts +0 -11
  155. package/dist/lib/timeline.d.ts.map +0 -1
  156. package/dist/lib/upcoming.d.ts +0 -14
  157. package/dist/lib/upcoming.d.ts.map +0 -1
  158. package/dist/lib/vault.d.ts +0 -24
  159. package/dist/lib/vault.d.ts.map +0 -1
  160. package/dist/mcp/handlers/advanced.d.ts +0 -14
  161. package/dist/mcp/handlers/advanced.d.ts.map +0 -1
  162. package/dist/mcp/handlers/audience.d.ts +0 -9
  163. package/dist/mcp/handlers/audience.d.ts.map +0 -1
  164. package/dist/mcp/handlers/core.d.ts +0 -10
  165. package/dist/mcp/handlers/core.d.ts.map +0 -1
  166. package/dist/mcp/handlers/crm.d.ts +0 -14
  167. package/dist/mcp/handlers/crm.d.ts.map +0 -1
  168. package/dist/mcp/handlers/index.d.ts +0 -4
  169. package/dist/mcp/handlers/index.d.ts.map +0 -1
  170. package/dist/mcp/handlers/types.d.ts +0 -10
  171. package/dist/mcp/handlers/types.d.ts.map +0 -1
  172. package/dist/mcp/http.d.ts +0 -17
  173. package/dist/mcp/http.d.ts.map +0 -1
  174. package/dist/mcp/index.d.ts +0 -4
  175. package/dist/mcp/index.d.ts.map +0 -1
  176. package/dist/mcp/register-tools.d.ts +0 -3
  177. package/dist/mcp/register-tools.d.ts.map +0 -1
  178. package/dist/mcp/schema.d.ts +0 -3
  179. package/dist/mcp/schema.d.ts.map +0 -1
  180. package/dist/mcp/storage-tools.d.ts +0 -3
  181. package/dist/mcp/storage-tools.d.ts.map +0 -1
  182. package/dist/mcp/tools.d.ts +0 -3799
  183. package/dist/mcp/tools.d.ts.map +0 -1
  184. package/dist/sdk/index.d.ts +0 -16
  185. package/dist/sdk/index.d.ts.map +0 -1
  186. package/dist/sdk/v1.generated.d.ts +0 -203
  187. package/dist/sdk/v1.generated.d.ts.map +0 -1
  188. package/dist/server/cloud.d.ts +0 -51
  189. package/dist/server/cloud.d.ts.map +0 -1
  190. package/dist/server/index.d.ts +0 -3
  191. package/dist/server/index.d.ts.map +0 -1
  192. package/dist/server/openapi.d.ts +0 -765
  193. package/dist/server/openapi.d.ts.map +0 -1
  194. package/dist/server/pg-store.d.ts +0 -861
  195. package/dist/server/pg-store.d.ts.map +0 -1
  196. package/dist/server/security.d.ts +0 -24
  197. package/dist/server/security.d.ts.map +0 -1
  198. package/dist/server/serve.d.ts +0 -9
  199. package/dist/server/serve.d.ts.map +0 -1
  200. package/dist/server/v1.d.ts +0 -6
  201. package/dist/server/v1.d.ts.map +0 -1
  202. package/dist/store/index.d.ts +0 -383
  203. package/dist/store/index.d.ts.map +0 -1
  204. package/dist/types/index.d.ts +0 -856
  205. package/dist/types/index.d.ts.map +0 -1
@@ -4513,10 +4513,13 @@ var require_data = __commonJS((exports, module) => {
4513
4513
  };
4514
4514
  });
4515
4515
 
4516
- // node_modules/fast-uri/lib/utils.js
4516
+ // vendor/fast-uri/lib/utils.js
4517
4517
  var require_utils = __commonJS((exports, module) => {
4518
4518
  var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
4519
4519
  var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
4520
+ var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
4521
+ var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
4522
+ var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
4520
4523
  function stringArrayToHexStripped(input) {
4521
4524
  let acc = "";
4522
4525
  let code = 0;
@@ -4710,27 +4713,77 @@ var require_utils = __commonJS((exports, module) => {
4710
4713
  }
4711
4714
  return output.join("");
4712
4715
  }
4713
- function normalizeComponentEncoding(component, esc2) {
4714
- const func = esc2 !== true ? escape : unescape;
4715
- if (component.scheme !== undefined) {
4716
- component.scheme = func(component.scheme);
4717
- }
4718
- if (component.userinfo !== undefined) {
4719
- component.userinfo = func(component.userinfo);
4720
- }
4721
- if (component.host !== undefined) {
4722
- component.host = func(component.host);
4716
+ var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
4717
+ var HOST_DELIM_RE = /[@/?#:]/g;
4718
+ var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
4719
+ function reescapeHostDelimiters(host, isIP) {
4720
+ const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
4721
+ re.lastIndex = 0;
4722
+ return host.replace(re, (ch) => HOST_DELIMS[ch]);
4723
+ }
4724
+ function normalizePercentEncoding(input, decodeUnreserved = false) {
4725
+ if (input.indexOf("%") === -1) {
4726
+ return input;
4723
4727
  }
4724
- if (component.path !== undefined) {
4725
- component.path = func(component.path);
4728
+ let output = "";
4729
+ for (let i = 0;i < input.length; i++) {
4730
+ if (input[i] === "%" && i + 2 < input.length) {
4731
+ const hex = input.slice(i + 1, i + 3);
4732
+ if (isHexPair(hex)) {
4733
+ const normalizedHex = hex.toUpperCase();
4734
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
4735
+ if (decodeUnreserved && isUnreserved(decoded)) {
4736
+ output += decoded;
4737
+ } else {
4738
+ output += "%" + normalizedHex;
4739
+ }
4740
+ i += 2;
4741
+ continue;
4742
+ }
4743
+ }
4744
+ output += input[i];
4726
4745
  }
4727
- if (component.query !== undefined) {
4728
- component.query = func(component.query);
4746
+ return output;
4747
+ }
4748
+ function normalizePathEncoding(input) {
4749
+ let output = "";
4750
+ for (let i = 0;i < input.length; i++) {
4751
+ if (input[i] === "%" && i + 2 < input.length) {
4752
+ const hex = input.slice(i + 1, i + 3);
4753
+ if (isHexPair(hex)) {
4754
+ const normalizedHex = hex.toUpperCase();
4755
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
4756
+ if (decoded !== "." && isUnreserved(decoded)) {
4757
+ output += decoded;
4758
+ } else {
4759
+ output += "%" + normalizedHex;
4760
+ }
4761
+ i += 2;
4762
+ continue;
4763
+ }
4764
+ }
4765
+ if (isPathCharacter(input[i])) {
4766
+ output += input[i];
4767
+ } else {
4768
+ output += escape(input[i]);
4769
+ }
4729
4770
  }
4730
- if (component.fragment !== undefined) {
4731
- component.fragment = func(component.fragment);
4771
+ return output;
4772
+ }
4773
+ function escapePreservingEscapes(input) {
4774
+ let output = "";
4775
+ for (let i = 0;i < input.length; i++) {
4776
+ if (input[i] === "%" && i + 2 < input.length) {
4777
+ const hex = input.slice(i + 1, i + 3);
4778
+ if (isHexPair(hex)) {
4779
+ output += "%" + hex.toUpperCase();
4780
+ i += 2;
4781
+ continue;
4782
+ }
4783
+ }
4784
+ output += escape(input[i]);
4732
4785
  }
4733
- return component;
4786
+ return output;
4734
4787
  }
4735
4788
  function recomposeAuthority(component) {
4736
4789
  const uriTokens = [];
@@ -4745,7 +4798,7 @@ var require_utils = __commonJS((exports, module) => {
4745
4798
  if (ipV6res.isIPV6 === true) {
4746
4799
  host = `[${ipV6res.escapedHost}]`;
4747
4800
  } else {
4748
- host = component.host;
4801
+ host = reescapeHostDelimiters(host, false);
4749
4802
  }
4750
4803
  }
4751
4804
  uriTokens.push(host);
@@ -4759,7 +4812,10 @@ var require_utils = __commonJS((exports, module) => {
4759
4812
  module.exports = {
4760
4813
  nonSimpleDomain,
4761
4814
  recomposeAuthority,
4762
- normalizeComponentEncoding,
4815
+ reescapeHostDelimiters,
4816
+ normalizePercentEncoding,
4817
+ normalizePathEncoding,
4818
+ escapePreservingEscapes,
4763
4819
  removeDotSegments,
4764
4820
  isIPv4,
4765
4821
  isUUID,
@@ -4768,7 +4824,7 @@ var require_utils = __commonJS((exports, module) => {
4768
4824
  };
4769
4825
  });
4770
4826
 
4771
- // node_modules/fast-uri/lib/schemes.js
4827
+ // vendor/fast-uri/lib/schemes.js
4772
4828
  var require_schemes = __commonJS((exports, module) => {
4773
4829
  var { isUUID } = require_utils();
4774
4830
  var URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu;
@@ -4942,13 +4998,13 @@ var require_schemes = __commonJS((exports, module) => {
4942
4998
  };
4943
4999
  });
4944
5000
 
4945
- // node_modules/fast-uri/index.js
5001
+ // vendor/fast-uri/index.js
4946
5002
  var require_fast_uri = __commonJS((exports, module) => {
4947
- var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils();
5003
+ var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
4948
5004
  var { SCHEMES, getSchemeHandler } = require_schemes();
4949
5005
  function normalize(uri, options) {
4950
5006
  if (typeof uri === "string") {
4951
- uri = serialize(parse6(uri, options), options);
5007
+ uri = normalizeString(uri, options);
4952
5008
  } else if (typeof uri === "object") {
4953
5009
  uri = parse6(serialize(uri, options), options);
4954
5010
  }
@@ -5014,19 +5070,9 @@ var require_fast_uri = __commonJS((exports, module) => {
5014
5070
  return target;
5015
5071
  }
5016
5072
  function equal(uriA, uriB, options) {
5017
- if (typeof uriA === "string") {
5018
- uriA = unescape(uriA);
5019
- uriA = serialize(normalizeComponentEncoding(parse6(uriA, options), true), { ...options, skipEscape: true });
5020
- } else if (typeof uriA === "object") {
5021
- uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
5022
- }
5023
- if (typeof uriB === "string") {
5024
- uriB = unescape(uriB);
5025
- uriB = serialize(normalizeComponentEncoding(parse6(uriB, options), true), { ...options, skipEscape: true });
5026
- } else if (typeof uriB === "object") {
5027
- uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
5028
- }
5029
- return uriA.toLowerCase() === uriB.toLowerCase();
5073
+ const normalizedA = normalizeComparableURI(uriA, options);
5074
+ const normalizedB = normalizeComparableURI(uriB, options);
5075
+ return normalizedA !== undefined && normalizedB !== undefined && normalizedA.toLowerCase() === normalizedB.toLowerCase();
5030
5076
  }
5031
5077
  function serialize(cmpts, opts) {
5032
5078
  const component = {
@@ -5052,12 +5098,12 @@ var require_fast_uri = __commonJS((exports, module) => {
5052
5098
  schemeHandler.serialize(component, options);
5053
5099
  if (component.path !== undefined) {
5054
5100
  if (!options.skipEscape) {
5055
- component.path = escape(component.path);
5101
+ component.path = escapePreservingEscapes(component.path);
5056
5102
  if (component.scheme !== undefined) {
5057
5103
  component.path = component.path.split("%3A").join(":");
5058
5104
  }
5059
5105
  } else {
5060
- component.path = unescape(component.path);
5106
+ component.path = normalizePercentEncoding(component.path);
5061
5107
  }
5062
5108
  }
5063
5109
  if (options.reference !== "suffix" && component.scheme) {
@@ -5092,7 +5138,17 @@ var require_fast_uri = __commonJS((exports, module) => {
5092
5138
  return uriTokens.join("");
5093
5139
  }
5094
5140
  var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
5095
- function parse6(uri, opts) {
5141
+ var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
5142
+ function getParseError(parsed, matches) {
5143
+ if (matches[2] !== undefined && parsed.path && parsed.path[0] !== "/") {
5144
+ return 'URI path must start with "/" when authority is present.';
5145
+ }
5146
+ if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) {
5147
+ return "URI port is malformed.";
5148
+ }
5149
+ return;
5150
+ }
5151
+ function parseWithStatus(uri, opts) {
5096
5152
  const options = Object.assign({}, opts);
5097
5153
  const parsed = {
5098
5154
  scheme: undefined,
@@ -5103,6 +5159,7 @@ var require_fast_uri = __commonJS((exports, module) => {
5103
5159
  query: undefined,
5104
5160
  fragment: undefined
5105
5161
  };
5162
+ let malformedAuthorityOrPort = false;
5106
5163
  let isIP = false;
5107
5164
  if (options.reference === "suffix") {
5108
5165
  if (options.scheme) {
@@ -5111,6 +5168,11 @@ var require_fast_uri = __commonJS((exports, module) => {
5111
5168
  uri = "//" + uri;
5112
5169
  }
5113
5170
  }
5171
+ const authorityMatch = uri.match(AUTHORITY_PREFIX);
5172
+ if (authorityMatch !== null && authorityMatch[1].indexOf("\\") !== -1) {
5173
+ parsed.error = "URI authority must not contain a literal backslash.";
5174
+ malformedAuthorityOrPort = true;
5175
+ }
5114
5176
  const matches = uri.match(URI_PARSE);
5115
5177
  if (matches) {
5116
5178
  parsed.scheme = matches[1];
@@ -5123,6 +5185,11 @@ var require_fast_uri = __commonJS((exports, module) => {
5123
5185
  if (isNaN(parsed.port)) {
5124
5186
  parsed.port = matches[5];
5125
5187
  }
5188
+ const parseError = getParseError(parsed, matches);
5189
+ if (parseError !== undefined) {
5190
+ parsed.error = parsed.error || parseError;
5191
+ malformedAuthorityOrPort = true;
5192
+ }
5126
5193
  if (parsed.host) {
5127
5194
  const ipv4result = isIPv4(parsed.host);
5128
5195
  if (ipv4result === false) {
@@ -5149,7 +5216,7 @@ var require_fast_uri = __commonJS((exports, module) => {
5149
5216
  if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
5150
5217
  if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
5151
5218
  try {
5152
- parsed.host = URL.domainToASCII(parsed.host.toLowerCase());
5219
+ parsed.host = new URL("http://" + parsed.host).hostname;
5153
5220
  } catch (e) {
5154
5221
  parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
5155
5222
  }
@@ -5161,14 +5228,18 @@ var require_fast_uri = __commonJS((exports, module) => {
5161
5228
  parsed.scheme = unescape(parsed.scheme);
5162
5229
  }
5163
5230
  if (parsed.host !== undefined) {
5164
- parsed.host = unescape(parsed.host);
5231
+ parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
5165
5232
  }
5166
5233
  }
5167
5234
  if (parsed.path) {
5168
- parsed.path = escape(unescape(parsed.path));
5235
+ parsed.path = normalizePathEncoding(parsed.path);
5169
5236
  }
5170
5237
  if (parsed.fragment) {
5171
- parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
5238
+ try {
5239
+ parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
5240
+ } catch {
5241
+ parsed.error = parsed.error || "URI malformed";
5242
+ }
5172
5243
  }
5173
5244
  }
5174
5245
  if (schemeHandler && schemeHandler.parse) {
@@ -5177,7 +5248,29 @@ var require_fast_uri = __commonJS((exports, module) => {
5177
5248
  } else {
5178
5249
  parsed.error = parsed.error || "URI can not be parsed.";
5179
5250
  }
5180
- return parsed;
5251
+ return { parsed, malformedAuthorityOrPort };
5252
+ }
5253
+ function parse6(uri, opts) {
5254
+ return parseWithStatus(uri, opts).parsed;
5255
+ }
5256
+ function normalizeString(uri, opts) {
5257
+ return normalizeStringWithStatus(uri, opts).normalized;
5258
+ }
5259
+ function normalizeStringWithStatus(uri, opts) {
5260
+ const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
5261
+ return {
5262
+ normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
5263
+ malformedAuthorityOrPort
5264
+ };
5265
+ }
5266
+ function normalizeComparableURI(uri, opts) {
5267
+ if (typeof uri === "string") {
5268
+ const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
5269
+ return malformedAuthorityOrPort ? undefined : normalized;
5270
+ }
5271
+ if (typeof uri === "object") {
5272
+ return serialize(uri, opts);
5273
+ }
5181
5274
  }
5182
5275
  var fastUri = {
5183
5276
  SCHEMES,
@@ -8923,6 +9016,14 @@ var init_pg_migrations = __esm(() => {
8923
9016
  CREATE INDEX IF NOT EXISTS idx_contacts_tombstones_deleted_at ON _contacts_tombstones(deleted_at);
8924
9017
 
8925
9018
  INSERT INTO _migrations (version) VALUES (12) ON CONFLICT DO NOTHING;
9019
+ `,
9020
+ `
9021
+ -- The contact_tags primary key is (contact_id, tag_id), which does not
9022
+ -- support the public tag_id filter efficiently. Keep this forward-only and
9023
+ -- idempotent for populated cloud deployments.
9024
+ CREATE INDEX IF NOT EXISTS idx_contact_tags_tag_contact ON contact_tags(tag_id, contact_id);
9025
+
9026
+ INSERT INTO _migrations (version) VALUES (13) ON CONFLICT DO NOTHING;
8926
9027
  `
8927
9028
  ];
8928
9029
  });
@@ -8950,7 +9051,8 @@ function resolveSigningSecret(env = process.env) {
8950
9051
  return env.HASNA_CONTACTS_API_SIGNING_KEY || env.HASNA_API_SIGNING_KEY || env.API_KEY_SIGNING_SECRET || undefined;
8951
9052
  }
8952
9053
  function isCloudModeEnabled(env = process.env) {
8953
- return Boolean(resolveCloudDatabaseUrl(env));
9054
+ const mode = env.HASNA_CONTACTS_STORAGE_MODE || env.CONTACTS_STORAGE_MODE;
9055
+ return Boolean(resolveCloudDatabaseUrl(env)) || mode === "cloud" || mode === "self_hosted";
8954
9056
  }
8955
9057
  function getCloudClient() {
8956
9058
  if (cachedClient)
@@ -31019,8 +31121,13 @@ async function main() {
31019
31121
  await buildServer().connect(transport);
31020
31122
  console.error("Contacts MCP server running on stdio");
31021
31123
  }
31022
- var isDirectRun = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("mcp/index.ts") || process.argv[1]?.endsWith("mcp/index.js");
31023
- if (isDirectRun) {
31124
+ function isDirectMcpEntry(entry = process.argv[1]) {
31125
+ if (!entry)
31126
+ return false;
31127
+ const normalized = entry.replaceAll("\\", "/");
31128
+ return normalized.endsWith("/mcp/index.ts") || normalized.endsWith("/mcp/index.js");
31129
+ }
31130
+ if (isDirectMcpEntry()) {
31024
31131
  main().catch((err2) => {
31025
31132
  console.error("Fatal error:", err2);
31026
31133
  process.exit(1);
@@ -31252,6 +31359,19 @@ class ContactsPgStore {
31252
31359
  constructor(client) {
31253
31360
  this.client = client;
31254
31361
  }
31362
+ async attachTags(contacts) {
31363
+ const tagsByContactId = new Map(contacts.map((contact) => [contact.id, []]));
31364
+ if (contacts.length === 0)
31365
+ return [];
31366
+ const rows = await this.client.many(`SELECT ct.contact_id, t.*
31367
+ FROM contact_tags ct
31368
+ JOIN tags t ON t.id = ct.tag_id
31369
+ WHERE ct.contact_id = ANY($1::text[])
31370
+ ORDER BY t.name ASC`, [contacts.map((contact) => contact.id)]);
31371
+ for (const row of rows)
31372
+ tagsByContactId.get(row.contact_id)?.push(mapTag(row));
31373
+ return contacts.map((contact) => ({ ...contact, tags: tagsByContactId.get(contact.id) ?? [] }));
31374
+ }
31255
31375
  async listContacts(filter = {}) {
31256
31376
  const limit = Math.min(Math.max(filter.limit ?? 50, 1), 500);
31257
31377
  const offset = Math.max(filter.offset ?? 0, 0);
@@ -31265,6 +31385,10 @@ class ContactsPgStore {
31265
31385
  params.push(filter.status);
31266
31386
  where.push(`status = $${params.length}`);
31267
31387
  }
31388
+ if (filter.tag_id) {
31389
+ params.push(filter.tag_id);
31390
+ where.push(`EXISTS (SELECT 1 FROM contact_tags ct WHERE ct.contact_id = contacts.id AND ct.tag_id = $${params.length})`);
31391
+ }
31268
31392
  if (filter.q) {
31269
31393
  params.push(filter.q);
31270
31394
  where.push(`search_vector @@ plainto_tsquery('simple', $${params.length})`);
@@ -31273,11 +31397,13 @@ class ContactsPgStore {
31273
31397
  const countRow = await this.client.get(`SELECT COUNT(*)::text AS count FROM contacts ${whereSql}`, params);
31274
31398
  params.push(limit, offset);
31275
31399
  const rows = await this.client.many(`SELECT * FROM contacts ${whereSql} ORDER BY display_name ASC LIMIT $${params.length - 1} OFFSET $${params.length}`, params);
31276
- return { contacts: rows.map(mapContact), count: Number(countRow?.count ?? rows.length) };
31400
+ return { contacts: await this.attachTags(rows.map(mapContact)), count: Number(countRow?.count ?? rows.length) };
31277
31401
  }
31278
31402
  async getContact(id) {
31279
31403
  const row = await this.client.get(`SELECT * FROM contacts WHERE id = $1`, [id]);
31280
- return row ? mapContact(row) : null;
31404
+ if (!row)
31405
+ return null;
31406
+ return (await this.attachTags([mapContact(row)]))[0];
31281
31407
  }
31282
31408
  async createContact(input) {
31283
31409
  const id = uuid3();
@@ -31313,7 +31439,7 @@ class ContactsPgStore {
31313
31439
  input.priority ?? 3,
31314
31440
  input.timezone ?? null
31315
31441
  ]);
31316
- return mapContact(row);
31442
+ return (await this.attachTags([mapContact(row)]))[0];
31317
31443
  }
31318
31444
  async updateContact(id, input) {
31319
31445
  const allowed = {};
@@ -31353,7 +31479,7 @@ class ContactsPgStore {
31353
31479
  const sets = keys.map((k, i) => `${k} = $${i + 2}`);
31354
31480
  sets.push(`updated_at = NOW()`);
31355
31481
  const row = await this.client.get(`UPDATE contacts SET ${sets.join(", ")} WHERE id = $1 RETURNING *`, [id, ...keys.map((k) => allowed[k])]);
31356
- return row ? mapContact(row) : null;
31482
+ return row ? (await this.attachTags([mapContact(row)]))[0] : null;
31357
31483
  }
31358
31484
  async deleteContact(id) {
31359
31485
  const result = await this.client.query(`DELETE FROM contacts WHERE id = $1`, [id]);
@@ -32815,6 +32941,16 @@ async function readJson(req) {
32815
32941
  return null;
32816
32942
  }
32817
32943
  }
32944
+ function contactListFilterFromUrl(url) {
32945
+ return {
32946
+ ...url.searchParams.get("company_id") ? { company_id: url.searchParams.get("company_id") } : {},
32947
+ ...url.searchParams.get("status") ? { status: url.searchParams.get("status") } : {},
32948
+ ...url.searchParams.get("tag_id") ? { tag_id: url.searchParams.get("tag_id") } : {},
32949
+ ...url.searchParams.get("q") ? { q: url.searchParams.get("q") } : {},
32950
+ ...url.searchParams.get("limit") ? { limit: Number(url.searchParams.get("limit")) } : {},
32951
+ ...url.searchParams.get("offset") ? { offset: Number(url.searchParams.get("offset")) } : {}
32952
+ };
32953
+ }
32818
32954
  async function handleV1Request(req, url) {
32819
32955
  const path = url.pathname;
32820
32956
  if (path !== "/v1" && !path.startsWith("/v1/"))
@@ -32834,7 +32970,12 @@ async function handleV1Request(req, url) {
32834
32970
  }
32835
32971
  await ensureCloudSchemaBestEffort();
32836
32972
  const store = getContactsPgStore(getCloudClient());
32837
- const segments = path.split("/").filter(Boolean).map((segment) => decodeURIComponent(segment));
32973
+ let segments;
32974
+ try {
32975
+ segments = path.split("/").filter(Boolean).map((segment) => decodeURIComponent(segment));
32976
+ } catch {
32977
+ return error2(400, "invalid URL path encoding");
32978
+ }
32838
32979
  const resource = segments[1];
32839
32980
  const id = segments[2];
32840
32981
  const sub = segments[3];
@@ -32923,13 +33064,7 @@ async function handleV1Request(req, url) {
32923
33064
  if (resource === "contacts") {
32924
33065
  if (!id) {
32925
33066
  if (method === "GET") {
32926
- const result = await store.listContacts({
32927
- ...url.searchParams.get("company_id") ? { company_id: url.searchParams.get("company_id") } : {},
32928
- ...url.searchParams.get("status") ? { status: url.searchParams.get("status") } : {},
32929
- ...url.searchParams.get("q") ? { q: url.searchParams.get("q") } : {},
32930
- ...url.searchParams.get("limit") ? { limit: Number(url.searchParams.get("limit")) } : {},
32931
- ...url.searchParams.get("offset") ? { offset: Number(url.searchParams.get("offset")) } : {}
32932
- });
33067
+ const result = await store.listContacts(contactListFilterFromUrl(url));
32933
33068
  return json5(result);
32934
33069
  }
32935
33070
  if (method === "POST") {
@@ -33589,6 +33724,7 @@ function getPackageVersion() {
33589
33724
  // src/server/openapi.ts
33590
33725
  var contactSchema = {
33591
33726
  type: "object",
33727
+ required: ["tags"],
33592
33728
  properties: {
33593
33729
  id: { type: "string" },
33594
33730
  first_name: { type: "string" },
@@ -33603,6 +33739,7 @@ var contactSchema = {
33603
33739
  sensitivity: { type: "string" },
33604
33740
  archived: { type: "boolean" },
33605
33741
  priority: { type: "number" },
33742
+ tags: { type: "array", items: { $ref: "#/components/schemas/Tag" } },
33606
33743
  created_at: { type: "string" },
33607
33744
  updated_at: { type: "string" }
33608
33745
  }
@@ -33735,6 +33872,7 @@ function buildV1OpenApiDocument(version2 = getPackageVersion()) {
33735
33872
  { name: "q", in: "query", schema: { type: "string" } },
33736
33873
  { name: "company_id", in: "query", schema: { type: "string" } },
33737
33874
  { name: "status", in: "query", schema: { type: "string" } },
33875
+ { name: "tag_id", in: "query", schema: { type: "string" } },
33738
33876
  { name: "limit", in: "query", schema: { type: "number" } },
33739
33877
  { name: "offset", in: "query", schema: { type: "number" } }
33740
33878
  ],
@@ -0,0 +1,15 @@
1
+ -- @hasna/contacts cloud schema (A1 pure-remote) — generated from src/db/pg-migrations.ts
2
+ -- Idempotent and forward-only: retains deletion metadata for remote sync.
3
+
4
+ CREATE TABLE IF NOT EXISTS _contacts_tombstones (
5
+ table_name TEXT NOT NULL CHECK(table_name IN ('contacts','companies','tags')),
6
+ row_id TEXT NOT NULL,
7
+ deleted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
8
+ actor TEXT,
9
+ reason TEXT,
10
+ PRIMARY KEY (table_name, row_id)
11
+ );
12
+
13
+ CREATE INDEX IF NOT EXISTS idx_contacts_tombstones_deleted_at ON _contacts_tombstones(deleted_at);
14
+
15
+ INSERT INTO _migrations (version) VALUES (12) ON CONFLICT DO NOTHING;
@@ -0,0 +1,9 @@
1
+ -- @hasna/contacts cloud schema (A1 pure-remote) — generated from src/db/pg-migrations.ts
2
+ -- Idempotent and forward-only: supports GET /v1/contacts?tag_id=... filters.
3
+
4
+ -- The contact_tags primary key is (contact_id, tag_id), which does not
5
+ -- support the public tag_id filter efficiently. Keep this forward-only and
6
+ -- idempotent for populated cloud deployments.
7
+ CREATE INDEX IF NOT EXISTS idx_contact_tags_tag_contact ON contact_tags(tag_id, contact_id);
8
+
9
+ INSERT INTO _migrations (version) VALUES (13) ON CONFLICT DO NOTHING;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/contacts",
3
- "version": "0.6.32",
3
+ "version": "0.6.34",
4
4
  "description": "Contact management for AI coding agents — CLI + MCP + Web",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -26,6 +26,8 @@
26
26
  "migrations",
27
27
  "hasna.contract.json",
28
28
  "LICENSE",
29
+ "THIRD_PARTY_NOTICES.md",
30
+ "vendor/fast-uri/LICENSE",
29
31
  "README.md"
30
32
  ],
31
33
  "scripts": {
@@ -33,8 +35,8 @@
33
35
  "clean:core": "rm -rf dist",
34
36
  "build": "bun run clean && cd dashboard && bun run build && cd .. && bun run build:bundles && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",
35
37
  "build:core": "bun run clean:core && bun run build:bundles && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",
36
- "build:bundles": "bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external pg --external @hasna/contracts --external @modelcontextprotocol/sdk && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external pg --external @hasna/contracts --external @modelcontextprotocol/sdk && bun build src/server/index.ts --outdir dist/server --target bun --external pg --external @hasna/contracts && bun build src/sdk/index.ts --outdir dist/sdk --target bun && bun build src/index.ts --outdir dist --target bun --external pg --external @hasna/contracts",
37
- "build:server": "rm -rf dist/server dist/sdk && bun build src/server/index.ts --outdir dist/server --target bun --external pg --external @hasna/contracts",
38
+ "build:bundles": "bun run scripts/build-bundles.ts",
39
+ "build:server": "rm -rf dist/server dist/sdk && bun run scripts/build-bundles.ts --server-only",
38
40
  "generate:sdk": "bun run scripts/generate-sdk.ts",
39
41
  "migrate": "bun run scripts/migrate.ts",
40
42
  "typecheck": "tsc --noEmit",
@@ -75,7 +77,6 @@
75
77
  "dependencies": {
76
78
  "@hasna/contracts": "^0.5.1",
77
79
  "@hasna/events": "^0.1.6",
78
- "@modelcontextprotocol/sdk": "^1.12.1",
79
80
  "chalk": "^5.4.1",
80
81
  "commander": "^13.1.0",
81
82
  "ink": "^5.2.0",
@@ -87,6 +88,10 @@
87
88
  "@types/bun": "^1.2.4",
88
89
  "@types/pg": "^8.11.11",
89
90
  "@types/react": "^18.3.18",
91
+ "@modelcontextprotocol/sdk": "^1.12.1",
90
92
  "typescript": "^5.7.3"
93
+ },
94
+ "overrides": {
95
+ "fast-uri": "3.1.3"
91
96
  }
92
97
  }
@@ -0,0 +1,30 @@
1
+ Copyright (c) 2011-2021, Gary Court until https://github.com/garycourt/uri-js/commit/a1acf730b4bba3f1097c9f52e7d9d3aba8cdcaae
2
+ Copyright (c) 2021-present The Fastify team <https://github.com/fastify/fastify#team>
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+ * Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ * The names of any contributors may not be used to endorse or promote
13
+ products derived from this software without specific prior written
14
+ permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY
20
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+
27
+ * * *
28
+
29
+ The complete list of contributors can be found at:
30
+ - https://github.com/garycourt/uri-js/graphs/contributors
@@ -1 +0,0 @@
1
- /*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */@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-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction: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-duration:initial;--tw-space-x-reverse:0}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--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-200:oklch(88.5% .062 18.334);--color-red-800:oklch(44.4% .177 26.899);--color-red-900:oklch(39.6% .141 25.723);--color-red-950:oklch(25.8% .092 26.042);--color-yellow-50:oklch(98.7% .026 102.212);--color-yellow-200:oklch(94.5% .129 101.54);--color-yellow-800:oklch(47.6% .114 61.907);--color-yellow-950:oklch(28.6% .066 53.813);--color-green-50:oklch(98.2% .018 155.826);--color-green-200:oklch(92.5% .084 155.995);--color-green-800:oklch(44.8% .119 151.328);--color-green-900:oklch(39.3% .095 152.535);--color-green-950:oklch(26.6% .065 152.934);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--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-base:1rem;--text-base--line-height: 1.5 ;--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);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--animate-spin:spin 1s linear infinite;--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)}}@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%;-moz-tab-size:4;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]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}:root{--background:0 0% 100%;--foreground:222.2 84% 4.9%;--card:0 0% 100%;--card-foreground:222.2 84% 4.9%;--popover:0 0% 100%;--popover-foreground:222.2 84% 4.9%;--primary:221.2 83.2% 53.3%;--primary-foreground:210 40% 98%;--secondary:210 40% 96.1%;--secondary-foreground:222.2 47.4% 11.2%;--muted:210 40% 96.1%;--muted-foreground:215.4 16.3% 46.9%;--accent:210 40% 96.1%;--accent-foreground:222.2 47.4% 11.2%;--destructive:0 84.2% 60.2%;--destructive-foreground:210 40% 98%;--border:214.3 31.8% 91.4%;--input:214.3 31.8% 91.4%;--ring:221.2 83.2% 53.3%;--radius:.5rem}.dark{--background:222.2 84% 4.9%;--foreground:210 40% 98%;--card:222.2 84% 4.9%;--card-foreground:210 40% 98%;--popover:222.2 84% 4.9%;--popover-foreground:210 40% 98%;--primary:217.2 91.2% 59.8%;--primary-foreground:222.2 47.4% 11.2%;--secondary:217.2 32.6% 17.5%;--secondary-foreground:210 40% 98%;--muted:217.2 32.6% 17.5%;--muted-foreground:215 20.2% 65.1%;--accent:217.2 32.6% 17.5%;--accent-foreground:210 40% 98%;--destructive:0 62.8% 30.6%;--destructive-foreground:210 40% 98%;--border:217.2 32.6% 17.5%;--input:217.2 32.6% 17.5%;--ring:224.3 76.3% 48%}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground));min-height:100vh;margin:0;font-family:system-ui,-apple-system,sans-serif}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.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}.inset-0{inset:calc(var(--spacing) * 0)}.end{inset-inline-end:var(--spacing)}.top-4{top:calc(var(--spacing) * 4)}.top-\[50\%\]{top:50%}.right-1{right:calc(var(--spacing) * 1)}.right-2{right:calc(var(--spacing) * 2)}.right-4{right:calc(var(--spacing) * 4)}.right-6{right:calc(var(--spacing) * 6)}.bottom-6{bottom:calc(var(--spacing) * 6)}.left-2{left:calc(var(--spacing) * 2)}.left-3{left:calc(var(--spacing) * 3)}.left-\[50\%\]{left:50%}.z-50{z-index:50}.-mx-1{margin-inline:calc(var(--spacing) * -1)}.mx-auto{margin-inline:auto}.my-1{margin-block:calc(var(--spacing) * 1)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mr-1{margin-right:calc(var(--spacing) * 1)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-2{margin-left:calc(var(--spacing) * 2)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-flex{display:inline-flex}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.size-16{width:calc(var(--spacing) * 16);height:calc(var(--spacing) * 16)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-14{height:calc(var(--spacing) * 14)}.h-\[calc\(100vh-56px\)\]{height:calc(100vh - 56px)}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-full{height:100%}.h-px{height:1px}.max-h-96{max-height:calc(var(--spacing) * 96)}.max-h-\[90vh\]{max-height:90vh}.min-h-screen{min-height:100vh}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-9{width:calc(var(--spacing) * 9)}.w-80{width:calc(var(--spacing) * 80)}.w-full{width:100%}.max-w-7xl{max-width:var(--container-7xl)}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-xl{max-width:var(--container-xl)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[8rem\]{min-width:8rem}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.translate-x-\[-50\%\]{--tw-translate-x:-50%;translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-1{--tw-translate-y:calc(var(--spacing) * 1);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-\[-50\%\]{--tw-translate-y:-50%;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)}.scale-110{--tw-scale-x:110%;--tw-scale-y:110%;--tw-scale-z:110%;scale:var(--tw-scale-x) var(--tw-scale-y)}.rotate-0{rotate:0deg}.rotate-90{rotate:90deg}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.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-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}: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-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)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.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-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-green-200{border-color:var(--color-green-200)}.border-red-200{border-color:var(--color-red-200)}.border-transparent{border-color:#0000}.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-green-50{background-color:var(--color-green-50)}.bg-red-50{background-color:var(--color-red-50)}.bg-transparent{background-color:#0000}.bg-yellow-50{background-color:var(--color-yellow-50)}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1{padding-inline:calc(var(--spacing) * 1)}.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-3{padding-block:calc(var(--spacing) * 3)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.pt-0{padding-top:calc(var(--spacing) * 0)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pr-9{padding-right:calc(var(--spacing) * 9)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-6{padding-left:calc(var(--spacing) * 6)}.pl-8{padding-left:calc(var(--spacing) * 8)}.pl-9{padding-left:calc(var(--spacing) * 9)}.text-center{text-align:center}.text-left{text-align:left}.align-middle{vertical-align:middle}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--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-\[10px\]{font-size:10px}.leading-none{--tw-leading:1;line-height:1}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.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)}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-green-800{color:var(--color-green-800)}.text-red-800{color:var(--color-red-800)}.text-white{color:var(--color-white)}.text-yellow-800{color:var(--color-yellow-800)}.capitalize{text-transform:capitalize}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-30{opacity:.3}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.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-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-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px 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)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.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}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-transparent::file-selector-button{background-color:#0000}.file\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}@media(hover:hover){.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.hover\:opacity-100:hover{opacity:1}}.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-offset-2:focus{--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\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-1:focus-visible{--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-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}@media(min-width:40rem){.sm\:flex-row{flex-direction:row}.sm\:justify-end{justify-content:flex-end}:where(.sm\:space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * 2) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-x-reverse)))}.sm\:rounded-lg{border-radius:var(--radius-lg)}.sm\:text-left{text-align:left}}@media(min-width:48rem){.md\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}@media(prefers-color-scheme:dark){.dark\:scale-0{--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x) var(--tw-scale-y)}.dark\:scale-100{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}.dark\:-rotate-90{rotate:-90deg}.dark\:rotate-0{rotate:0deg}.dark\:border-green-900{border-color:var(--color-green-900)}.dark\:border-red-900{border-color:var(--color-red-900)}.dark\:bg-green-950{background-color:var(--color-green-950)}.dark\:bg-red-950{background-color:var(--color-red-950)}.dark\:bg-yellow-950{background-color:var(--color-yellow-950)}.dark\:text-green-200{color:var(--color-green-200)}.dark\:text-red-200{color:var(--color-red-200)}.dark\:text-yellow-200{color:var(--color-yellow-200)}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_tr\]\:border-b tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-style:var(--tw-border-style);border-width:0}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:calc(var(--spacing) * 0)}.\[\&\>\[role\=checkbox\]\]\:translate-y-\[2px\]>[role=checkbox]{--tw-translate-y:2px;translate:var(--tw-translate-x) var(--tw-translate-y)}.\[\&\>span\]\:line-clamp-1>span{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.\[\&\>svg\]\:size-4>svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\[\&\>svg\]\:shrink-0>svg{flex-shrink:0}.\[\&\>tr\]\:last\:border-b-0>tr:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}}@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-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{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-duration{syntax:"*";inherits:false}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@keyframes spin{to{transform:rotate(360deg)}}