modscape 2.0.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +189 -5
- package/README.md +185 -3
- package/package.json +1 -1
- package/src/layout.js +47 -26
- package/src/templates/rules.md +97 -22
- package/visualizer/package.json +1 -1
- package/visualizer-dist/assets/index-CVn9qVGW.css +1 -0
- package/visualizer-dist/assets/index-Crci4Usl.js +432 -0
- package/visualizer-dist/index.html +2 -2
- package/visualizer-dist/assets/index-nIGQ5zIu.js +0 -432
- package/visualizer-dist/assets/index-zFK5TNtm.css +0 -1
package/src/templates/rules.md
CHANGED
|
@@ -11,11 +11,12 @@
|
|
|
11
11
|
## QUICK REFERENCE (read this first)
|
|
12
12
|
|
|
13
13
|
```
|
|
14
|
-
ROOT KEYS domains | tables | relationships | lineage | annotations | layout
|
|
14
|
+
ROOT KEYS domains | tables | relationships | lineage | annotations | layout | consumers
|
|
15
15
|
COORDINATES ONLY in `layout`. NEVER inside tables or domains.
|
|
16
16
|
LINEAGE Use top-level `lineage` section (not relationships, not table.lineage.upstream).
|
|
17
|
+
lineage.to can reference either a table ID or a consumer ID.
|
|
17
18
|
parentId Declare a table's domain membership inside layout, not inside domains.
|
|
18
|
-
IDs Every object (table, domain, annotation) needs a unique `id`.
|
|
19
|
+
IDs Every object (table, domain, annotation, consumer) needs a unique `id`.
|
|
19
20
|
sampleData First row = column IDs. At least 3 realistic data rows.
|
|
20
21
|
Grid All x/y values must be multiples of 40.
|
|
21
22
|
```
|
|
@@ -33,6 +34,7 @@ relationships: # (array) ER cardinality edges — OPTIONAL
|
|
|
33
34
|
lineage: # (array) data lineage edges — OPTIONAL
|
|
34
35
|
annotations: # (array) sticky notes / callouts — OPTIONAL
|
|
35
36
|
layout: # (object) ALL coordinates — REQUIRED if any objects exist
|
|
37
|
+
consumers: # (array) downstream consumers (BI dashboards, ML models, apps) — OPTIONAL
|
|
36
38
|
```
|
|
37
39
|
|
|
38
40
|
**MUST NOT** add any other top-level keys. They will be ignored or cause errors.
|
|
@@ -45,13 +47,12 @@ layout: # (object) ALL coordinates — REQUIRED if any objects exist
|
|
|
45
47
|
|
|
46
48
|
| Field | Required | Description |
|
|
47
49
|
|-------|----------|-------------|
|
|
48
|
-
| `id` | **REQUIRED** | Unique identifier used as a key in `layout`, `domains.tables`, `lineage
|
|
50
|
+
| `id` | **REQUIRED** | Unique identifier used as a key in `layout`, `domains.tables`, `lineage`, etc. Use snake_case. |
|
|
49
51
|
| `name` | **REQUIRED** | Conceptual (business) name shown large on the canvas. |
|
|
50
52
|
| `logical_name` | optional | Formal business name shown medium. Omit if same as `name`. |
|
|
51
53
|
| `physical_name` | optional | Actual database table name shown small. |
|
|
52
54
|
| `appearance` | optional | Visual type, icon, color. |
|
|
53
55
|
| `conceptual` | optional | AI-friendly business context metadata. |
|
|
54
|
-
| `lineage` | optional | Upstream table IDs. Only for `mart` / aggregated tables. |
|
|
55
56
|
| `columns` | optional | Column definitions. |
|
|
56
57
|
| `sampleData` | optional | 2D array of sample rows. Strongly recommended. |
|
|
57
58
|
|
|
@@ -72,7 +73,7 @@ appearance:
|
|
|
72
73
|
|------|-------------|
|
|
73
74
|
| `fact` | Events, transactions, measurements. Has measures (numbers) and FK columns. |
|
|
74
75
|
| `dimension` | Entities, master data, reference lists. Descriptive attributes. |
|
|
75
|
-
| `mart` | Aggregated or consumer-facing output. **Always add `lineage
|
|
76
|
+
| `mart` | Aggregated or consumer-facing output. **Always add a top-level `lineage` entry.** |
|
|
76
77
|
| `hub` | Data Vault: stores a single unique business key. |
|
|
77
78
|
| `link` | Data Vault: joins two or more hubs (transaction or relationship). |
|
|
78
79
|
| `satellite` | Data Vault: descriptive attributes of a hub, tracked over time. |
|
|
@@ -96,7 +97,7 @@ Each column has an `id` plus optional `logical` and `physical` blocks.
|
|
|
96
97
|
|
|
97
98
|
```yaml
|
|
98
99
|
columns:
|
|
99
|
-
- id: order_id # REQUIRED. Unique within the table.
|
|
100
|
+
- id: order_id # REQUIRED. Unique within the table.
|
|
100
101
|
logical:
|
|
101
102
|
name: "Order ID" # Display name
|
|
102
103
|
type: Int # Int | String | Decimal | Date | Timestamp | Boolean | ...
|
|
@@ -138,7 +139,7 @@ relationships:
|
|
|
138
139
|
| `many-to-one` | Fact → Dimension *(inverse notation of above)* |
|
|
139
140
|
| `many-to-many` | Via a bridge / link table |
|
|
140
141
|
|
|
141
|
-
**MUST NOT** use `relationships` to express data lineage (use `lineage
|
|
142
|
+
**MUST NOT** use `relationships` to express data lineage (use the top-level `lineage` section instead).
|
|
142
143
|
|
|
143
144
|
---
|
|
144
145
|
|
|
@@ -198,17 +199,52 @@ domains:
|
|
|
198
199
|
name: "Sales Operations" # REQUIRED. Display name.
|
|
199
200
|
description: "..." # optional
|
|
200
201
|
color: "rgba(59, 130, 246, 0.1)" # optional. rgba recommended.
|
|
201
|
-
|
|
202
|
+
members: # REQUIRED. List of table or consumer IDs inside this domain.
|
|
202
203
|
- fct_orders
|
|
203
204
|
- dim_customers
|
|
204
|
-
isLocked: false # optional. true = prevent drag on canvas.
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
-
**MUST** list only
|
|
207
|
+
**MUST** list only IDs that actually exist in `tables` or `consumers`.
|
|
208
208
|
**MUST** add a layout entry for the domain with `width` and `height`.
|
|
209
209
|
|
|
210
210
|
---
|
|
211
211
|
|
|
212
|
+
## 5b. Consumers
|
|
213
|
+
|
|
214
|
+
Consumers represent downstream users of your data model — BI dashboards, ML models, applications, etc. They appear as distinct nodes on the canvas and can receive lineage edges.
|
|
215
|
+
|
|
216
|
+
```yaml
|
|
217
|
+
consumers:
|
|
218
|
+
- id: revenue_dashboard # REQUIRED. Unique ID. Used in lineage and layout.
|
|
219
|
+
name: "Revenue Dashboard" # REQUIRED. Display name.
|
|
220
|
+
description: "Monthly KPI dashboard for finance team." # optional
|
|
221
|
+
appearance:
|
|
222
|
+
icon: "📊" # optional. Defaults to 📊.
|
|
223
|
+
color: "#e0f2fe" # optional. Header/accent color.
|
|
224
|
+
url: "https://..." # optional. Link to the actual dashboard or service.
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Field rules:**
|
|
228
|
+
- `id` and `name` are **REQUIRED**. All other fields are optional.
|
|
229
|
+
- Add a `layout` entry for each consumer (same as tables — absolute coordinates or relative inside a domain with `parentId`).
|
|
230
|
+
- To connect a consumer with lineage, set `lineage.to` to the consumer's `id`. The `lineage.from` must be a table ID.
|
|
231
|
+
- Consumers can be added to domain `members` lists just like tables.
|
|
232
|
+
|
|
233
|
+
```yaml
|
|
234
|
+
# Example: lineage from mart to a consumer
|
|
235
|
+
lineage:
|
|
236
|
+
- from: mart_monthly_revenue
|
|
237
|
+
to: revenue_dashboard # consumer ID
|
|
238
|
+
|
|
239
|
+
# Example: domain containing consumers
|
|
240
|
+
domains:
|
|
241
|
+
- id: dashboards_domain
|
|
242
|
+
name: "BI Dashboards"
|
|
243
|
+
members: [revenue_dashboard, ops_dashboard]
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
212
248
|
## 6. Layout
|
|
213
249
|
|
|
214
250
|
**All coordinates live here.** Never put `x`, `y`, `width`, or `height` inside `tables` or `domains`.
|
|
@@ -222,7 +258,6 @@ domains:
|
|
|
222
258
|
| `width` | domains | Total pixel width of the domain container |
|
|
223
259
|
| `height` | domains | Total pixel height of the domain container |
|
|
224
260
|
| `parentId` | tables inside a domain | ID of the containing domain. Makes coordinates relative to domain origin. |
|
|
225
|
-
| `isLocked` | domains or tables | Prevents drag when true |
|
|
226
261
|
|
|
227
262
|
### 6-2. Domain Size Formula
|
|
228
263
|
|
|
@@ -424,7 +459,7 @@ lineage:
|
|
|
424
459
|
# WRONG
|
|
425
460
|
domains:
|
|
426
461
|
- id: sales_ops
|
|
427
|
-
|
|
462
|
+
members: [fct_orders, dim_customers] # dim_customers listed here...
|
|
428
463
|
|
|
429
464
|
layout:
|
|
430
465
|
sales_ops: { x: 0, y: 0, width: 880, height: 400 }
|
|
@@ -497,7 +532,7 @@ The command reads `target/manifest.json` and produces YAML with:
|
|
|
497
532
|
| `physical_name` | `node.alias` | Falls back to `node.name` |
|
|
498
533
|
| `conceptual.description` | `node.description` | From dbt docs |
|
|
499
534
|
| `columns[].logical.name/type/description` | `node.columns` | From dbt schema.yml |
|
|
500
|
-
| `lineage
|
|
535
|
+
| `lineage` (top-level) | `node.depends_on.nodes` | Auto-populated as `{from, to}` entries |
|
|
501
536
|
| `appearance.type` | — | **Always `table`. Must be reclassified.** |
|
|
502
537
|
| `sampleData` | — | **Not generated. Must be added.** |
|
|
503
538
|
| `layout` | — | **Not generated. Must be added.** |
|
|
@@ -517,7 +552,7 @@ After running `modscape dbt import`, the generated YAML needs enrichment. AI age
|
|
|
517
552
|
|
|
518
553
|
3. **Add `sampleData`** — The import does not generate sample data. Add at least 3 realistic rows per table.
|
|
519
554
|
|
|
520
|
-
4. **Do NOT re-generate `lineage
|
|
555
|
+
4. **Do NOT re-generate `lineage` entries** — Top-level `lineage` is already correctly populated from `depends_on.nodes`.
|
|
521
556
|
|
|
522
557
|
### 11-4. `dbt sync` — Incremental updates
|
|
523
558
|
|
|
@@ -527,7 +562,7 @@ Use `modscape dbt sync` when the dbt project has changed (new models, updated co
|
|
|
527
562
|
- `name`, `logical_name`, `physical_name`
|
|
528
563
|
- `conceptual.description`
|
|
529
564
|
- `columns` (all)
|
|
530
|
-
- `lineage
|
|
565
|
+
- `lineage` (top-level)
|
|
531
566
|
|
|
532
567
|
**What `sync` preserves (safe to edit manually):**
|
|
533
568
|
- `appearance` (type, icon, color, scd)
|
|
@@ -549,14 +584,15 @@ id: "model.my_project.fct_orders"
|
|
|
549
584
|
id: "source.my_project.raw.orders"
|
|
550
585
|
id: "seed.my_project.product_categories"
|
|
551
586
|
|
|
552
|
-
# lineage
|
|
587
|
+
# top-level lineage also uses unique_id format
|
|
553
588
|
lineage:
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
589
|
+
- from: "model.my_project.stg_orders"
|
|
590
|
+
to: "model.my_project.fct_orders"
|
|
591
|
+
- from: "source.my_project.raw.customers"
|
|
592
|
+
to: "model.my_project.fct_orders"
|
|
557
593
|
```
|
|
558
594
|
|
|
559
|
-
**MUST NOT** shorten these IDs. They are the join keys between `tables`, `domains.
|
|
595
|
+
**MUST NOT** shorten these IDs. They are the join keys between `tables`, `domains.members`, `lineage`, and `layout`.
|
|
560
596
|
|
|
561
597
|
---
|
|
562
598
|
|
|
@@ -611,6 +647,17 @@ Use the built-in mutation commands to **add, update, or remove individual entiti
|
|
|
611
647
|
|
|
612
648
|
### 13-2. Recommended AI Agent Flow
|
|
613
649
|
|
|
650
|
+
When inspecting a model's current state, **prefer using the list/get commands** over reading the YAML file directly.
|
|
651
|
+
They return validated, structured JSON output that is easier to process.
|
|
652
|
+
|
|
653
|
+
```bash
|
|
654
|
+
# Inspect current state before making changes
|
|
655
|
+
modscape table list model.yaml --json
|
|
656
|
+
modscape domain list model.yaml --json
|
|
657
|
+
modscape relationship list model.yaml --json
|
|
658
|
+
modscape lineage list model.yaml --json
|
|
659
|
+
```
|
|
660
|
+
|
|
614
661
|
Before `add` or `update`, check existence with `get` or `list`:
|
|
615
662
|
|
|
616
663
|
```bash
|
|
@@ -732,12 +779,26 @@ domains:
|
|
|
732
779
|
name: "Sales Operations"
|
|
733
780
|
description: "Core transactional data."
|
|
734
781
|
color: "rgba(239, 68, 68, 0.1)"
|
|
735
|
-
|
|
782
|
+
members: [dim_customers, fct_orders]
|
|
736
783
|
|
|
737
784
|
- id: analytics_domain
|
|
738
785
|
name: "Analytics & Insights"
|
|
739
786
|
color: "rgba(245, 158, 11, 0.1)"
|
|
740
|
-
|
|
787
|
+
members: [mart_monthly_revenue]
|
|
788
|
+
|
|
789
|
+
- id: dashboards_domain
|
|
790
|
+
name: "BI Dashboards"
|
|
791
|
+
color: "rgba(139, 92, 246, 0.1)"
|
|
792
|
+
members: [revenue_dashboard]
|
|
793
|
+
|
|
794
|
+
consumers:
|
|
795
|
+
- id: revenue_dashboard
|
|
796
|
+
name: "Revenue Dashboard"
|
|
797
|
+
description: "Monthly KPI dashboard for the finance team."
|
|
798
|
+
appearance:
|
|
799
|
+
icon: "📊"
|
|
800
|
+
color: "#e0f2fe"
|
|
801
|
+
url: "https://bi.example.com/revenue"
|
|
741
802
|
|
|
742
803
|
tables:
|
|
743
804
|
- id: dim_customers
|
|
@@ -817,6 +878,8 @@ lineage: # data flow — separate from ER
|
|
|
817
878
|
to: mart_monthly_revenue
|
|
818
879
|
- from: dim_customers
|
|
819
880
|
to: mart_monthly_revenue
|
|
881
|
+
- from: mart_monthly_revenue
|
|
882
|
+
to: revenue_dashboard # consumer ID — valid lineage target
|
|
820
883
|
|
|
821
884
|
relationships: # ER only — not for lineage
|
|
822
885
|
- from: { table: dim_customers, column: customer_key }
|
|
@@ -862,4 +925,16 @@ layout:
|
|
|
862
925
|
x: 80
|
|
863
926
|
y: 80
|
|
864
927
|
parentId: analytics_domain
|
|
928
|
+
|
|
929
|
+
# dashboards_domain: 1 consumer → w:480, h:280
|
|
930
|
+
dashboards_domain:
|
|
931
|
+
x: 1560
|
|
932
|
+
y: 0
|
|
933
|
+
width: 480
|
|
934
|
+
height: 280
|
|
935
|
+
|
|
936
|
+
revenue_dashboard:
|
|
937
|
+
x: 80
|
|
938
|
+
y: 80
|
|
939
|
+
parentId: dashboards_domain
|
|
865
940
|
```
|
package/visualizer/package.json
CHANGED
|
@@ -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}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.-bottom-1{bottom:-.25rem}.-left-1{left:-.25rem}.-left-\[15px\]{left:-15px}.-right-1{right:-.25rem}.bottom-2{bottom:.5rem}.bottom-4{bottom:1rem}.left-0{left:0}.left-1{left:.25rem}.left-1\/2{left:50%}.left-14{left:3.5rem}.left-3{left:.75rem}.left-4{left:1rem}.right-0{right:0}.right-14{right:3.5rem}.right-3{right:.75rem}.right-4{right:1rem}.right-6{right:1.5rem}.top-0{top:0}.top-1{top:.25rem}.top-1\/2{top:50%}.top-2{top:.5rem}.top-4{top:1rem}.top-6{top:1.5rem}.top-full{top:100%}.z-10{z-index:10}.z-50{z-index:50}.z-\[100\]{z-index:100}.z-\[110\]{z-index:110}.z-\[2000\]{z-index:2000}.z-\[200\]{z-index:200}.z-\[60\]{z-index:60}.-my-2{margin-top:-.5rem;margin-bottom:-.5rem}.mx-0\.5{margin-left:.125rem;margin-right:.125rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.-mt-3{margin-top:-.75rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.ml-0\.5{margin-left:.125rem}.ml-1{margin-left:.25rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.\!table{display:table!important}.table{display:table}.grid{display:grid}.hidden{display:none}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.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-8{height:2rem}.h-9{height:2.25rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[120px\]{max-height:120px}.max-h-\[300px\]{max-height:300px}.min-h-0{min-height:0px}.w-0\.5{width:.125rem}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-14{width:3.5rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-8{width:2rem}.w-\[456px\]{width:456px}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.w-screen{width:100vw}.min-w-0{min-width:0px}.min-w-\[140px\]{min-width:140px}.min-w-\[20px\]{min-width:20px}.min-w-\[60px\]{min-width:60px}.max-w-2xl{max-width:42rem}.max-w-\[180px\]{max-width:180px}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.caption-bottom{caption-side:bottom}.border-collapse{border-collapse:collapse}.-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))}.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 pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-help{cursor:help}.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}.resize-none{resize:none}.resize{resize:both}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(0px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px * var(--tw-space-y-reverse))}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-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))}.self-center{align-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.text-wrap{text-wrap:wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[inherit\]{border-radius:inherit}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-4{border-width:4px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-t-2{border-top-width:2px}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-blue-100{--tw-border-opacity: 1;border-color:rgb(219 234 254 / var(--tw-border-opacity, 1))}.border-blue-200{--tw-border-opacity: 1;border-color:rgb(191 219 254 / var(--tw-border-opacity, 1))}.border-blue-500\/20{border-color:#3b82f633}.border-blue-500\/30{border-color:#3b82f64d}.border-emerald-100{--tw-border-opacity: 1;border-color:rgb(209 250 229 / var(--tw-border-opacity, 1))}.border-emerald-500\/30{border-color:#10b9814d}.border-green-500\/40{border-color:#22c55e66}.border-green-500\/50{border-color:#22c55e80}.border-red-100{--tw-border-opacity: 1;border-color:rgb(254 226 226 / var(--tw-border-opacity, 1))}.border-red-500\/50{border-color:#ef444480}.border-slate-100{--tw-border-opacity: 1;border-color:rgb(241 245 249 / var(--tw-border-opacity, 1))}.border-slate-200{--tw-border-opacity: 1;border-color:rgb(226 232 240 / var(--tw-border-opacity, 1))}.border-slate-300{--tw-border-opacity: 1;border-color:rgb(203 213 225 / var(--tw-border-opacity, 1))}.border-slate-600{--tw-border-opacity: 1;border-color:rgb(71 85 105 / var(--tw-border-opacity, 1))}.border-slate-700{--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity, 1))}.border-slate-700\/30{border-color:#3341554d}.border-slate-700\/50{border-color:#33415580}.border-slate-800{--tw-border-opacity: 1;border-color:rgb(30 41 59 / var(--tw-border-opacity, 1))}.border-slate-800\/30{border-color:#1e293b4d}.border-slate-800\/50{border-color:#1e293b80}.border-transparent{border-color:transparent}.border-white{--tw-border-opacity: 1;border-color:rgb(255 255 255 / var(--tw-border-opacity, 1))}.border-l-blue-500{--tw-border-opacity: 1;border-left-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-l-slate-800{--tw-border-opacity: 1;border-left-color:rgb(30 41 59 / var(--tw-border-opacity, 1))}.border-l-transparent{border-left-color:transparent}.border-r-slate-800{--tw-border-opacity: 1;border-right-color:rgb(30 41 59 / var(--tw-border-opacity, 1))}.border-t-transparent{border-top-color:transparent}.bg-\[\#282c34\]{--tw-bg-opacity: 1;background-color:rgb(40 44 52 / 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-50\/50{background-color:#eff6ff80}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-500\/10{background-color:#3b82f61a}.bg-blue-500\/20{background-color:#3b82f633}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-blue-600\/10{background-color:#2563eb1a}.bg-emerald-50{--tw-bg-opacity: 1;background-color:rgb(236 253 245 / var(--tw-bg-opacity, 1))}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity, 1))}.bg-emerald-500\/10{background-color:#10b9811a}.bg-emerald-500\/20{background-color:#10b98133}.bg-emerald-600{--tw-bg-opacity: 1;background-color:rgb(5 150 105 / var(--tw-bg-opacity, 1))}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-500\/20{background-color:#22c55e33}.bg-green-500\/30{background-color:#22c55e4d}.bg-red-900\/90{background-color:#7f1d1de6}.bg-slate-100{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity, 1))}.bg-slate-200{--tw-bg-opacity: 1;background-color:rgb(226 232 240 / var(--tw-bg-opacity, 1))}.bg-slate-300{--tw-bg-opacity: 1;background-color:rgb(203 213 225 / var(--tw-bg-opacity, 1))}.bg-slate-400{--tw-bg-opacity: 1;background-color:rgb(148 163 184 / var(--tw-bg-opacity, 1))}.bg-slate-50{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.bg-slate-50\/50{background-color:#f8fafc80}.bg-slate-600{--tw-bg-opacity: 1;background-color:rgb(71 85 105 / var(--tw-bg-opacity, 1))}.bg-slate-700{--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity, 1))}.bg-slate-700\/50{background-color:#33415580}.bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.bg-slate-800\/30{background-color:#1e293b4d}.bg-slate-800\/40{background-color:#1e293b66}.bg-slate-800\/50{background-color:#1e293b80}.bg-slate-900{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity, 1))}.bg-slate-900\/20{background-color:#0f172a33}.bg-slate-900\/50{background-color:#0f172a80}.bg-slate-900\/80{background-color:#0f172acc}.bg-slate-900\/90{background-color:#0f172ae6}.bg-slate-950{--tw-bg-opacity: 1;background-color:rgb(2 6 23 / var(--tw-bg-opacity, 1))}.bg-slate-950\/20{background-color:#02061733}.bg-slate-950\/30{background-color:#0206174d}.bg-slate-950\/40{background-color:#02061766}.bg-slate-950\/50{background-color:#02061780}.bg-slate-950\/70{background-color:#020617b3}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/20{background-color:#fff3}.bg-white\/80{background-color:#fffc}.bg-white\/90{background-color:#ffffffe6}.stroke-\[3px\]{stroke-width:3px}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.p-\[1px\]{padding:1px}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.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-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.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-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-20{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}.pb-2{padding-bottom:.5rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pl-9{padding-left:2.25rem}.pr-1{padding-right:.25rem}.pr-2{padding-right:.5rem}.pr-4{padding-right:1rem}.pr-8{padding-right:2rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.pt-\[15vh\]{padding-top:15vh}.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}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji"}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.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-black{font-weight:900}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-tight{letter-spacing:-.025em}.tracking-tighter{letter-spacing:-.05em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.text-amber-500{--tw-text-opacity: 1;color:rgb(245 158 11 / var(--tw-text-opacity, 1))}.text-blue-100{--tw-text-opacity: 1;color:rgb(219 234 254 / var(--tw-text-opacity, 1))}.text-blue-300{--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.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-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-emerald-500{--tw-text-opacity: 1;color:rgb(16 185 129 / var(--tw-text-opacity, 1))}.text-emerald-600{--tw-text-opacity: 1;color:rgb(5 150 105 / var(--tw-text-opacity, 1))}.text-emerald-700{--tw-text-opacity: 1;color:rgb(4 120 87 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-green-400\/70{color:#4ade80b3}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-green-600\/70{color:#16a34ab3}.text-orange-400{--tw-text-opacity: 1;color:rgb(251 146 60 / var(--tw-text-opacity, 1))}.text-red-100{--tw-text-opacity: 1;color:rgb(254 226 226 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-500\/50{color:#ef444480}.text-slate-100{--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity, 1))}.text-slate-200{--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity, 1))}.text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.text-slate-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity, 1))}.text-slate-600{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.text-slate-700{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity, 1))}.text-slate-800{--tw-text-opacity: 1;color:rgb(30 41 59 / var(--tw-text-opacity, 1))}.text-slate-900{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.text-violet-400{--tw-text-opacity: 1;color:rgb(167 139 250 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.underline-offset-4{text-underline-offset:4px}.placeholder-slate-400::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(148 163 184 / var(--tw-placeholder-opacity, 1))}.placeholder-slate-400::placeholder{--tw-placeholder-opacity: 1;color:rgb(148 163 184 / var(--tw-placeholder-opacity, 1))}.placeholder-slate-600::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(71 85 105 / var(--tw-placeholder-opacity, 1))}.placeholder-slate-600::placeholder{--tw-placeholder-opacity: 1;color:rgb(71 85 105 / var(--tw-placeholder-opacity, 1))}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-20{opacity:.2}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-80{opacity:.8}.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-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px 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-\[0_32px_64px_-12px_rgba\(0\,0\,0\,0\.5\)\]{--tw-shadow: 0 32px 64px -12px rgba(0,0,0,.5);--tw-shadow-colored: 0 32px 64px -12px 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-inner{--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 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)}.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)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px 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-blue-500\/20{--tw-shadow-color: rgb(59 130 246 / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-blue-500\/5{--tw-shadow-color: rgb(59 130 246 / .05);--tw-shadow: var(--tw-shadow-colored)}.shadow-emerald-500\/20{--tw-shadow-color: rgb(16 185 129 / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-slate-200\/50{--tw-shadow-color: rgb(226 232 240 / .5);--tw-shadow: var(--tw-shadow-colored)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.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-\[2px\]{--tw-backdrop-blur: blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-md{--tw-backdrop-blur: blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur: blur(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,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}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}:root{--canvas-bg: #f1f5f9;--node-bg: #ffffff;--text-primary: #0f172a;--text-secondary: #64748b;--border-main: #e2e8f0;--header-bg: #f8fafc;--glass-bg: rgba(255, 255, 255, .7);--glass-border: rgba(203, 213, 225, .5)}.dark{--canvas-bg: #020617;--node-bg: #1e293b;--text-primary: #f1f5f9;--text-secondary: #94a3b8;--border-main: #334155;--header-bg: #0f172a;--glass-bg: rgba(15, 23, 42, .85);--glass-border: rgba(51, 65, 85, .5)}*{border-color:var(--border-main)}body{margin:0;padding:0;background-color:var(--canvas-bg);color:var(--text-primary);transition:background-color .3s ease,color .3s ease}#root{height:100vh;width:100vw}@keyframes node-appear{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.animate-creation{animation:node-appear .4s ease-out forwards}.custom-scrollbar::-webkit-scrollbar{width:4px}.custom-scrollbar::-webkit-scrollbar-track{background:transparent}.custom-scrollbar::-webkit-scrollbar-thumb{background:#0000001a;border-radius:10px}.dark .custom-scrollbar::-webkit-scrollbar-thumb{background:#ffffff1a}.custom-scrollbar::-webkit-scrollbar-thumb:hover{background:#0003}.dark .custom-scrollbar::-webkit-scrollbar-thumb:hover{background:#fff3}.last\:border-0:last-child{border-width:0px}.hover\:rotate-90:hover{--tw-rotate: 90deg;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))}.hover\:border-blue-300:hover{--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity, 1))}.hover\:border-blue-500\/50:hover{border-color:#3b82f680}.hover\:bg-blue-50:hover{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-50\/30:hover{background-color:#eff6ff4d}.hover\:bg-blue-500:hover{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.hover\:bg-blue-500\/20:hover{background-color:#3b82f633}.hover\:bg-blue-700:hover{--tw-bg-opacity: 1;background-color:rgb(29 78 216 / var(--tw-bg-opacity, 1))}.hover\:bg-emerald-700:hover{--tw-bg-opacity: 1;background-color:rgb(4 120 87 / var(--tw-bg-opacity, 1))}.hover\:bg-red-50:hover{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-100:hover{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-200:hover{--tw-bg-opacity: 1;background-color:rgb(226 232 240 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-50:hover{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-700:hover{--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-800:hover{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.hover\:bg-slate-800\/30:hover{background-color:#1e293b4d}.hover\:bg-slate-800\/50:hover{background-color:#1e293b80}.hover\:bg-slate-800\/60:hover{background-color:#1e293b99}.hover\:bg-violet-50:hover{--tw-bg-opacity: 1;background-color:rgb(245 243 255 / var(--tw-bg-opacity, 1))}.hover\:bg-white:hover{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.hover\:text-blue-400:hover{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.hover\:text-blue-500:hover{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.hover\:text-blue-600:hover{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.hover\:text-red-400:hover{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.hover\:text-red-500:hover{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.hover\:text-slate-100:hover{--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity, 1))}.hover\:text-slate-200:hover{--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity, 1))}.hover\:text-slate-300:hover{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.hover\:text-slate-400:hover{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.hover\:text-slate-600:hover{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.hover\:text-slate-700:hover{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity, 1))}.hover\:text-slate-900:hover{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity, 1))}.hover\:text-violet-600:hover{--tw-text-opacity: 1;color:rgb(124 58 237 / var(--tw-text-opacity, 1))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.hover\:opacity-50:hover{opacity:.5}.hover\:shadow-md:hover{--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)}.hover\:shadow-sm:hover{--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)}.focus\:border-blue-400:focus{--tw-border-opacity: 1;border-color:rgb(96 165 250 / var(--tw-border-opacity, 1))}.focus\:border-blue-500\/30:focus{border-color:#3b82f64d}.focus\:border-blue-500\/50:focus{border-color:#3b82f680}.focus\:bg-blue-50:focus{--tw-bg-opacity: 1;background-color:rgb(239 246 255 / var(--tw-bg-opacity, 1))}.focus\:bg-slate-50:focus{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity, 1))}.focus\:bg-slate-800:focus{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-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-blue-400:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(96 165 250 / var(--tw-ring-opacity, 1))}.focus\:ring-blue-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity, 1))}.focus\:ring-blue-500\/50:focus{--tw-ring-color: rgb(59 130 246 / .5)}.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-offset-2:focus-visible{--tw-ring-offset-width: 2px}.active\:scale-90:active{--tw-scale-x: .9;--tw-scale-y: .9;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))}.active\:scale-95:active{--tw-scale-x: .95;--tw-scale-y: .95;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))}.active\:scale-\[0\.98\]:active{--tw-scale-x: .98;--tw-scale-y: .98;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))}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.group:hover .group-hover\:animate-bounce{animation:bounce 1s infinite}.group:hover .group-hover\:text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.group:hover .group-hover\:text-slate-600{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.group:hover .group-hover\:opacity-100{opacity:1}.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)}@media(min-width:640px){.sm\:block{display:block}}@media(prefers-color-scheme:dark){.dark\:border-slate-700{--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity, 1))}.dark\:border-slate-800{--tw-border-opacity: 1;border-color:rgb(30 41 59 / var(--tw-border-opacity, 1))}.dark\:border-slate-900{--tw-border-opacity: 1;border-color:rgb(15 23 42 / var(--tw-border-opacity, 1))}.dark\:bg-slate-700{--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity, 1))}.dark\:bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.dark\:text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.dark\:text-slate-600{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.dark\:hover\:bg-slate-800:hover{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.dark\:hover\:bg-slate-900:hover{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity, 1))}}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&\>tr\]\:last\:border-b-0:last-child>tr{border-bottom-width:0px}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:1rem;height:1rem}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0px}.\[\&_tr\]\:border-b tr{border-bottom-width:1px}
|