easy_ml 0.2.0.pre.rc40 → 0.2.0.pre.rc43

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +11 -9
  3. data/app/controllers/easy_ml/settings_controller.rb +1 -4
  4. data/app/frontend/pages/SettingsPage.tsx +1 -80
  5. data/app/jobs/easy_ml/batch_job.rb +45 -1
  6. data/app/jobs/easy_ml/compute_feature_job.rb +68 -4
  7. data/app/models/concerns/easy_ml/dataframe_serialization.rb +30 -0
  8. data/app/models/easy_ml/dataset.rb +23 -22
  9. data/app/models/easy_ml/dataset_history.rb +1 -6
  10. data/app/models/easy_ml/datasources/polars_datasource.rb +4 -18
  11. data/app/models/easy_ml/event.rb +2 -1
  12. data/app/models/easy_ml/event_context.rb +58 -0
  13. data/app/models/easy_ml/feature.rb +43 -14
  14. data/app/models/easy_ml/model.rb +4 -7
  15. data/app/models/easy_ml/model_file.rb +17 -48
  16. data/app/models/easy_ml/splitter_history.rb +16 -0
  17. data/app/serializers/easy_ml/prediction_serializer.rb +6 -1
  18. data/config/initializers/zhong.rb +4 -0
  19. data/lib/easy_ml/data/date_converter.rb +1 -0
  20. data/lib/easy_ml/data/polars_reader.rb +17 -4
  21. data/lib/easy_ml/data/statistics_learner.rb +1 -1
  22. data/lib/easy_ml/engine.rb +22 -0
  23. data/lib/easy_ml/pending_migrations.rb +19 -0
  24. data/lib/easy_ml/predict.rb +25 -12
  25. data/lib/easy_ml/railtie/generators/migration/migration_generator.rb +39 -157
  26. data/lib/easy_ml/railtie/templates/migration/add_workflow_status_to_easy_ml_features.rb.tt +13 -0
  27. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_column_histories.rb.tt +4 -2
  28. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_columns.rb.tt +22 -20
  29. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_dataset_histories.rb.tt +5 -3
  30. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_datasets.rb.tt +26 -24
  31. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_datasource_histories.rb.tt +5 -3
  32. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_datasources.rb.tt +12 -10
  33. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_deploys.rb.tt +21 -19
  34. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_event_contexts.rb.tt +14 -0
  35. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_events.rb.tt +16 -14
  36. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_feature_histories.rb.tt +10 -8
  37. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_features.rb.tt +27 -25
  38. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_model_file_histories.rb.tt +5 -3
  39. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_model_files.rb.tt +13 -11
  40. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_model_histories.rb.tt +5 -3
  41. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_models.rb.tt +28 -26
  42. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_predictions.rb.tt +13 -11
  43. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_retraining_jobs.rb.tt +70 -66
  44. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_settings.rb.tt +6 -4
  45. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_splitter_histories.rb.tt +6 -4
  46. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_splitters.rb.tt +11 -9
  47. data/lib/easy_ml/railtie/templates/migration/create_easy_ml_tuner_jobs.rb.tt +34 -30
  48. data/lib/easy_ml/railtie/templates/migration/drop_path_from_easy_ml_model_files.rb.tt +11 -0
  49. data/lib/easy_ml/version.rb +1 -1
  50. data/lib/easy_ml.rb +1 -0
  51. data/public/easy_ml/assets/.vite/manifest.json +2 -2
  52. data/public/easy_ml/assets/assets/Application-zpGA_Q9c.css +1 -0
  53. data/public/easy_ml/assets/assets/entrypoints/{Application.tsx-DF5SSkYi.js → Application.tsx-jPsqOyb0.js} +87 -97
  54. data/public/easy_ml/assets/assets/entrypoints/Application.tsx-jPsqOyb0.js.map +1 -0
  55. metadata +11 -19
  56. data/public/easy_ml/assets/assets/Application-Cu7lNJmG.css +0 -1
  57. data/public/easy_ml/assets/assets/entrypoints/Application.tsx-DF5SSkYi.js.map +0 -1
@@ -1,34 +1,36 @@
1
1
  # lib/railtie/generators/templates/migration/create_easy_ml_models.rb.tt
2
2
  class CreateEasyMLModels < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
3
3
  def change
