lightly-studio 0.3.3__py3-none-any.whl → 0.4.0__py3-none-any.whl

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.

Potentially problematic release.


This version of lightly-studio might be problematic. Click here for more details.

Files changed (137) hide show
  1. lightly_studio/api/app.py +2 -0
  2. lightly_studio/api/features.py +3 -5
  3. lightly_studio/api/routes/api/caption.py +30 -0
  4. lightly_studio/api/routes/api/dataset_tag.py +10 -0
  5. lightly_studio/api/routes/api/embeddings2d.py +42 -39
  6. lightly_studio/api/routes/api/metadata.py +57 -1
  7. lightly_studio/core/add_samples.py +138 -0
  8. lightly_studio/core/dataset.py +232 -18
  9. lightly_studio/core/dataset_query/__init__.py +14 -0
  10. lightly_studio/core/sample.py +33 -1
  11. lightly_studio/dataset/loader.py +2 -8
  12. lightly_studio/db_manager.py +14 -6
  13. lightly_studio/dist_lightly_studio_view_app/_app/env.js +1 -1
  14. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.CN4hnTks.css +1 -0
  15. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/2.CkOblLn7.css +1 -0
  16. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/Samples.C0_eo9eP.css +1 -0
  17. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/{useFeatureFlags.CV-KWLNP.css → _layout.CefECEWA.css} +1 -1
  18. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.kFFGI0zL.css +1 -0
  19. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/transform.sLzR40om.css +1 -0
  20. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{6t3IJ0vQ.js → BOmrKuMn.js} +1 -1
  21. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{Cs1XmhiF.js → BPpOWbDa.js} +1 -1
  22. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BaFFwDFr.js +1 -0
  23. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BiGQqqJP.js +1 -0
  24. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BrNKoXwc.js +20 -0
  25. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BsaJCCG_.js +96 -0
  26. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BtXGzlpP.js +20 -0
  27. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C1FmrZbK.js +1 -0
  28. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C3xJX0nD.js +1 -0
  29. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CANX9QXL.js +1 -0
  30. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CAPx0Bfm.js +1 -0
  31. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CP9M7pei.js +39 -0
  32. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CWuDkrMZ.js +436 -0
  33. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/ChlxSwqI.js +1 -0
  34. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cj4nZbtb.js +1 -0
  35. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/ClzkJBWk.js +1 -0
  36. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CpbA3HU7.js +2 -0
  37. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D8ZGoCPm.js +3 -0
  38. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DMJzr1NB.js +1 -0
  39. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{BdfTHw61.js → DNJnBfHs.js} +1 -1
  40. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{keKYsoph.js → DUtlYNuP.js} +1 -1
  41. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DVxjPOJB.js +1 -0
  42. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DmGM9V9Q.js +1 -0
  43. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DoEId1MK.js +1 -0
  44. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DthpwYR_.js +2 -0
  45. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DyIcJj6J.js +1 -0
  46. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/SiegjVo0.js +1 -0
  47. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{BfHVnyNT.js → WEyXQRi6.js} +1 -1
  48. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/gBp1tBnA.js +1 -0
  49. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/xQhUoIl9.js +1 -0
  50. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.Y-sSoz5q.js +2 -0
  51. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.CvxVp0Cu.js +1 -0
  52. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.0Fm6E-5B.js +4 -0
  53. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/1.DB-0vkHb.js +1 -0
  54. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.vaUePh5k.js +1 -0
  55. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/11.7i7ljNVT.js +1 -0
  56. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/13.9qy3WtZv.js +1 -0
  57. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{2.C8HLK8mj.js → 2.Drwwdm7A.js} +267 -111
  58. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{3.CLvg3QcJ.js → 3.D3X_-Wan.js} +1 -1
  59. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{4.BQhDtXUI.js → 4.C9TqY3tA.js} +1 -1
  60. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.iRw6HCWX.js +39 -0
  61. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{6.uBV1Lhat.js → 6.fqfYR7dB.js} +1 -1
  62. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.C7gMM-gk.js +1 -0
  63. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.C4v1w-oS.js +20 -0
  64. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/9.DbHcSiMn.js +1 -0
  65. lightly_studio/dist_lightly_studio_view_app/_app/version.json +1 -1
  66. lightly_studio/dist_lightly_studio_view_app/index.html +15 -14
  67. lightly_studio/examples/example.py +4 -0
  68. lightly_studio/examples/example_coco.py +4 -0
  69. lightly_studio/examples/example_coco_caption.py +24 -0
  70. lightly_studio/examples/example_metadata.py +4 -1
  71. lightly_studio/examples/example_selection.py +4 -0
  72. lightly_studio/examples/example_split_work.py +4 -0
  73. lightly_studio/examples/example_yolo.py +4 -0
  74. lightly_studio/export/export_dataset.py +11 -3
  75. lightly_studio/metadata/compute_typicality.py +1 -1
  76. lightly_studio/models/caption.py +74 -0
  77. lightly_studio/models/dataset.py +1 -2
  78. lightly_studio/models/metadata.py +1 -1
  79. lightly_studio/models/sample.py +9 -2
  80. lightly_studio/models/settings.py +5 -0
  81. lightly_studio/resolvers/caption_resolver.py +80 -0
  82. lightly_studio/resolvers/dataset_resolver.py +6 -11
  83. lightly_studio/resolvers/metadata_resolver/__init__.py +2 -2
  84. lightly_studio/resolvers/metadata_resolver/sample/__init__.py +3 -3
  85. lightly_studio/resolvers/metadata_resolver/sample/bulk_update_metadata.py +46 -0
  86. lightly_studio/resolvers/sample_resolver.py +1 -0
  87. lightly_studio/resolvers/samples_filter.py +18 -10
  88. lightly_studio/resolvers/settings_resolver.py +3 -0
  89. lightly_studio/resolvers/twodim_embedding_resolver.py +29 -0
  90. lightly_studio/selection/__init__.py +1 -0
  91. lightly_studio/selection/mundig.py +41 -0
  92. lightly_studio/type_definitions.py +2 -0
  93. lightly_studio-0.4.0.dist-info/METADATA +78 -0
  94. {lightly_studio-0.3.3.dist-info → lightly_studio-0.4.0.dist-info}/RECORD +96 -88
  95. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.CA_CXIBb.css +0 -1
  96. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.DS78jgNY.css +0 -1
  97. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/index.BVs_sZj9.css +0 -1
  98. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/transform.D487hwJk.css +0 -1
  99. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/8NsknIT2.js +0 -1
  100. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BND_-4Kp.js +0 -1
  101. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BjkP1AHA.js +0 -1
  102. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BuuNVL9G.js +0 -1
  103. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BzKGpnl4.js +0 -1
  104. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CCx7Ho51.js +0 -1
  105. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CH6P3X75.js +0 -1
  106. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CR2upx_Q.js +0 -4
  107. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CWPZrTTJ.js +0 -1
  108. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CwPowJfP.js +0 -1
  109. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CxFKfZ9T.js +0 -1
  110. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cxevwdid.js +0 -1
  111. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D4whDBUi.js +0 -1
  112. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D6r9vr07.js +0 -1
  113. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DA6bFLPR.js +0 -1
  114. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DEgUu98i.js +0 -3
  115. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DGTPl6Gk.js +0 -1
  116. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DKGxBSlK.js +0 -1
  117. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DQXoLcsF.js +0 -1
  118. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DQe_kdRt.js +0 -92
  119. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DcY4jgG3.js +0 -1
  120. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/H7C68rOM.js +0 -1
  121. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/RmD8FzRo.js +0 -1
  122. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/V-MnMC1X.js +0 -1
  123. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.BVr6DYqP.js +0 -2
  124. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.u7zsVvqp.js +0 -1
  125. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.Da2agmdd.js +0 -1
  126. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/1.B11tVRJV.js +0 -1
  127. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.l30Zud4h.js +0 -1
  128. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.CgKPGcAP.js +0 -1
  129. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.-6XqWX5G.js +0 -1
  130. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.BXsgoQZh.js +0 -1
  131. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.BkbcnUs8.js +0 -1
  132. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/9.Bkrv-Vww.js +0 -1
  133. lightly_studio/resolvers/metadata_resolver/sample/bulk_set_metadata.py +0 -48
  134. lightly_studio/selection/README.md +0 -6
  135. lightly_studio-0.3.3.dist-info/METADATA +0 -814
  136. /lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{11.CWG1ehzT.js → 12.CWG1ehzT.js} +0 -0
  137. {lightly_studio-0.3.3.dist-info → lightly_studio-0.4.0.dist-info}/WHEEL +0 -0
@@ -6,6 +6,7 @@ from pathlib import Path
6
6
  from typing import Iterable, Iterator
7
7
  from uuid import UUID
8
8
 