4
- create_table :easy_ml_models do |t|
5
- t.string :name, null: false
6
- t.string :model_type
7
- t.string :status
8
- t.bigint :dataset_id
9
- t.bigint :model_file_id
10
- t.json :configuration
11
- t.string :version, null: false
12
- t.string :root_dir
13
- t.json :file
14
- t.string :sha
15
- t.datetime :last_trained_at
16
- t.boolean :is_training
4
+ unless table_exists?(:easy_ml_models)
5
+ create_table :easy_ml_models do |t|
6
+ t.string :name, null: false
7
+ t.string :model_type
8
+ t.string :status
9
+ t.bigint :dataset_id
10
+ t.bigint :model_file_id
11
+ t.json :configuration
12
+ t.string :version, null: false
13
+ t.string :root_dir
14
+ t.json :file
15
+ t.string :sha
16
+ t.datetime :last_trained_at
17
+ t.boolean :is_training
17
18
 
18
- t.timestamps
19
+ t.timestamps
19
20
 
20
- t.index :created_at
21
- t.index :last_trained_at
22
- t.index :name
23
- t.index :version
24
- t.index :status
25
- t.index [:name, :status]
26
- t.index [:name, :version]
27
- t.index :dataset_id
28
- t.index :model_type
29
- t.index :model_file_id
30
- t.index :sha
31
- t.index :is_training
21
+ t.index :created_at
22
+ t.index :last_trained_at
23
+ t.index :name
24
+ t.index :version
25
+ t.index :status
26
+ t.index [:name, :status]
27
+ t.index [:name, :version]
28
+ t.index :dataset_id
29
+ t.index :model_type
30
+ t.index :model_file_id
31
+ t.index :sha
32
+ t.index :is_training
33
+ end
32
34
  end
33
35
  end
34
36
  end
@@ -1,17 +1,19 @@
1
1
  class CreateEasyMLPredictions < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
2
  def change
3
- create_table :easy_ml_predictions do |t|
4
- t.bigint :model_id, null: false
5
- t.bigint :model_history_id
6
- t.string :prediction_type
7
- t.jsonb :prediction_value
8
- t.jsonb :raw_input
9
- t.jsonb :normalized_input
10
- t.timestamps
3
+ unless table_exists?(:easy_ml_predictions)
4
+ create_table :easy_ml_predictions do |t|
5
+ t.bigint :model_id, null: false
6
+ t.bigint :model_history_id
7
+ t.string :prediction_type
8
+ t.jsonb :prediction_value
9
+ t.jsonb :raw_input
10
+ t.jsonb :normalized_input
11
+ t.timestamps
11
12
 
12
- t.index :model_id
13
- t.index :model_history_id
14
- t.index :created_at
13
+ t.index :model_id
14
+ t.index :model_history_id
15
+ t.index :created_at
16
+ end
15
17
  end
16
18
  end
17
19
  end
@@ -1,77 +1,81 @@
1
1
  class CreateEasyMLRetrainingJobs < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
2
  def change
3
- create_table :easy_ml_retraining_jobs do |t|
4
- t.bigint :model_id
5
- t.string :frequency, null: false # day, week, month, hour
6
- t.json :at, null: false # hour of day (0-23)
7
- t.json :evaluator # Model evaluator
8
- t.boolean :tuning_enabled, default: false
9
- t.json :tuner_config # configuration for the tuner
10
- t.string :tuning_frequency # day, week, month, hour - when to run with tuner
11
- t.datetime :last_tuning_at # track last tuning run
12
- t.boolean :active, default: true
13
- t.string :status, default: "pending"
14
- t.datetime :last_run_at
15
- t.string :metric, null: false
16
- t.string :direction, null: false
17
- t.float :threshold, null: false
18
- t.boolean :auto_deploy, default: false
19
- t.boolean :batch_mode
20
- t.integer :batch_size
21
- t.integer :batch_overlap
22
- t.string :batch_key
3
+ unless table_exists?(:easy_ml_retraining_jobs)
4
+ create_table :easy_ml_retraining_jobs do |t|
5
+ t.bigint :model_id
6
+ t.string :frequency, null: false # day, week, month, hour
7
+ t.json :at, null: false # hour of day (0-23)
8
+ t.json :evaluator # Model evaluator
9
+ t.boolean :tuning_enabled, default: false
10
+ t.json :tuner_config # configuration for the tuner
11
+ t.string :tuning_frequency # day, week, month, hour - when to run with tuner
12
+ t.datetime :last_tuning_at # track last tuning run
13
+ t.boolean :active, default: true
14
+ t.string :status, default: "pending"
15
+ t.datetime :last_run_at
16
+ t.string :metric, null: false
17
+ t.string :direction, null: false
18
+ t.float :threshold, null: false
19
+ t.boolean :auto_deploy, default: false
20
+ t.boolean :batch_mode
21
+ t.integer :batch_size
22
+ t.integer :batch_overlap
23
+ t.string :batch_key
23
24
 
24
- t.timestamps
25
+ t.timestamps
25
26
 
26
- t.index :model_id
27
- t.index :active
28
- t.index :last_run_at
29
- t.index :last_tuning_at
30
- t.index :batch_mode
31
- t.index :auto_deploy
32
- t.index :tuning_enabled
27
+ t.index :model_id
28
+ t.index :active
29
+ t.index :last_run_at
30
+ t.index :last_tuning_at
31
+ t.index :batch_mode
32
+ t.index :auto_deploy
33
+ t.index :tuning_enabled
34
+ end
33
35
  end
34
36
 
35
- create_table :easy_ml_retraining_runs do |t|
36
- t.bigint :model_id
37
- t.bigint :model_history_id
38
- t.bigint :model_file_id
39
- t.bigint :retraining_job_id, null: false
40
- t.bigint :tuner_job_id, null: true
41
- t.string :status, default: 'pending'
42
- t.float :metric_value
43
- t.float :threshold
44
- t.string :trigger, default: 'manual'
45
- t.string :threshold_direction
46
- t.datetime :started_at
47
- t.datetime :completed_at
48
- t.text :error_message
49
- t.jsonb :metadata
50
- t.jsonb :metrics
51
- t.jsonb :best_params
52
- t.string :wandb_url
53
- t.string :snapshot_id
54
- t.boolean :deployable
55
- t.boolean :is_deploying
56
- t.boolean :deployed
57
- t.bigint :deploy_id
37
+ unless table_exists?(:easy_ml_retraining_runs)
38
+ create_table :easy_ml_retraining_runs do |t|
39
+ t.bigint :model_id
40
+ t.bigint :model_history_id
41
+ t.bigint :model_file_id
42
+ t.bigint :retraining_job_id, null: false
43
+ t.bigint :tuner_job_id, null: true
44
+ t.string :status, default: 'pending'
45
+ t.float :metric_value
46
+ t.float :threshold
47
+ t.string :trigger, default: 'manual'
48
+ t.string :threshold_direction
49
+ t.datetime :started_at
50
+ t.datetime :completed_at
51
+ t.text :error_message
52
+ t.jsonb :metadata
53
+ t.jsonb :metrics
54
+ t.jsonb :best_params
55
+ t.string :wandb_url
56
+ t.string :snapshot_id
57
+ t.boolean :deployable
58
+ t.boolean :is_deploying
59
+ t.boolean :deployed
60
+ t.bigint :deploy_id
58
61
 
59
- t.timestamps
62
+ t.timestamps
60
63
 
61
- t.index :status
62
- t.index :started_at
63
- t.index :completed_at
64
- t.index :created_at
65
- t.index :tuner_job_id
66
- t.index :retraining_job_id
67
- t.index :model_id
68
- t.index :trigger
69
- t.index :wandb_url
70
- t.index :snapshot_id
71
- t.index :deploy_id
72
- t.index :model_history_id
73
- t.index :deployable
74
- t.index :is_deploying
64
+ t.index :status
65
+ t.index :started_at
66
+ t.index :completed_at
67
+ t.index :created_at
68
+ t.index :tuner_job_id
69
+ t.index :retraining_job_id
70
+ t.index :model_id
71
+ t.index :trigger
72
+ t.index :wandb_url
73
+ t.index :snapshot_id
74
+ t.index :deploy_id
75
+ t.index :model_history_id
76
+ t.index :deployable
77
+ t.index :is_deploying
78
+ end
75
79
  end
76
80
  end
77
81
  end
@@ -1,9 +1,11 @@
1
1
  class CreateEasyMLSettings < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
2
  def change
3
- create_table :easy_ml_settings do |t|
4
- t.json :configuration
3
+ unless table_exists?(:easy_ml_settings)
4
+ create_table :easy_ml_settings do |t|
5
+ t.json :configuration
5
6
 
6
- t.timestamps
7
+ t.timestamps
8
+ end
7
9
  end