9
+ import yaml
9
10
  from labelformat.formats import (
10
11
  COCOInstanceSegmentationInput,
11
12
  COCOObjectDetectionInput,
@@ -37,12 +38,15 @@ from lightly_studio.models.sample import SampleTable
37
38
  from lightly_studio.resolvers import (
38
39
  dataset_resolver,
39
40
  embedding_model_resolver,
41
+ sample_embedding_resolver,
40
42
  sample_resolver,
43
+ tag_resolver,
41
44
  )
42
45
  from lightly_studio.type_definitions import PathLike
43
46
 
44
47
  # Constants
45
48
  DEFAULT_DATASET_NAME = "default_dataset"
49
+ ALLOWED_YOLO_SPLITS = {"train", "val", "test", "minival"}
46
50
 
47
51
  _SliceType = slice # to avoid shadowing built-in slice in type annotations
48
52
 
@@ -50,7 +54,40 @@ _SliceType = slice # to avoid shadowing built-in slice in type annotations
50
54
  class Dataset:
51
55
  """A LightlyStudio Dataset.
52
56
 
53
- Keeps a reference to the underlying DatasetTable.
57
+ It can be created or loaded using one of the static methods:
58
+ ```python
59
+ dataset = Dataset.create()
60
+ dataset = Dataset.load()
61
+ dataset = Dataset.load_or_create()
62
+ ```
63
+
64
+ Samples can be added to the dataset using various methods:
65
+ ```python
66
+ dataset.add_samples_from_path(...)
67
+ dataset.add_samples_from_yolo(...)
68
+ dataset.add_samples_from_coco(...)
69
+ dataset.add_samples_from_coco_caption(...)
70
+ dataset.add_samples_from_labelformat(...)
71
+ ```
72
+
73
+ The dataset samples can be queried directly by iterating over it or slicing it:
74
+ ```python
75
+ dataset = Dataset.load("my_dataset")
76
+ first_ten_samples = dataset[:10]
77
+ for sample in dataset:
78
+ print(sample.file_name)
79
+ sample.metadata["new_key"] = "new_value"
80
+ ```
81
+
82
+ For filtering or ordering samples first, use the query interface:
83
+ ```python
84
+ from lightly_studio.core.dataset_query.sample_field import SampleField
85
+
86
+ dataset = Dataset.load("my_dataset")
87
+ query = dataset.match(SampleField.width > 10).order_by(SampleField.file_name)
88
+ for sample in query:
89
+ ...
90
+ ```
54
91
  """
55
92
 
56
93
  def __init__(self, dataset: DatasetTable) -> None:
@@ -68,7 +105,7 @@ class Dataset:
68
105
 
69
106
  dataset = dataset_resolver.create(
70
107
  session=db_manager.persistent_session(),
71
- dataset=DatasetCreate(name=name, directory=""),
108
+ dataset=DatasetCreate(name=name),
72
109
  )
73
110
  return Dataset(dataset=dataset)
74
111
 
@@ -81,7 +118,10 @@ class Dataset:
81
118
  dataset = dataset_resolver.get_by_name(session=db_manager.persistent_session(), name=name)
82
119
  if dataset is None:
83
120
  raise ValueError(f"Dataset with name '{name}' not found.")
84
-
121
+ # If we have embeddings in the database enable the FSC and embedding search features.
122
+ _enable_embedding_features_if_available(
123
+ session=db_manager.persistent_session(), dataset_id=dataset.dataset_id
124
+ )
85
125
  return Dataset(dataset=dataset)
86
126
 
87
127
  @staticmethod
@@ -94,6 +134,10 @@ class Dataset:
94
134
  if dataset is None:
95
135
  return Dataset.create(name=name)
96
136
 
137
+ # If we have embeddings in the database enable the FSC and embedding search features.
138
+ _enable_embedding_features_if_available(
139
+ session=db_manager.persistent_session(), dataset_id=dataset.dataset_id
140
+ )
97
141
  return Dataset(dataset=dataset)
98
142
 
99
143
  def __iter__(self) -> Iterator[Sample]:
@@ -262,14 +306,15 @@ class Dataset:
262
306
  def add_samples_from_yolo(
263
307
  self,
264
308
  data_yaml: PathLike,
265
- input_split: str = "train",
309
+ input_split: str | None = None,
266
310
  embed: bool = True,
267
311
  ) -> None:
268
312
  """Load a dataset in YOLO format and store in DB.
269
313
 
270
314
  Args:
271
315
  data_yaml: Path to the YOLO data.yaml file.
272
- input_split: The split to load (e.g., 'train', 'val').
316
+ input_split: The split to load (e.g., 'train', 'val', 'test').
317
+ If None, all available splits will be loaded and assigned a corresponding tag.
273
318
  embed: If True, generate embeddings for the newly added samples.
274
319
  """
275
320
  if isinstance(data_yaml, str):
@@ -279,24 +324,54 @@ class Dataset:
279
324
  if not data_yaml.is_file() or data_yaml.suffix != ".yaml":
280
325
  raise FileNotFoundError(f"YOLO data yaml file not found: '{data_yaml}'")
281
326
 
282
- # Load the dataset using labelformat.
283
- label_input = YOLOv8ObjectDetectionInput(
284
- input_file=data_yaml,
285
- input_split=input_split,
286
- )
287
- images_path = label_input._images_dir() # noqa: SLF001
327
+ # Determine which splits to process
328
+ splits_to_process = _resolve_yolo_splits(data_yaml=data_yaml, input_split=input_split)
288
329
 
289
- self.add_samples_from_labelformat(
290
- input_labels=label_input,
291
- images_path=images_path,
292
- embed=embed,
293
- )
330
+ all_created_sample_ids = []
331
+
332
+ # Process each split
333
+ for split in splits_to_process:
334
+ # Load the dataset using labelformat.
335
+ label_input = YOLOv8ObjectDetectionInput(
336
+ input_file=data_yaml,
337
+ input_split=split,
338
+ )
339
+ images_path = label_input._images_dir() # noqa: SLF001
340
+
341
+ created_sample_ids = add_samples.load_into_dataset_from_labelformat(
342
+ session=self.session,
343
+ dataset_id=self.dataset_id,
344
+ input_labels=label_input,
345
+ images_path=images_path,
346
+ )
347
+
348
+ # Tag samples with split name
349
+ if created_sample_ids:
350
+ tag = tag_resolver.get_or_create_sample_tag_by_name(
351
+ session=self.session,
352
+ dataset_id=self.dataset_id,
353
+ tag_name=split,
354
+ )
355
+ tag_resolver.add_sample_ids_to_tag_id(
356
+ session=self.session,
357
+ tag_id=tag.tag_id,
358
+ sample_ids=created_sample_ids,
359
+ )
360
+
361
+ all_created_sample_ids.extend(created_sample_ids)
362
+
363
+ # Generate embeddings for all samples at once
364
+ if embed:
365
+ _generate_embeddings(
366
+ session=self.session, dataset_id=self.dataset_id, sample_ids=all_created_sample_ids
367
+ )
294
368
 
295
369
  def add_samples_from_coco(
296
370
  self,
297
371
  annotations_json: PathLike,
298
372
  images_path: PathLike,
299
373
  annotation_type: AnnotationType = AnnotationType.OBJECT_DETECTION,
374
+ split: str | None = None,
300
375
  embed: bool = True,
301
376
  ) -> None:
302
377
  """Load a dataset in COCO Object Detection format and store in DB.
@@ -306,6 +381,8 @@ class Dataset:
306
381
  images_path: Path to the folder containing the images.
307
382
  annotation_type: The type of annotation to be loaded (e.g., 'ObjectDetection',
308
383
  'InstanceSegmentation').
384
+ split: Optional split name to tag samples (e.g., 'train', 'val').
385
+ If provided, all samples will be tagged with this name.
309
386
  embed: If True, generate embeddings for the newly added samples.
310
387
  """
311
388
  if isinstance(annotations_json, str):
@@ -330,12 +407,83 @@ class Dataset:
330
407
 
331
408
  images_path = Path(images_path).absolute()
332
409
 
333
- self.add_samples_from_labelformat(
410
+ created_sample_ids = add_samples.load_into_dataset_from_labelformat(
411
+ session=self.session,
412
+ dataset_id=self.dataset_id,
334
413
  input_labels=label_input,
335
414
  images_path=images_path,
336
- embed=embed,
337
415
  )
338
416
 
417
+ # Tag samples with split name if provided
418
+ if split is not None and created_sample_ids:
419
+ tag = tag_resolver.get_or_create_sample_tag_by_name(
420
+ session=self.session,
421
+ dataset_id=self.dataset_id,
422
+ tag_name=split,
423
+ )
424
+ tag_resolver.add_sample_ids_to_tag_id(
425
+ session=self.session,
426
+ tag_id=tag.tag_id,
427
+ sample_ids=created_sample_ids,
428
+ )
429
+
430
+ if embed:
431
+ _generate_embeddings(
432
+ session=self.session, dataset_id=self.dataset_id, sample_ids=created_sample_ids
433
+ )
434
+
435
+ def add_samples_from_coco_caption(
436
+ self,
437
+ annotations_json: PathLike,
438
+ images_path: PathLike,
439
+ split: str | None = None,
440
+ embed: bool = True,
441
+ ) -> None:
442
+ """Load a dataset in COCO caption format and store in DB.
443
+
444
+ Args:
445
+ annotations_json: Path to the COCO caption JSON file.
446
+ images_path: Path to the folder containing the images.
447
+ split: Optional split name to tag samples (e.g., 'train', 'val').
448
+ If provided, all samples will be tagged with this name.
449
+ embed: If True, generate embeddings for the newly added samples.
450
+ """
451
+ if isinstance(annotations_json, str):
452
+ annotations_json = Path(annotations_json)
453
+ annotations_json = annotations_json.absolute()
454
+
455
+ if not annotations_json.is_file() or annotations_json.suffix != ".json":
456
+ raise FileNotFoundError(f"COCO caption json file not found: '{annotations_json}'")
457
+
458
+ if isinstance(images_path, str):
459
+ images_path = Path(images_path)
460
+ images_path = images_path.absolute()
461
+
462
+ created_sample_ids = add_samples.load_into_dataset_from_coco_captions(
463
+ session=self.session,
464
+ dataset_id=self.dataset_id,
465
+ annotations_json=annotations_json,
466
+ images_path=images_path,
467
+ )
468
+
469
+ # Tag samples with split name if provided
470
+ if split is not None and created_sample_ids:
471
+ tag = tag_resolver.get_or_create_sample_tag_by_name(
472
+ session=self.session,
473
+ dataset_id=self.dataset_id,
474
+ tag_name=split,
475
+ )
476
+ tag_resolver.add_sample_ids_to_tag_id(
477
+ session=self.session,
478
+ tag_id=tag.tag_id,
479
+ sample_ids=created_sample_ids,
480
+ )
481
+
482
+ if embed:
483
+ _generate_embeddings(
484
+ session=self.session, dataset_id=self.dataset_id, sample_ids=created_sample_ids
485
+ )
486
+
339
487
  def compute_typicality_metadata(
340
488
  self,
341
489
  embedding_model_name: str | None = None,
@@ -393,3 +541,69 @@ def _generate_embeddings(session: Session, dataset_id: UUID, sample_ids: list[UU
393
541
  # Mark the embedding search feature as enabled.
394
542
  if "embeddingSearchEnabled" not in features.lightly_studio_active_features:
395
543
  features.lightly_studio_active_features.append("embeddingSearchEnabled")
544
+ # Mark the FSC feature as enabled.
545
+ if "fewShotClassifierEnabled" not in features.lightly_studio_active_features:
546
+ features.lightly_studio_active_features.append("fewShotClassifierEnabled")
547
+
548
+
549
+ def _resolve_yolo_splits(data_yaml: Path, input_split: str | None) -> list[str]:
550
+ """Determine which YOLO splits to process for the given config."""
551
+ if input_split is not None:
552
+ if input_split not in ALLOWED_YOLO_SPLITS:
553
+ raise ValueError(
554
+ f"Split '{input_split}' not found in config file '{data_yaml}'. "
555
+ f"Allowed splits: {sorted(ALLOWED_YOLO_SPLITS)}"
556
+ )
557
+ return [input_split]
558
+
559
+ with data_yaml.open() as f:
560
+ config = yaml.safe_load(f)
561
+
562
+ config_keys = config.keys() if isinstance(config, dict) else []
563
+ splits = [key for key in config_keys if key in ALLOWED_YOLO_SPLITS]
564
+ if not splits:
565
+ raise ValueError(f"No splits found in config file '{data_yaml}'")
566
+ return splits
567
+
568
+
569
+ def _are_embeddings_available(session: Session, dataset_id: UUID) -> bool:
570
+ """Check if there are any embeddings available for the given dataset.
571
+
572
+ Args:
573
+ session: Database session for resolver operations.
574
+ dataset_id: The ID of the dataset to check for embeddings.
575
+
576
+ Returns:
577
+ True if embeddings exist for the dataset, False otherwise.
578
+ """
579
+ embedding_manager = EmbeddingManagerProvider.get_embedding_manager()
580
+ model_id = embedding_manager.load_or_get_default_model(
581
+ session=session,
582
+ dataset_id=dataset_id,
583
+ )
584
+ if model_id is None:
585
+ # No default embedding model loaded for this dataset.
586
+ return False
587
+
588
+ return (
589
+ len(
590
+ sample_embedding_resolver.get_all_by_dataset_id(
591
+ session=session, dataset_id=dataset_id, embedding_model_id=model_id
592
+ )
593
+ )
594
+ > 0
595
+ )
596
+
597
+
598
+ def _enable_embedding_features_if_available(session: Session, dataset_id: UUID) -> None:
599
+ """Enable embedding-related features if embeddings are available in the DB.
600
+
601
+ Args:
602
+ session: Database session for resolver operations.
603
+ dataset_id: The ID of the dataset to check for embeddings.
604
+ """
605
+ if _are_embeddings_available(session=session, dataset_id=dataset_id):
606
+ if "embeddingSearchEnabled" not in features.lightly_studio_active_features:
607
+ features.lightly_studio_active_features.append("embeddingSearchEnabled")
608
+ if "fewShotClassifierEnabled" not in features.lightly_studio_active_features:
609
+ features.lightly_studio_active_features.append("fewShotClassifierEnabled")
@@ -0,0 +1,14 @@
1
+ from .boolean_expression import AND, NOT, OR
2
+ from .dataset_query import DatasetQuery
3
+ from .order_by import OrderByExpression, OrderByField
4
+ from .sample_field import SampleField
5
+
6
+ __all__ = [
7
+ "AND",
8
+ "NOT",
9
+ "OR",
10
+ "DatasetQuery",
11
+ "OrderByExpression",
12
+ "OrderByField",
13
+ "SampleField",
14
+ ]
@@ -50,7 +50,39 @@ class DBField(Generic[T]):
50
50
 
51
51
 
52
52
  class Sample:
53
- """Interface to a dataset sample."""
53
+ """Interface to a dataset sample.
54
+
55
+ It is usually returned by a query to the dataset.
56
+ ```python
57
+ for sample in dataset:
58
+ ...
59
+ ```
60
+
61
+ Many properties of the sample are directly accessible as attributes of this class.
62
+ ```python
63
+ print(f"Sample file name: {sample.file_name}")
64
+ print(f"Sample file path: {sample.file_path_abs}")
65
+ print(f"Sample width: {sample.width}")
66
+ print(f"Sample height: {sample.height}")
67
+ ```
68
+ Note that some attributes like the `sample_id` are technically writable, but changing
69
+ them is not recommended and may lead to inconsistent states.
70
+
71
+ Access sample's metadata via the `metadata` property, which
72
+ provides a dictionary-like interface to get and set metadata key-value pairs.
73
+ ```python
74
+ some_value = sample.metadata["some_key"]
75
+ sample.metadata["another_key"] = "new_value"
76
+ ```
77
+
78
+ Access sample's tags via the `tags` property.
79
+ ```python
80
+ sample.tags = ["tag1", "tag2"] # Replace all tags
81
+ print(f"Current tags: {sample.tags}")
82
+ sample.add_tag("tag_3")
83
+ sample.remove_tag("tag_1")
84
+ ```
85
+ """
54
86
 
55
87
  file_name = DBField(col(SampleTable.file_name))
56
88
  width = DBField(col(SampleTable.width))
@@ -258,10 +258,7 @@ class DatasetLoader:
258
258
  # Create dataset and annotation task.
259
259
  dataset = dataset_resolver.create(
260
260
  session=self.session,
261
- dataset=DatasetCreate(
262
- name=dataset_name,
263
- directory=str(img_dir_path),
264
- ),
261
+ dataset=DatasetCreate(name=dataset_name),
265
262
  )
266
263
 
267
264
  self._load_into_dataset(
@@ -296,10 +293,7 @@ class DatasetLoader:
296
293
  # Create dataset.
297
294
  dataset = dataset_resolver.create(
298
295
  session=self.session,
299
- dataset=DatasetCreate(
300
- name=dataset_name,
301
- directory=img_dir,
302
- ),
296
+ dataset=DatasetCreate(name=dataset_name),
303
297
  )
304
298
 
305
299
  # Collect image file paths with extension filtering.
@@ -47,8 +47,10 @@ class DatabaseEngine:
47
47
  @contextmanager
48
48
  def session(self) -> Generator[Session, None, None]:
49
49
  """Create a short-lived database session. The session is autoclosed."""
50
- # The code below addresses a foreign key constraint violation issue
51
- # with DuckDB. See LIG-7527 for more details.
50
+ # Commit the persistent session before creating a short-lived session.
51
+ # This prevents a foreign key constraint violation issue if the short-lived
52
+ # session attempts a delete of an object referencing an object modified
53
+ # in the persistent session.
52
54
  if self.get_persistent_session().in_transaction():
53
55
  logging.debug("The persistent session is in transaction, committing changes.")
54
56
  self.get_persistent_session().commit()
@@ -57,6 +59,11 @@ class DatabaseEngine:
57
59
  try:
58
60
  yield session
59
61
  session.commit()
62
+
63
+ # Commit the persistent session to ensure it sees the latest data changes.
64
+ # This prevents the persistent session from having stale data when it's used
65
+ # after operations in short-lived sessions have modified the database.
66
+ self.get_persistent_session().commit()
60
67
  except Exception:
61
68
  session.rollback()
62
69
  raise
@@ -66,7 +73,9 @@ class DatabaseEngine:
66
73
  def get_persistent_session(self) -> Session:
67
74
  """Get the persistent database session."""
68
75
  if self._persistent_session is None:
69
- self._persistent_session = Session(self._engine, close_resets_only=False)
76
+ self._persistent_session = Session(
77
+ self._engine, close_resets_only=False, expire_on_commit=True
78
+ )
70
79
  return self._persistent_session
71
80
 
72
81
 
@@ -78,11 +87,10 @@ def get_engine() -> DatabaseEngine:
78
87
  """Get the database engine.
79
88
 
80
89
  If the engine does not exist yet, it is newly created with the default settings.
81
- In that case, a pre-existing database file is deleted.
82
90
  """
83
91
  global _engine # noqa: PLW0603
84
92
  if _engine is None:
85
- _engine = DatabaseEngine(cleanup_existing=True)
93
+ _engine = DatabaseEngine()
86
94
  return _engine
87
95
 
88
96
 
@@ -94,7 +102,7 @@ def set_engine(engine: DatabaseEngine) -> None:
94
102
  _engine = engine
95
103
 
96
104
 
97
- def connect(db_file: str | None, cleanup_existing: bool = False) -> None:
105
+ def connect(db_file: str | None = None, cleanup_existing: bool = False) -> None:
98
106
  """Set up the database connection.
99
107
 
100
108
  Helper function to set up the database engine.
@@ -1 +1 @@
1
- export const env={"PUBLIC_SAMPLES_URL":"/images","PUBLIC_LIGHTLY_STUDIO_API_URL":"/"}
1
+ export const env={"PUBLIC_SAMPLES_URL":"/images","PUBLIC_LIGHTLY_STUDIO_API_URL":"/","PUBLIC_POSTHOG_DEV_KEY":"phc_A9K0pMRovzmhFhngbKAZIr2qZdA14eHvsZY6kjNdYWr","PUBLIC_POSTHOG_KEY":"","PUBLIC_POSTHOG_HOST":"https://eu.i.posthog.com"}
@@ -0,0 +1 @@
1
+ @font-face{font-family:Open Sans;src:url(./OpenSans-VariableFont_wdth_wght.BZBpG5Iz.ttf) format("truetype-variations");font-weight:100 1000;font-style:normal;font-display:swap}@font-face{font-family:Open Sans;src:url(./OpenSans-Italic-VariableFont_wdth_wght.B4AZ-wl6.ttf) format("truetype-variations");font-style:italic;font-weight:100 1000;font-display:swap}@font-face{font-family:Open Sans;src:url(./OpenSans-Regular.DxJTClRG.ttf) format("truetype");font-weight:400;font-style:normal;font-display:swap}@font-face{font-family:Open Sans;src:url(./OpenSans-Medium.DVUZMR_6.ttf) format("truetype");font-weight:500;font-style:normal;font-display:swap}@font-face{font-family:Open Sans;src:url(./OpenSans-SemiBold.D3TTYgdB.ttf) format("truetype");font-weight:600;font-style:normal;font-display:swap}@font-face{font-family:Open Sans;src:url(./OpenSans-Bold.DGvYQtcs.ttf) format("truetype");font-weight:700;font-style:normal;font-display:swap}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 100%;--foreground: 240 10% 3.9%;--card: 0 0% 100%;--card-foreground: 240 10% 3.9%;--diffuse: 0 0% 100%;--diffuse-foreground: 240 10% 3.9%;--popover: 0 0% 100%;--popover-foreground: 240 10% 3.9%;--primary: 42.1 76.2% 36.3%;--primary-foreground: 355.7 100% 97.3%;--secondary: 240 4.8% 95.9%;--secondary-foreground: 240 5.9% 10%;--muted: 240 4.8% 95.9%;--muted-foreground: 240 3.8% 46.1%;--accent: 240 4.8% 95.9%;--accent-foreground: 240 5.9% 10%;--destructive: 0 72.22% 50.59%;--destructive-foreground: 0 0% 98%;--border: 240 5.9% 90%;--border-hard: 240 5.9% 90%;--input: 240 5.9% 90%;--ring: 142.1 76.2% 36.3%;--radius: .5rem}.dark{--background: 20 14.3% 4.1%;--foreground: 0 0% 95%;--card: 220 16% 11%;--card-foreground: 0 0% 95%;--diffuse: 0 0% 95%;--diffuse-foreground: 0 0% 73.73%;--popover: 0 0% 9%;--popover-foreground: 0 0% 95%;--primary: var(--color-lightly-primary);--primary-foreground: 144.9 80.4% 10%;--secondary: 240 3.7% 15.9%;--secondary-foreground: 0 0% 98%;--muted: 0 0% 15%;--muted-foreground: 240 5% 64.9%;--accent: 12 6.5% 15.1%;--accent-foreground: 0 0% 98%;--destructive: 0 62.8% 30.6%;--destructive-foreground: 0 85.7% 97.3%;--border: 240 3.7% 15.9%;--border-hard: 223 12% 66%;--input: 240 3.7% 15.9%;--ring: 142.4 71.8% 29.2%}*{--tw-border-opacity: 1;border-color:hsl(var(--border) / var(--tw-border-opacity, 1))}body{--tw-bg-opacity: 1;background-color:hsl(var(--background) / var(--tw-bg-opacity, 1));--tw-text-opacity: 1;color:hsl(var(--foreground) / var(--tw-text-opacity, 1));font-family:Open Sans,sans-serif;font-size:16px}.container{width:100%;margin-right:auto;margin-left:auto;padding-right:2rem;padding-left:2rem}@media (min-width: 1400px){.container{max-width:1400px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.invisible{visibility:hidden}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.left-0{left:0}.left-1{left:.25rem}.left-2{left:.5rem}.left-4{left:1rem}.left-\[50\%\]{left:50%}.right-0{right:0}.right-4{right:1rem}.right-7{right:1.75rem}.top-0{top:0}.top-1{top:.25rem}.top-1\/2{top:50%}.top-2{top:.5rem}.top-4{top:1rem}.top-\[50\%\]{top:50%}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.col-span-3{grid-column:span 3 / span 3}.m-0{margin:0}.m-2{margin:.5rem}.-mx-1{margin-left:-.25rem;margin-right:-.25rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-4{margin-top:1rem;margin-bottom:1rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.box-content{box-sizing:content-box}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.\!table{display:table!important}.table{display:table}.grid{display:grid}.contents{display:contents}.hidden{display:none}.size-12{width:3rem;height:3rem}.size-3\.5{width:.875rem;height:.875rem}.size-4{width:1rem;height:1rem}.size-5{width:1.25rem;height:1.25rem}.size-6{width:1.5rem;height:1.5rem}.size-8{width:2rem;height:2rem}.size-9{width:2.25rem;height:2.25rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-2{height:.5rem}.h-28{height:7rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[1px\]{height:1px}.h-\[var\(--bits-select-anchor-height\)\]{height:var(--bits-select-anchor-height)}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-48{max-height:12rem}.max-h-96{max-height:24rem}.max-h-\[300px\]{max-height:300px}.min-h-0{min-height:0px}.min-h-44{min-height:11rem}.min-h-full{min-height:100%}.w-1{width:.25rem}.w-10{width:2.5rem}.w-2{width:.5rem}.w-3{width:.75rem}.w-3\/4{width:75%}.w-4{width:1rem}.w-4\/12{width:33.333333%}.w-56{width:14rem}.w-6{width:1.5rem}.w-72{width:18rem}.w-8{width:2rem}.w-80{width:20rem}.w-9{width:2.25rem}.w-\[1px\]{width:1px}.w-\[200px\]{width:200px}.w-\[320px\]{width:320px}.w-\[32px\]{width:32px}.w-\[375px\]{width:375px}.w-\[400px\]{width:400px}.w-\[480px\]{width:480px}.w-auto{width:auto}.w-full{width:100%}.w-px{width:1px}.w-screen{width:100vw}.min-w-0{min-width:0px}.min-w-\[250px\]{min-width:250px}.min-w-\[8rem\]{min-width:8rem}.min-w-\[var\(--bits-select-anchor-width\)\]{min-width:var(--bits-select-anchor-width)}.max-w-\[150px\]{max-width:150px}.max-w-\[200px\]{max-width:200px}.max-w-\[30\%\]{max-width:30%}.max-w-lg{max-width:32rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.flex-auto{flex:1 1 auto}.flex-none{flex:none}.flex-shrink-0,.shrink-0{flex-shrink:0}.grow{flex-grow:1}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[-50\%\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\[-50\%\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-col-resize{cursor:col-resize}.cursor-crosshair{cursor:crosshair}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize{resize:both}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.grid-cols-\[6rem_1fr\]{grid-template-columns:6rem 1fr}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-10{gap:2.5rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-y-3{row-gap:.75rem}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1rem * var(--tw-space-x-reverse));margin-left:calc(1rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-nowrap{text-wrap:nowrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-\[1vw\]{border-radius:1vw}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-b-lg{border-bottom-right-radius:var(--radius);border-bottom-left-radius:var(--radius)}.border{border-width:1px}.border-0{border-width:0px}.border-2{border-width:2px}.border-x{border-left-width:1px;border-right-width:1px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-accent-foreground\/20{border-color:hsl(var(--accent-foreground) / .2)}.border-border{--tw-border-opacity: 1;border-color:hsl(var(--border) / var(--tw-border-opacity, 1))}.border-border-hard{border-color:hsl(var(--border-hard) / .2)}.border-destructive\/50{border-color:hsl(var(--destructive) / .5)}.border-gray-800{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity, 1))}.border-input{--tw-border-opacity: 1;border-color:hsl(var(--input) / var(--tw-border-opacity, 1))}.border-primary{--tw-border-opacity: 1;border-color:hsl(var(--primary) / var(--tw-border-opacity, 1))}.border-red-400{--tw-border-opacity: 1;border-color:rgb(248 113 113 / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-white{--tw-border-opacity: 1;border-color:rgb(255 255 255 / var(--tw-border-opacity, 1))}.bg-accent{--tw-bg-opacity: 1;background-color:hsl(var(--accent) / var(--tw-bg-opacity, 1))}.bg-background{--tw-bg-opacity: 1;background-color:hsl(var(--background) / var(--tw-bg-opacity, 1))}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-black\/30{background-color:#0000004d}.bg-black\/60{background-color:#0009}.bg-black\/80{background-color:#000c}.bg-border{--tw-bg-opacity: 1;background-color:hsl(var(--border) / var(--tw-bg-opacity, 1))}.bg-border-hard{background-color:hsl(var(--border-hard) / .2)}.bg-card{--tw-bg-opacity: 1;background-color:hsl(var(--card) / var(--tw-bg-opacity, 1))}.bg-destructive{--tw-bg-opacity: 1;background-color:hsl(var(--destructive) / var(--tw-bg-opacity, 1))}.bg-muted{--tw-bg-opacity: 1;background-color:hsl(var(--muted) / var(--tw-bg-opacity, 1))}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.bg-popover{--tw-bg-opacity: 1;background-color:hsl(var(--popover) / var(--tw-bg-opacity, 1))}.bg-primary{--tw-bg-opacity: 1;background-color:hsl(var(--primary) / var(--tw-bg-opacity, 1))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity, 1))}.bg-secondary{--tw-bg-opacity: 1;background-color:hsl(var(--secondary) / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-opacity-20{--tw-bg-opacity: .2}.bg-opacity-80{--tw-bg-opacity: .8}.p-0{padding:0}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0{padding-top:0;padding-bottom:0}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-0{padding-bottom:0}.pb-4{padding-bottom:1rem}.pl-8{padding-left:2rem}.pr-2{padding-right:.5rem}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-start{text-align:start}.text-end{text-align:end}.align-baseline{vertical-align:baseline}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.italic{font-style:italic}.leading-none{line-height:1}.tracking-tight{letter-spacing:-.025em}.tracking-widest{letter-spacing:.1em}.text-current{color:currentColor}.text-destructive{--tw-text-opacity: 1;color:hsl(var(--destructive) / var(--tw-text-opacity, 1))}.text-destructive-foreground{--tw-text-opacity: 1;color:hsl(var(--destructive-foreground) / var(--tw-text-opacity, 1))}.text-diffuse-foreground{--tw-text-opacity: 1;color:hsl(var(--diffuse-foreground) / var(--tw-text-opacity, 1))}.text-foreground{--tw-text-opacity: 1;color:hsl(var(--foreground) / var(--tw-text-opacity, 1))}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-muted-foreground{--tw-text-opacity: 1;color:hsl(var(--muted-foreground) / var(--tw-text-opacity, 1))}.text-popover-foreground{--tw-text-opacity: 1;color:hsl(var(--popover-foreground) / var(--tw-text-opacity, 1))}.text-primary{--tw-text-opacity: 1;color:hsl(var(--primary) / var(--tw-text-opacity, 1))}.text-primary-foreground{--tw-text-opacity: 1;color:hsl(var(--primary-foreground) / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-secondary-foreground{--tw-text-opacity: 1;color:hsl(var(--secondary-foreground) / var(--tw-text-opacity, 1))}.text-transparent{color:transparent}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-0{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-primary{--tw-ring-opacity: 1;--tw-ring-color: hsl(var(--primary) / var(--tw-ring-opacity, 1))}.ring-ring{--tw-ring-opacity: 1;--tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity, 1))}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background) / 1)}.drop-shadow{--tw-drop-shadow: drop-shadow(0 1px 2px rgb(0 0 0 / .1)) drop-shadow(0 1px 1px rgb(0 0 0 / .06));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)}.invert{--tw-invert: invert(100%);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)}.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-sm{--tw-backdrop-blur: blur(4px);-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,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}@keyframes enter{0%{opacity:var(--tw-enter-opacity, 1);transform:translate3d(var(--tw-enter-translate-x, 0),var(--tw-enter-translate-y, 0),0) scale3d(var(--tw-enter-scale, 1),var(--tw-enter-scale, 1),var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity, 1);transform:translate3d(var(--tw-exit-translate-x, 0),var(--tw-exit-translate-y, 0),0) scale3d(var(--tw-exit-scale, 1),var(--tw-exit-scale, 1),var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0))}}.animate-in{animation-name:enter;animation-duration:.15s;--tw-enter-opacity: initial;--tw-enter-scale: initial;--tw-enter-rotate: initial;--tw-enter-translate-x: initial;--tw-enter-translate-y: initial}.fade-in-0{--tw-enter-opacity: 0}.zoom-in{--tw-enter-scale: 0}.zoom-in-95{--tw-enter-scale: .95}.zoom-out{--tw-exit-scale: 0}.duration-200{animation-duration:.2s}.ease-in-out{animation-timing-function:cubic-bezier(.4,0,.2,1)}@custom-variant dark (&:where(.dark,.dark *));:root{--color-lightly-primary: 159 64% 54%}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:.875rem;line-height:1.25rem}.file\:font-medium::file-selector-button{font-weight:500}.placeholder\:text-muted-foreground::-moz-placeholder{--tw-text-opacity: 1;color:hsl(var(--muted-foreground) / var(--tw-text-opacity, 1))}.placeholder\:text-muted-foreground::placeholder{--tw-text-opacity: 1;color:hsl(var(--muted-foreground) / var(--tw-text-opacity, 1))}.hover\:bg-accent:hover{--tw-bg-opacity: 1;background-color:hsl(var(--accent) / var(--tw-bg-opacity, 1))}.hover\:bg-accent\/50:hover{background-color:hsl(var(--accent) / .5)}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:text-accent-foreground:hover{--tw-text-opacity: 1;color:hsl(var(--accent-foreground) / var(--tw-text-opacity, 1))}.hover\:text-destructive:hover{--tw-text-opacity: 1;color:hsl(var(--destructive) / var(--tw-text-opacity, 1))}.hover\:text-foreground:hover{--tw-text-opacity: 1;color:hsl(var(--foreground) / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-ring:focus{--tw-ring-opacity: 1;--tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity, 1))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-opacity: 1;--tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity, 1))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.focus-visible\:ring-offset-background:focus-visible{--tw-ring-offset-color: hsl(var(--background) / 1)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.peer:disabled~.peer-disabled\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\:opacity-70{opacity:.7}.aria-selected\:bg-accent[aria-selected=true]{--tw-bg-opacity: 1;background-color:hsl(var(--accent) / var(--tw-bg-opacity, 1))}.aria-selected\:text-accent-foreground[aria-selected=true]{--tw-text-opacity: 1;color:hsl(var(--accent-foreground) / var(--tw-text-opacity, 1))}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[orientation\=\'horizontal\'\]\:h-2[data-orientation=horizontal]{height:.5rem}.data-\[orientation\=\'horizontal\'\]\:h-full[data-orientation=horizontal],.data-\[orientation\=\'vertical\'\]\:h-full[data-orientation=vertical]{height:100%}.data-\[orientation\=\'vertical\'\]\:min-h-44[data-orientation=vertical]{min-height:11rem}.data-\[orientation\=\'horizontal\'\]\:w-full[data-orientation=horizontal]{width:100%}.data-\[orientation\=\'vertical\'\]\:w-2[data-orientation=vertical]{width:.5rem}.data-\[orientation\=\'vertical\'\]\:w-auto[data-orientation=vertical]{width:auto}.data-\[orientation\=\'vertical\'\]\:w-full[data-orientation=vertical]{width:100%}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=checked\]\:translate-x-4[data-state=checked]{--tw-translate-x: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=unchecked\]\:translate-x-0[data-state=unchecked]{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[disabled\=true\]\:cursor-not-allowed[data-disabled=true]{cursor:not-allowed}.data-\[orientation\=\'vertical\'\]\:flex-col[data-orientation=vertical]{flex-direction:column}.data-\[highlighted\]\:bg-accent[data-highlighted]{--tw-bg-opacity: 1;background-color:hsl(var(--accent) / var(--tw-bg-opacity, 1))}.data-\[state\=active\]\:bg-background[data-state=active]{--tw-bg-opacity: 1;background-color:hsl(var(--background) / var(--tw-bg-opacity, 1))}.data-\[state\=checked\]\:bg-primary[data-state=checked]{--tw-bg-opacity: 1;background-color:hsl(var(--primary) / var(--tw-bg-opacity, 1))}.data-\[state\=open\]\:bg-secondary[data-state=open]{--tw-bg-opacity: 1;background-color:hsl(var(--secondary) / var(--tw-bg-opacity, 1))}.data-\[state\=unchecked\]\:bg-input[data-state=unchecked]{--tw-bg-opacity: 1;background-color:hsl(var(--input) / var(--tw-bg-opacity, 1))}.data-\[highlighted\]\:text-accent-foreground[data-highlighted]{--tw-text-opacity: 1;color:hsl(var(--accent-foreground) / var(--tw-text-opacity, 1))}.data-\[placeholder\]\:text-muted-foreground[data-placeholder]{--tw-text-opacity: 1;color:hsl(var(--muted-foreground) / var(--tw-text-opacity, 1))}.data-\[state\=active\]\:text-foreground[data-state=active]{--tw-text-opacity: 1;color:hsl(var(--foreground) / var(--tw-text-opacity, 1))}.data-\[state\=checked\]\:text-primary-foreground[data-state=checked]{--tw-text-opacity: 1;color:hsl(var(--primary-foreground) / var(--tw-text-opacity, 1))}.data-\[disabled\=true\]\:opacity-50[data-disabled=true],.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[state\=active\]\:shadow-sm[data-state=active]{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\[state\=closed\]\:duration-300[data-state=closed]{transition-duration:.3s}.data-\[state\=open\]\:duration-500[data-state=open]{transition-duration:.5s}.data-\[state\=open\]\:animate-in[data-state=open]{animation-name:enter;animation-duration:.15s;--tw-enter-opacity: initial;--tw-enter-scale: initial;--tw-enter-rotate: initial;--tw-enter-translate-x: initial;--tw-enter-translate-y: initial}.data-\[state\=closed\]\:animate-out[data-state=closed]{animation-name:exit;animation-duration:.15s;--tw-exit-opacity: initial;--tw-exit-scale: initial;--tw-exit-rotate: initial;--tw-exit-translate-x: initial;--tw-exit-translate-y: initial}.data-\[state\=closed\]\:fade-out-0[data-state=closed]{--tw-exit-opacity: 0}.data-\[state\=open\]\:fade-in-0[data-state=open]{--tw-enter-opacity: 0}.data-\[state\=closed\]\:zoom-out-95[data-state=closed]{--tw-exit-scale: .95}.data-\[state\=open\]\:zoom-in-95[data-state=open]{--tw-enter-scale: .95}.data-\[side\=bottom\]\:slide-in-from-top-2[data-side=bottom]{--tw-enter-translate-y: -.5rem}.data-\[side\=left\]\:slide-in-from-right-2[data-side=left]{--tw-enter-translate-x: .5rem}.data-\[side\=right\]\:slide-in-from-left-2[data-side=right]{--tw-enter-translate-x: -.5rem}.data-\[side\=top\]\:slide-in-from-bottom-2[data-side=top]{--tw-enter-translate-y: .5rem}.data-\[state\=closed\]\:slide-out-to-bottom[data-state=closed]{--tw-exit-translate-y: 100%}.data-\[state\=closed\]\:slide-out-to-left[data-state=closed]{--tw-exit-translate-x: -100%}.data-\[state\=closed\]\:slide-out-to-left-1\/2[data-state=closed]{--tw-exit-translate-x: -50%}.data-\[state\=closed\]\:slide-out-to-right[data-state=closed]{--tw-exit-translate-x: 100%}.data-\[state\=closed\]\:slide-out-to-top[data-state=closed]{--tw-exit-translate-y: -100%}.data-\[state\=closed\]\:slide-out-to-top-\[48\%\][data-state=closed]{--tw-exit-translate-y: -48%}.data-\[state\=open\]\:slide-in-from-bottom[data-state=open]{--tw-enter-translate-y: 100%}.data-\[state\=open\]\:slide-in-from-left[data-state=open]{--tw-enter-translate-x: -100%}.data-\[state\=open\]\:slide-in-from-left-1\/2[data-state=open]{--tw-enter-translate-x: -50%}.data-\[state\=open\]\:slide-in-from-right[data-state=open]{--tw-enter-translate-x: 100%}.data-\[state\=open\]\:slide-in-from-top[data-state=open]{--tw-enter-translate-y: -100%}.data-\[state\=open\]\:slide-in-from-top-\[48\%\][data-state=open]{--tw-enter-translate-y: -48%}.data-\[state\=closed\]\:duration-300[data-state=closed]{animation-duration:.3s}.data-\[state\=open\]\:duration-500[data-state=open]{animation-duration:.5s}.dark\:border-destructive:is(.dark *){--tw-border-opacity: 1;border-color:hsl(var(--destructive) / var(--tw-border-opacity, 1))}.dark\:bg-black:is(.dark *){--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.dark\:text-gray-600:is(.dark *){--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.dark\:\[color-scheme\:dark\]:is(.dark *){color-scheme:dark}@media (min-width: 640px){.sm\:inline{display:inline}.sm\:max-w-\[425px\]{max-width:425px}.sm\:max-w-\[500px\]{max-width:500px}.sm\:max-w-sm{max-width:24rem}.sm\:flex-row{flex-direction:row}.sm\:justify-end{justify-content:flex-end}.sm\:gap-2\.5{gap:.625rem}.sm\:space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.sm\:rounded-lg{border-radius:var(--radius)}.sm\:text-left{text-align:left}}@media (min-width: 768px){.md\:text-sm{font-size:.875rem;line-height:1.25rem}}.\[\&\>span\]\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\[\&\>svg\]\:absolute>svg{position:absolute}.\[\&\>svg\]\:left-4>svg{left:1rem}.\[\&\>svg\]\:top-4>svg{top:1rem}.\[\&\>svg\]\:size-3\.5>svg{width:.875rem;height:.875rem}.\[\&\>svg\]\:text-destructive>svg{--tw-text-opacity: 1;color:hsl(var(--destructive) / var(--tw-text-opacity, 1))}.\[\&\>svg\]\:text-foreground>svg{--tw-text-opacity: 1;color:hsl(var(--foreground) / var(--tw-text-opacity, 1))}.\[\&\>svg\~\*\]\:pl-7>svg~*{padding-left:1.75rem}.\[\&_\[data-command-group\]\:not\(\[hidden\]\)_\~\[data-command-group\]\]\:pt-0 [data-command-group]:not([hidden])~[data-command-group]{padding-top:0}.\[\&_\[data-command-group\]\]\:px-2 [data-command-group]{padding-left:.5rem;padding-right:.5rem}.\[\&_\[data-command-input-wrapper\]_svg\]\:h-5 [data-command-input-wrapper] svg{height:1.25rem}.\[\&_\[data-command-input-wrapper\]_svg\]\:w-5 [data-command-input-wrapper] svg{width:1.25rem}.\[\&_\[data-command-input\]\]\:h-12 [data-command-input]{height:3rem}.\[\&_\[data-command-item\]\]\:px-2 [data-command-item]{padding-left:.5rem;padding-right:.5rem}.\[\&_\[data-command-item\]\]\:py-3 [data-command-item]{padding-top:.75rem;padding-bottom:.75rem}.\[\&_\[data-command-item\]_svg\]\:h-5 [data-command-item] svg{height:1.25rem}.\[\&_\[data-command-item\]_svg\]\:w-5 [data-command-item] svg{width:1.25rem}.\[\&_p\]\:leading-relaxed p{line-height:1.625}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:1rem;height:1rem}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}html[dir=ltr],[data-sonner-toaster][dir=ltr]{--toast-icon-margin-start: -3px;--toast-icon-margin-end: 4px;--toast-svg-margin-start: -1px;--toast-svg-margin-end: 0px;--toast-button-margin-start: auto;--toast-button-margin-end: 0;--toast-close-button-start: 0;--toast-close-button-end: unset;--toast-close-button-transform: translate(-35%, -35%)}html[dir=rtl],[data-sonner-toaster][dir=rtl]{--toast-icon-margin-start: 4px;--toast-icon-margin-end: -3px;--toast-svg-margin-start: 0px;--toast-svg-margin-end: -1px;--toast-button-margin-start: 0;--toast-button-margin-end: auto;--toast-close-button-start: unset;--toast-close-button-end: 0;--toast-close-button-transform: translate(35%, -35%)}[data-sonner-toaster]{position:fixed;width:var(--width);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;--gray1: hsl(0, 0%, 99%);--gray2: hsl(0, 0%, 97.3%);--gray3: hsl(0, 0%, 95.1%);--gray4: hsl(0, 0%, 93%);--gray5: hsl(0, 0%, 90.9%);--gray6: hsl(0, 0%, 88.7%);--gray7: hsl(0, 0%, 85.8%);--gray8: hsl(0, 0%, 78%);--gray9: hsl(0, 0%, 56.1%);--gray10: hsl(0, 0%, 52.3%);--gray11: hsl(0, 0%, 43.5%);--gray12: hsl(0, 0%, 9%);--border-radius: 8px;box-sizing:border-box;padding:0;margin:0;list-style:none;outline:none;z-index:999999999;transition:transform .4s ease}@media (hover: none) and (pointer: coarse){[data-sonner-toaster][data-lifted=true]{transform:none}}[data-sonner-toaster][data-x-position=right]{right:var(--offset-right)}[data-sonner-toaster][data-x-position=left]{left:var(--offset-left)}[data-sonner-toaster][data-x-position=center]{left:50%;transform:translate(-50%)}[data-sonner-toaster][data-y-position=top]{top:var(--offset-top)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--offset-bottom)}[data-sonner-toast]{--y: translateY(100%);--lift-amount: calc(var(--lift) * var(--gap));z-index:var(--z-index);position:absolute;opacity:0;transform:var(--y);touch-action:none;transition:transform .4s,opacity .4s,height .4s,box-shadow .2s;box-sizing:border-box;outline:none;overflow-wrap:anywhere}[data-sonner-toast][data-styled=true]{padding:16px;background:var(--normal-bg);border:1px solid var(--normal-border);color:var(--normal-text);border-radius:var(--border-radius);box-shadow:0 4px 12px #0000001a;width:var(--width);font-size:13px;display:flex;align-items:center;gap:6px}[data-sonner-toast]:focus-visible{box-shadow:0 4px 12px #0000001a,0 0 0 2px #0003}[data-sonner-toast][data-y-position=top]{top:0;--y: translateY(-100%);--lift: 1;--lift-amount: calc(1 * var(--gap))}[data-sonner-toast][data-y-position=bottom]{bottom:0;--y: translateY(100%);--lift: -1;--lift-amount: calc(var(--lift) * var(--gap))}[data-sonner-toast][data-styled=true] [data-description]{font-weight:400;line-height:1.4;color:#3f3f3f}[data-rich-colors=true][data-sonner-toast][data-styled=true] [data-description]{color:inherit}[data-sonner-toaster][data-sonner-theme=dark] [data-description]{color:#e8e8e8}[data-sonner-toast][data-styled=true] [data-title]{font-weight:500;line-height:1.5;color:inherit}[data-sonner-toast][data-styled=true] [data-icon]{display:flex;height:16px;width:16px;position:relative;justify-content:flex-start;align-items:center;flex-shrink:0;margin-left:var(--toast-icon-margin-start);margin-right:var(--toast-icon-margin-end)}[data-sonner-toast][data-promise=true] [data-icon]>svg{opacity:0;transform:scale(.8);transform-origin:center;animation:sonner-fade-in .3s ease forwards}[data-sonner-toast][data-styled=true] [data-icon]>*{flex-shrink:0}[data-sonner-toast][data-styled=true] [data-icon] svg{margin-left:var(--toast-svg-margin-start);margin-right:var(--toast-svg-margin-end)}[data-sonner-toast][data-styled=true] [data-content]{display:flex;flex-direction:column;gap:2px}[data-sonner-toast][data-styled=true] [data-button]{border-radius:4px;padding-left:8px;padding-right:8px;height:24px;font-size:12px;color:var(--normal-bg);background:var(--normal-text);margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end);border:none;font-weight:500;cursor:pointer;outline:none;display:flex;align-items:center;flex-shrink:0;transition:opacity .4s,box-shadow .2s}[data-sonner-toast][data-styled=true] [data-button]:focus-visible{box-shadow:0 0 0 2px #0006}[data-sonner-toast][data-styled=true] [data-button]:first-of-type{margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end)}[data-sonner-toast][data-styled=true] [data-cancel]{color:var(--normal-text);background:#00000014}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-styled=true] [data-cancel]{background:#ffffff4d}[data-sonner-toast][data-styled=true] [data-close-button]{position:absolute;left:var(--toast-close-button-start);right:var(--toast-close-button-end);top:0;height:20px;width:20px;display:flex;justify-content:center;align-items:center;padding:0;color:var(--gray12);background:var(--normal-bg);border:1px solid var(--gray4);transform:var(--toast-close-button-transform);border-radius:50%;cursor:pointer;z-index:1;transition:opacity .1s,background .2s,border-color .2s}[data-sonner-toast][data-styled=true] [data-close-button]:focus-visible{box-shadow:0 4px 12px #0000001a,0 0 0 2px #0003}[data-sonner-toast][data-styled=true] [data-disabled=true]{cursor:not-allowed}[data-sonner-toast][data-styled=true]:hover [data-close-button]:hover{background:var(--gray2);border-color:var(--gray5)}[data-sonner-toast][data-swiping=true]:before{content:"";position:absolute;left:-100%;right:-100%;height:100%;z-index:-1}[data-sonner-toast][data-y-position=top][data-swiping=true]:before{bottom:50%;transform:scaleY(3) translateY(50%)}[data-sonner-toast][data-y-position=bottom][data-swiping=true]:before{top:50%;transform:scaleY(3) translateY(-50%)}[data-sonner-toast][data-swiping=false][data-removed=true]:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;transform:scaleY(2)}[data-sonner-toast][data-expanded=true]:after{content:"";position:absolute;left:0;height:calc(var(--gap) + 1px);bottom:100%;width:100%}[data-sonner-toast][data-mounted=true]{--y: translateY(0);opacity:1}[data-sonner-toast][data-expanded=false][data-front=false]{--scale: var(--toasts-before) * .05 + 1;--y: translateY(calc(var(--lift-amount) * var(--toasts-before))) scale(calc(-1 * var(--scale)));height:var(--front-toast-height)}[data-sonner-toast]>*{transition:opacity .4s}[data-sonner-toast][data-x-position=right]{right:0}[data-sonner-toast][data-x-position=left]{left:0}[data-sonner-toast][data-expanded=false][data-front=false][data-styled=true]>*{opacity:0}[data-sonner-toast][data-visible=false]{opacity:0;pointer-events:none}[data-sonner-toast][data-mounted=true][data-expanded=true]{--y: translateY(calc(var(--lift) * var(--offset)));height:var(--initial-height)}[data-sonner-toast][data-removed=true][data-front=true][data-swipe-out=false]{--y: translateY(calc(var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=true]{--y: translateY( calc(var(--lift) * var(--offset) + var(--lift) * -100%) );opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=false]{--y: translateY(40%);opacity:0;transition:transform .5s,opacity .2s}[data-sonner-toast][data-removed=true][data-front=false]:before{height:calc(var(--initial-height) + 20%)}[data-sonner-toast][data-swiping=true]{transform:var(--y) translateY(var(--swipe-amount-y, 0px)) translate(var(--swipe-amount-x, 0px));transition:none}[data-sonner-toast][data-swiped=true]{-webkit-user-select:none;-moz-user-select:none;user-select:none}[data-sonner-toast][data-swipe-out=true][data-y-position=bottom],[data-sonner-toast][data-swipe-out=true][data-y-position=top]{animation-duration:.2s;animation-timing-function:ease-out;animation-fill-mode:forwards}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=left]{animation-name:swipe-out-left}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=right]{animation-name:swipe-out-right}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=up]{animation-name:swipe-out-up}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=down]{animation-name:swipe-out-down}@keyframes swipe-out-left{0%{transform:var(--y) translate(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translate(calc(var(--swipe-amount-x) - 100%));opacity:0}}@keyframes swipe-out-right{0%{transform:var(--y) translate(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translate(calc(var(--swipe-amount-x) + 100%));opacity:0}}@keyframes swipe-out-up{0%{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) - 100%));opacity:0}}@keyframes swipe-out-down{0%{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) + 100%));opacity:0}}@media (max-width: 600px){[data-sonner-toaster]{position:fixed;right:var(--mobile-offset-right);left:var(--mobile-offset-left);width:100%}[data-sonner-toaster][dir=rtl]{left:calc(var(--mobile-offset-left) * -1)}[data-sonner-toaster] [data-sonner-toast]{left:0;right:0;width:calc(100% - var(--mobile-offset-left) * 2)}[data-sonner-toaster][data-x-position=left]{left:var(--mobile-offset-left)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--mobile-offset-bottom)}[data-sonner-toaster][data-y-position=top]{top:var(--mobile-offset-top)}[data-sonner-toaster][data-x-position=center]{left:var(--mobile-offset-left);right:var(--mobile-offset-right);transform:none}}[data-sonner-toaster][data-sonner-theme=light]{--normal-bg: #fff;--normal-border: var(--gray4);--normal-text: var(--gray12);--success-bg: hsl(143, 85%, 96%);--success-border: hsl(145, 92%, 87%);--success-text: hsl(140, 100%, 27%);--info-bg: hsl(208, 100%, 97%);--info-border: hsl(221, 91%, 93%);--info-text: hsl(210, 92%, 45%);--warning-bg: hsl(49, 100%, 97%);--warning-border: hsl(49, 91%, 84%);--warning-text: hsl(31, 92%, 45%);--error-bg: hsl(359, 100%, 97%);--error-border: hsl(359, 100%, 94%);--error-text: hsl(360, 100%, 45%)}[data-sonner-toaster][data-sonner-theme=light] [data-sonner-toast][data-invert=true]{--normal-bg: #000;--normal-border: hsl(0, 0%, 20%);--normal-text: var(--gray1)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-invert=true]{--normal-bg: #fff;--normal-border: var(--gray3);--normal-text: var(--gray12)}[data-sonner-toaster][data-sonner-theme=dark]{--normal-bg: #000;--normal-bg-hover: hsl(0, 0%, 12%);--normal-border: hsl(0, 0%, 20%);--normal-border-hover: hsl(0, 0%, 25%);--normal-text: var(--gray1);--success-bg: hsl(150, 100%, 6%);--success-border: hsl(147, 100%, 12%);--success-text: hsl(150, 86%, 65%);--info-bg: hsl(215, 100%, 6%);--info-border: hsl(223, 43%, 17%);--info-text: hsl(216, 87%, 65%);--warning-bg: hsl(64, 100%, 6%);--warning-border: hsl(60, 100%, 9%);--warning-text: hsl(46, 87%, 65%);--error-bg: hsl(358, 76%, 10%);--error-border: hsl(357, 89%, 16%);--error-text: hsl(358, 100%, 81%)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]{background:var(--normal-bg);border-color:var(--normal-border);color:var(--normal-text)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]:hover{background:var(--normal-bg-hover);border-color:var(--normal-border-hover)}[data-rich-colors=true][data-sonner-toast][data-type=success],[data-rich-colors=true][data-sonner-toast][data-type=success] [data-close-button]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=info],[data-rich-colors=true][data-sonner-toast][data-type=info] [data-close-button]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning],[data-rich-colors=true][data-sonner-toast][data-type=warning] [data-close-button]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=error],[data-rich-colors=true][data-sonner-toast][data-type=error] [data-close-button]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}.sonner-loading-wrapper{--size: 16px;height:var(--size);width:var(--size);position:absolute;top:0;right:0;bottom:0;left:0;z-index:10}.sonner-loading-wrapper[data-visible=false]{transform-origin:center;animation:sonner-fade-out .2s ease forwards}.sonner-spinner{position:relative;top:50%;left:50%;height:var(--size);width:var(--size)}.sonner-loading-bar{animation:sonner-spin 1.2s linear infinite;background:var(--gray11);border-radius:6px;height:8%;left:-10%;position:absolute;top:-3.9%;width:24%}.sonner-loading-bar:nth-child(1){animation-delay:-1.2s;transform:rotate(.0001deg) translate(146%)}.sonner-loading-bar:nth-child(2){animation-delay:-1.1s;transform:rotate(30deg) translate(146%)}.sonner-loading-bar:nth-child(3){animation-delay:-1s;transform:rotate(60deg) translate(146%)}.sonner-loading-bar:nth-child(4){animation-delay:-.9s;transform:rotate(90deg) translate(146%)}.sonner-loading-bar:nth-child(5){animation-delay:-.8s;transform:rotate(120deg) translate(146%)}.sonner-loading-bar:nth-child(6){animation-delay:-.7s;transform:rotate(150deg) translate(146%)}.sonner-loading-bar:nth-child(7){animation-delay:-.6s;transform:rotate(180deg) translate(146%)}.sonner-loading-bar:nth-child(8){animation-delay:-.5s;transform:rotate(210deg) translate(146%)}.sonner-loading-bar:nth-child(9){animation-delay:-.4s;transform:rotate(240deg) translate(146%)}.sonner-loading-bar:nth-child(10){animation-delay:-.3s;transform:rotate(270deg) translate(146%)}.sonner-loading-bar:nth-child(11){animation-delay:-.2s;transform:rotate(300deg) translate(146%)}.sonner-loading-bar:nth-child(12){animation-delay:-.1s;transform:rotate(330deg) translate(146%)}@keyframes sonner-fade-in{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes sonner-fade-out{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.8)}}@keyframes sonner-spin{0%{opacity:1}to{opacity:.15}}@media (prefers-reduced-motion){[data-sonner-toast],[data-sonner-toast]>*,.sonner-loading-bar{transition:none!important;animation:none!important}}.sonner-loader{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);transform-origin:center;transition:opacity .2s,transform .2s}.sonner-loader[data-visible=false]{opacity:0;transform:scale(.8) translate(-50%,-50%)}
@@ -0,0 +1 @@
1
+ .legend-dot.svelte-d3o8w3{display:inline-block;height:.75rem;width:.75rem;border-radius:9999px}
@@ -0,0 +1 @@
1
+ .spinner.svelte-uqfq9v{fill:hsl(var(--primary) / var(--tw-bg-opacity, 1))}.crop.svelte-112wvhq{position:relative;overflow:hidden}.annotation-box.svelte-112wvhq{position:absolute;border:1px solid rgba(0,0,0,0);box-sizing:content-box}.annotation-label.svelte-112wvhq{position:absolute;transform:translate3d(-1px,-100%,0);padding:1px 6px 2px;white-space:nowrap;cursor:pointer}.annotation-selected.svelte-112wvhq{outline:drop-shadow(1px 1px 1px hsl(var(--primary))) drop-shadow(1px -1px 1px hsl(var(--primary))) drop-shadow(-1px -1px 1px hsl(var(--primary))) drop-shadow(-1px 1px 1px hsl(var(--primary)))}.group.svelte-lseqsj{outline:0}.sample-image.svelte-1a2mlic{width:var(--sample-width);height:var(--sample-height);-o-object-fit:var(--object-fit);object-fit:var(--object-fit)}.viewport.svelte-w4icmb{overflow-y:hidden}.sample-selected.svelte-w4icmb{outline:drop-shadow(1px 1px 1px hsl(var(--primary))) drop-shadow(1px -1px 1px hsl(var(--primary))) drop-shadow(-1px -1px 1px hsl(var(--primary))) drop-shadow(-1px 1px 1px hsl(var(--primary)))}
@@ -1 +1 @@
1
- [data-select-viewport],[data-combobox-viewport]{scrollbar-width:none!important;-ms-overflow-style:none!important;-webkit-overflow-scrolling:touch!important}[data-combobox-viewport]::-webkit-scrollbar{display:none!important}[data-select-viewport]::-webkit-scrollbar{display:none!important}
1
+ [data-select-viewport],[data-combobox-viewport]{scrollbar-width:none!important;-ms-overflow-style:none!important;-webkit-overflow-scrolling:touch!important}[data-combobox-viewport]::-webkit-scrollbar{display:none!important}[data-select-viewport]::-webkit-scrollbar{display:none!important}.legend-dot.svelte-d3o8w3{display:inline-block;height:.75rem;width:.75rem;border-radius:9999px}