8
10
  end
9
- end
11
+ end
@@ -2,8 +2,10 @@ require "historiographer/postgres_migration"
2
2
 
3
3
  class CreateEasyMLSplitterHistories < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
4
4
  def change
5
- create_table :easy_ml_splitter_histories do |t|
6
- t.histories(foreign_key: :splitter_id)
5
+ unless table_exists?(:easy_ml_splitter_histories)
6
+ create_table :easy_ml_splitter_histories do |t|
7
+ t.histories(foreign_key: :splitter_id)
8
+ end
7
9
  end
8
- end
9
- end
10
+ end
11
+ end
@@ -1,15 +1,17 @@
1
1
  class CreateEasyMLSplitters < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
2
  def change
3
- create_table :easy_ml_splitters do |t|
4
- t.string :splitter_type, null: false
5
- t.json :configuration
6
- t.bigint :dataset_id, null: false
3
+ unless table_exists?(:easy_ml_splitters)
4
+ create_table :easy_ml_splitters do |t|
5
+ t.string :splitter_type, null: false
6
+ t.json :configuration
7
+ t.bigint :dataset_id, null: false
7
8
 
8
- t.timestamps
9
+ t.timestamps
9
10
 
10
- t.index :splitter_type
11
- t.index :created_at
12
- t.index :dataset_id
11
+ t.index :splitter_type
12
+ t.index :created_at
13
+ t.index :dataset_id
14
+ end
13
15
  end
14
16
  end
15
- end
17
+ end
@@ -1,40 +1,44 @@
1
1
  class CreateEasyMLTunerJobs < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
2
  def change
3
- create_table :easy_ml_tuner_jobs do |t|
4
- t.json :config, null: false
5
- t.bigint :best_tuner_run_id
6
- t.bigint :model_id, null: false
7
- t.string :status
8
- t.string :direction, default: 'minimize'
9
- t.datetime :started_at
10
- t.datetime :completed_at
11
- t.jsonb :metadata
12
- t.string :wandb_url
3
+ unless table_exists?(:easy_ml_tuner_jobs)
4
+ create_table :easy_ml_tuner_jobs do |t|
5
+ t.json :config, null: false
6
+ t.bigint :best_tuner_run_id
7
+ t.bigint :model_id, null: false
8
+ t.string :status
9
+ t.string :direction, default: 'minimize'
10
+ t.datetime :started_at
11
+ t.datetime :completed_at
12
+ t.jsonb :metadata
13
+ t.string :wandb_url
13
14
 
14
- t.timestamps
15
+ t.timestamps
15
16
 
16
- t.index :status
17
- t.index :started_at
18
- t.index :completed_at
19
- t.index :model_id
20
- t.index :best_tuner_run_id
21
- t.index :wandb_url
17
+ t.index :status
18
+ t.index :started_at
19
+ t.index :completed_at
20
+ t.index :model_id
21
+ t.index :best_tuner_run_id
22
+ t.index :wandb_url
23
+ end
22
24
  end
23
25
 
24
- create_table :easy_ml_tuner_runs do |t|
25
- t.bigint :tuner_job_id, null: false
26
- t.json :hyperparameters, null: false
27
- t.float :value
28
- t.integer :trial_number
29
- t.string :status
30
- t.string :wandb_url
26
+ unless table_exists?(:easy_ml_tuner_runs)
27
+ create_table :easy_ml_tuner_runs do |t|
28
+ t.bigint :tuner_job_id, null: false
29
+ t.json :hyperparameters, null: false
30
+ t.float :value
31
+ t.integer :trial_number
32
+ t.string :status
33
+ t.string :wandb_url
31
34
 
32
- t.timestamps
35
+ t.timestamps
33
36
 
34
- t.index [:tuner_job_id, :value]
35
- t.index [:tuner_job_id, :trial_number], name: "idx_tuner_runs_and_trial_number"
36
- t.index :status
37
- t.index :wandb_url
37
+ t.index [:tuner_job_id, :value]
38
+ t.index [:tuner_job_id, :trial_number], name: "idx_tuner_runs_and_trial_number"
39
+ t.index :status
40
+ t.index :wandb_url
41
+ end
38
42
  end
39
43
  end
40
- end
44
+ end
@@ -0,0 +1,11 @@
1
+ class DropPathFromEasyMLModelFiles < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ if column_exists?(:easy_ml_model_files, :path)
4
+ remove_column :easy_ml_model_files, :path
5
+ end
6
+
7
+ if column_exists?(:easy_ml_model_file_histories, :path)
8
+ remove_column :easy_ml_model_file_histories, :path
9
+ end
10
+ end
11
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EasyML
4
- VERSION = "0.2.0-rc40"
4
+ VERSION = "0.2.0-rc43"
5
5
 
6
6
  module Version
7
7
  end
data/lib/easy_ml.rb CHANGED
@@ -24,4 +24,5 @@ module EasyML
24
24
  require_relative "easy_ml/feature_store"
25
25
  require_relative "easy_ml/core"
26
26
  require_relative "easy_ml/predict"
27
+ require_relative "easy_ml/pending_migrations"
27
28
  end
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "entrypoints/Application.tsx": {
3
- "file": "assets/entrypoints/Application.tsx-DF5SSkYi.js",
3
+ "file": "assets/entrypoints/Application.tsx-jPsqOyb0.js",
4
4
  "name": "entrypoints/Application.tsx",
5
5
  "src": "entrypoints/Application.tsx",
6
6
  "isEntry": true,
7
7
  "css": [
8
- "assets/Application-Cu7lNJmG.css"
8
+ "assets/Application-zpGA_Q9c.css"
9
9
  ]
10
10
  }
11
11
  }
@@ -0,0 +1 @@
1
+ *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 100%;--foreground: 0 0% 3.9%;--card: 0 0% 100%;--card-foreground: 0 0% 3.9%;--popover: 0 0% 100%;--popover-foreground: 0 0% 3.9%;--primary: 0 0% 9%;--primary-foreground: 0 0% 98%;--secondary: 0 0% 96.1%;--secondary-foreground: 0 0% 9%;--muted: 0 0% 96.1%;--muted-foreground: 0 0% 45.1%;--accent: 0 0% 96.1%;--accent-foreground: 0 0% 9%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 0 0% 98%;--border: 0 0% 89.8%;--input: 0 0% 89.8%;--ring: 0 0% 3.9%;--chart-1: 12 76% 61%;--chart-2: 173 58% 39%;--chart-3: 197 37% 24%;--chart-4: 43 74% 66%;--chart-5: 27 87% 67%;--radius: .5rem}body{background-color:hsl(var(--background));color:hsl(var(--foreground))}.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}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.inset-y-0{top:0;bottom:0}.left-0{left:0}.left-3{left:.75rem}.left-4{left:1rem}.right-0{right:0}.right-4{right:1rem}.top-0{top:0}.top-1\/2{top:50%}.top-4{top:1rem}.z-0{z-index:0}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.col-span-3{grid-column:span 3 / span 3}.col-span-4{grid-column:span 4 / span 4}.m-1{margin:.25rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.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-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-1{margin-left:.25rem}.ml-16{margin-left:4rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-64{margin-left:16rem}.ml-auto{margin-left:auto}.mr-2{margin-right:.5rem}.mr-4{margin-right:1rem}.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}.line-clamp-1{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-0\.5{height:.125rem}.h-12{height:3rem}.h-16{height:4rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-8{height:2rem}.h-\[1px\]{height:1px}.h-\[calc\(100vh-4rem\)\]{height:calc(100vh - 4rem)}.h-\[calc\(90vh-8rem\)\]{height:calc(90vh - 8rem)}.h-full{height:100%}.h-screen{height:100vh}.max-h-32{max-height:8rem}.max-h-60{max-height:15rem}.max-h-96{max-height:24rem}.max-h-\[400px\]{max-height:400px}.max-h-\[90vh\]{max-height:90vh}.max-h-\[calc\(90vh-8rem\)\]{max-height:calc(90vh - 8rem)}.min-h-0{min-height:0px}.min-h-\[calc\(100vh-4rem\)\]{min-height:calc(100vh - 4rem)}.min-h-screen{min-height:100vh}.w-12{width:3rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-3{width:.75rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-8{width:2rem}.w-96{width:24rem}.w-\[1px\]{width:1px}.w-full{width:100%}.min-w-0,.min-w-\[0px\]{min-width:0px}.min-w-\[120px\]{min-width:120px}.min-w-full{min-width:100%}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-\[70\%\]{max-width:70%}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.-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-y-2{--tw-translate-y: -.5rem;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-grab{cursor:grab}.cursor-grabbing{cursor:grabbing}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.-space-x-px>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(-1px * var(--tw-space-x-reverse));margin-left:calc(-1px * 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-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-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))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.divide-x>:not([hidden])~:not([hidden]){--tw-divide-x-reverse: 0;border-right-width:calc(1px * var(--tw-divide-x-reverse));border-left-width:calc(1px * calc(1 - var(--tw-divide-x-reverse)))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(229 231 235 / var(--tw-divide-opacity, 1))}.divide-gray-300>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(209 213 219 / var(--tw-divide-opacity, 1))}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.rounded{border-radius:.25rem}.rounded-\[inherit\]{border-radius:inherit}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-l-md{border-top-left-radius:calc(var(--radius) - 2px);border-bottom-left-radius:calc(var(--radius) - 2px)}.rounded-r-md{border-top-right-radius:calc(var(--radius) - 2px);border-bottom-right-radius:calc(var(--radius) - 2px)}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-l-0{border-left-width:0px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-purple-500{--tw-border-opacity: 1;border-color:rgb(168 85 247 / var(--tw-border-opacity, 1))}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-l-transparent{border-left-color:transparent}.border-t-transparent{border-top-color:transparent}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity, 1))}.bg-blue-100{--tw-bg-opacity: 1;background-color:rgb(219 234 254 / var(--tw-bg-opacity, 1))}.bg-blue-400{--tw-bg-opacity: 1;background-color:rgb(96 165 250 / var(--tw-bg-opacity, 1))}.bg-blue-50{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-border{background-color:hsl(var(--border))}.bg-destructive{background-color:hsl(var(--destructive))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-gray-700{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}.bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity, 1))}.bg-green-100{--tw-bg-opacity: 1;background-color:rgb(220 252 231 / var(--tw-bg-opacity, 1))}.bg-green-400{--tw-bg-opacity: 1;background-color:rgb(74 222 128 / var(--tw-bg-opacity, 1))}.bg-green-50{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity, 1))}.bg-primary{background-color:hsl(var(--primary))}.bg-purple-100{--tw-bg-opacity: 1;background-color:rgb(243 232 255 / var(--tw-bg-opacity, 1))}.bg-purple-50{--tw-bg-opacity: 1;background-color:rgb(250 245 255 / var(--tw-bg-opacity, 1))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity, 1))}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.bg-secondary{background-color:hsl(var(--secondary))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/10{background-color:#ffffff1a}.bg-yellow-100{--tw-bg-opacity: 1;background-color:rgb(254 249 195 / var(--tw-bg-opacity, 1))}.bg-yellow-400{--tw-bg-opacity: 1;background-color:rgb(250 204 21 / var(--tw-bg-opacity, 1))}.bg-yellow-50{--tw-bg-opacity: 1;background-color:rgb(254 252 232 / var(--tw-bg-opacity, 1))}.bg-opacity-50{--tw-bg-opacity: .5}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-blue-600{--tw-gradient-from: #2563eb var(--tw-gradient-from-position);--tw-gradient-to: rgb(37 99 235 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.to-indigo-600{--tw-gradient-to: #4f46e5 var(--tw-gradient-to-position)}.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}.p-\[1px\]{padding:1px}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-2{padding-bottom:.5rem}.pb-4{padding-bottom:1rem}.pl-10{padding-left:2.5rem}.pl-3{padding-left:.75rem}.pl-4{padding-left:1rem}.pl-8{padding-left:2rem}.pl-9{padding-left:2.25rem}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.tracking-wider{letter-spacing:.05em}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-blue-700{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.text-blue-800{--tw-text-opacity: 1;color:rgb(30 64 175 / var(--tw-text-opacity, 1))}.text-blue-900{--tw-text-opacity: 1;color:rgb(30 58 138 / var(--tw-text-opacity, 1))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-foreground{color:hsl(var(--foreground))}.text-gray-100{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-green-800{--tw-text-opacity: 1;color:rgb(22 101 52 / var(--tw-text-opacity, 1))}.text-green-900{--tw-text-opacity: 1;color:rgb(20 83 45 / var(--tw-text-opacity, 1))}.text-orange-700{--tw-text-opacity: 1;color:rgb(194 65 12 / var(--tw-text-opacity, 1))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-purple-500{--tw-text-opacity: 1;color:rgb(168 85 247 / var(--tw-text-opacity, 1))}.text-purple-800{--tw-text-opacity: 1;color:rgb(107 33 168 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-red-800{--tw-text-opacity: 1;color:rgb(153 27 27 / var(--tw-text-opacity, 1))}.text-red-900{--tw-text-opacity: 1;color:rgb(127 29 29 / var(--tw-text-opacity, 1))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.text-yellow-600{--tw-text-opacity: 1;color:rgb(202 138 4 / var(--tw-text-opacity, 1))}.text-yellow-700{--tw-text-opacity: 1;color:rgb(161 98 7 / var(--tw-text-opacity, 1))}.text-yellow-800{--tw-text-opacity: 1;color:rgb(133 77 14 / var(--tw-text-opacity, 1))}.text-yellow-900{--tw-text-opacity: 1;color:rgb(113 63 18 / var(--tw-text-opacity, 1))}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px 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-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{outline-style:solid}.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-black{--tw-ring-opacity: 1;--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity, 1))}.ring-opacity-5{--tw-ring-opacity: .05}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-shadow{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.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))}}.duration-150{animation-duration:.15s}.duration-200{animation-duration:.2s}.duration-300{animation-duration:.3s}.ease-in-out{animation-timing-function:cubic-bezier(.4,0,.2,1)}.running{animation-play-state:running}: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}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground));font-feature-settings:"rlig" 1,"calt" 1}.hover\:border-gray-300:hover{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.hover\:bg-blue-500:hover{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-600:hover{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-700:hover{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-900:hover{--tw-bg-opacity: 1;background-color:rgb(30 58 138 / var(--tw-bg-opacity, 1))}.hover\:bg-destructive\/80:hover{background-color:hsl(var(--destructive) / .8)}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-200:hover{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.hover\:bg-green-600:hover{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.hover\:bg-green-900:hover{--tw-bg-opacity: 1;background-color:rgb(20 83 45 / var(--tw-bg-opacity, 1))}.hover\:bg-primary\/80:hover{background-color:hsl(var(--primary) / .8)}.hover\:bg-red-600:hover{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.hover\:bg-red-900:hover{--tw-bg-opacity: 1;background-color:rgb(127 29 29 / var(--tw-bg-opacity, 1))}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:bg-yellow-100:hover{--tw-bg-opacity: 1;background-color:rgb(254 249 195 / var(--tw-bg-opacity, 1))}.hover\:bg-yellow-600:hover{--tw-bg-opacity: 1;background-color:rgb(202 138 4 / var(--tw-bg-opacity, 1))}.hover\:bg-opacity-10:hover{--tw-bg-opacity: .1}.hover\:from-blue-700:hover{--tw-gradient-from: #1d4ed8 var(--tw-gradient-from-position);--tw-gradient-to: rgb(29 78 216 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.hover\:to-indigo-700:hover{--tw-gradient-to: #4338ca var(--tw-gradient-to-position)}.hover\:text-blue-600:hover{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.hover\:text-blue-700:hover{--tw-text-opacity: 1;color:rgb(29 78 216 / var(--tw-text-opacity, 1))}.hover\:text-blue-800:hover{--tw-text-opacity: 1;color:rgb(30 64 175 / var(--tw-text-opacity, 1))}.hover\:text-gray-500:hover{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.hover\:text-gray-900:hover{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.hover\:text-green-600:hover{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.hover\:text-purple-600:hover{--tw-text-opacity: 1;color:rgb(147 51 234 / var(--tw-text-opacity, 1))}.hover\:text-red-600:hover{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.hover\:text-red-700:hover{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.hover\:text-red-800:hover{--tw-text-opacity: 1;color:rgb(153 27 27 / var(--tw-text-opacity, 1))}.hover\:shadow-lg:hover{--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)}.focus\:border-blue-500:focus{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.focus\:border-indigo-500:focus{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity, 1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1: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(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)}.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-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1))}.focus\:ring-indigo-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity, 1))}.focus\:ring-red-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(239 68 68 / var(--tw-ring-opacity, 1))}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.active\:cursor-grabbing:active{cursor:grabbing}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-100:disabled{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.disabled\:bg-gray-300:disabled{--tw-bg-opacity: 1;background-color:rgb(209 213 219 / var(--tw-bg-opacity, 1))}.disabled\:text-gray-400:disabled{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:opacity-100{opacity:1}@media (min-width: 640px){.sm\:flex{display:flex}.sm\:hidden{display:none}.sm\:flex-1{flex:1 1 0%}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width: 1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}