@reddb-io/ui 0.1.1 → 0.3.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.
Files changed (60) hide show
  1. package/build/_app/immutable/assets/0.DQDLkSdR.css +1 -0
  2. package/build/_app/immutable/assets/Workspace.CvP5De7i.css +1 -0
  3. package/build/_app/immutable/chunks/65XjEwaF.js +367 -0
  4. package/build/_app/immutable/chunks/BjFADNkA.js +992 -0
  5. package/build/_app/immutable/chunks/{ALqaDrNQ.js → C278awGv.js} +1 -1
  6. package/build/_app/immutable/chunks/{Ov8N-vxt.js → C9rXzYLu.js} +1 -1
  7. package/build/_app/immutable/chunks/CDKIdLnm.js +187 -0
  8. package/build/_app/immutable/chunks/{DXY_Rxa7.js → CXNPJgv1.js} +7 -7
  9. package/build/_app/immutable/chunks/{Bgso8cDH.js → DqvWKbSc.js} +1 -1
  10. package/build/_app/immutable/chunks/pDJnDxXM.js +1 -0
  11. package/build/_app/immutable/entry/app.DdaMXHAv.js +2 -0
  12. package/build/_app/immutable/entry/start.-MLBtQXB.js +1 -0
  13. package/build/_app/immutable/nodes/{0.CHPiFxDo.js → 0.Ysoz3Y3h.js} +1 -1
  14. package/build/_app/immutable/nodes/{1.BC_4YZ0h.js → 1.C2jbGTOJ.js} +1 -1
  15. package/build/_app/immutable/nodes/11.CAG5_cGP.js +1 -0
  16. package/build/_app/immutable/nodes/{10.B7DMKSNc.js → 12.DQG5zpEx.js} +5 -5
  17. package/build/_app/immutable/nodes/7.CAG5_cGP.js +1 -0
  18. package/build/_app/immutable/nodes/{7.BZX9Iird.js → 8.CrHI4F9p.js} +1 -1
  19. package/build/_app/version.json +1 -1
  20. package/build/index.html +12 -12
  21. package/dist/embed/{RedUiEmbedRoot-BGoLxJf1.js → RedUiEmbedRoot-BwFUA5X-.js} +12715 -10653
  22. package/dist/embed/RedUiEmbedRoot-BwFUA5X-.js.map +1 -0
  23. package/dist/embed/index-DGhgtnaK.js +577 -0
  24. package/dist/embed/{index-B6ZQhCsu.js.map → index-DGhgtnaK.js.map} +1 -1
  25. package/dist/embed/{index-fad77a13.esm-BqPj0saH.js → index-fad77a13.esm-BMULHdcE.js} +22 -20
  26. package/dist/embed/{index-fad77a13.esm-BqPj0saH.js.map → index-fad77a13.esm-BMULHdcE.js.map} +1 -1
  27. package/dist/embed/index.js +1 -1
  28. package/dist/embed/sigma-edge-curve.esm-CAT5Xrom.js +536 -0
  29. package/dist/embed/sigma-edge-curve.esm-CAT5Xrom.js.map +1 -0
  30. package/dist/embed/{sigma-node-border.esm-CGtlgqmo.js → sigma-node-border.esm-Bnk4BRbw.js} +32 -32
  31. package/dist/embed/{sigma-node-border.esm-CGtlgqmo.js.map → sigma-node-border.esm-Bnk4BRbw.js.map} +1 -1
  32. package/dist/embed/{sigma.esm-y0qgY-OC.js → sigma.esm-D5yoExsH.js} +3 -3
  33. package/dist/embed/{sigma.esm-y0qgY-OC.js.map → sigma.esm-D5yoExsH.js.map} +1 -1
  34. package/package.json +5 -3
  35. package/src/lib/Appearance.svelte +90 -0
  36. package/src/lib/CommandPalette.svelte +2 -0
  37. package/src/lib/SettingsView.svelte +376 -0
  38. package/src/lib/Topbar.svelte +15 -1
  39. package/src/lib/Workspace.svelte +14 -1
  40. package/src/lib/index.ts +2 -0
  41. package/src/lib/renderers/GraphRenderer.svelte +448 -44
  42. package/src/lib/renderers/graph-bundle.ts +401 -0
  43. package/src/lib/renderers/graph-communities.ts +193 -0
  44. package/src/lib/renderers/graph-render.ts +48 -5
  45. package/src/lib/renderers/graph-sigma.ts +274 -8
  46. package/src/lib/router.svelte.ts +84 -57
  47. package/src/lib/settings-sections.ts +267 -0
  48. package/src/lib/skins/skins.svelte.ts +64 -0
  49. package/src/lib/skins/skins.ts +178 -0
  50. package/build/_app/immutable/assets/0.C63jY5jX.css +0 -1
  51. package/build/_app/immutable/assets/Workspace.BCzG1DsH.css +0 -1
  52. package/build/_app/immutable/chunks/BMHKbvs8.js +0 -1
  53. package/build/_app/immutable/chunks/BQHbwf54.js +0 -916
  54. package/build/_app/immutable/chunks/Bmgx1mfv.js +0 -310
  55. package/build/_app/immutable/entry/app.D_IVtpdv.js +0 -2
  56. package/build/_app/immutable/entry/start.3oC0UQ_Q.js +0 -1
  57. package/dist/embed/RedUiEmbedRoot-BGoLxJf1.js.map +0 -1
  58. package/dist/embed/index-B6ZQhCsu.js +0 -577
  59. /package/build/_app/immutable/assets/{10.Dblyk0Kr.css → 12.Dblyk0Kr.css} +0 -0
  60. /package/build/_app/immutable/nodes/{8.CAG5_cGP.js → 10.CAG5_cGP.js} +0 -0
@@ -0,0 +1,267 @@
1
+ // Data-driven settings registry + a pure config-key resolver.
2
+ //
3
+ // Settings are defined as DATA, not hand-built rows: `SECTIONS` lists the
4
+ // curated config keys per section, and three override maps (`LABELS`,
5
+ // `DESCRIPTIONS`, `ENUM_OPTIONS`) keyed by config path supply the human copy.
6
+ // `resolveControl(key, value)` maps a single reddb config/connection key to a
7
+ // rendered control descriptor (human label, description, input kind, enum
8
+ // options), degrading gracefully for keys nobody curated. Adding a curated key
9
+ // is a one-line edit to a section's `keys` array.
10
+ //
11
+ // Kept framework-free (no Svelte imports) so the registry and the resolver are
12
+ // trivially unit-testable. Icons are mapped to components in `SettingsView`,
13
+ // not here — a section carries only an icon *name*. Mirrors the registry idiom
14
+ // in `renderers/registry`: a tiny pure surface over curated data.
15
+
16
+ /** The input control a config value is rendered through. */
17
+ export type ControlKind = "text" | "number" | "boolean" | "enum";
18
+
19
+ /** Where a config key is sourced from — gates permission-aware rendering. */
20
+ export type SettingsSource = "stats" | "cluster" | "capabilities" | "session";
21
+
22
+ /** A resolved control for one config key. */
23
+ export interface ControlDescriptor {
24
+ /** The config path this descriptor was resolved from. */
25
+ key: string;
26
+ /** Human label — a curated override or a humanized key. */
27
+ label: string;
28
+ /** Optional one-line explanation. */
29
+ description?: string;
30
+ /** Input kind inferred from the curated enum map or the value's type. */
31
+ kind: ControlKind;
32
+ /** Allowed values when `kind === "enum"`. */
33
+ options?: readonly string[];
34
+ }
35
+
36
+ export interface SettingsSection {
37
+ /** Stable identifier used as the active-section key (component state only). */
38
+ id: string;
39
+ /** Nav label. */
40
+ label: string;
41
+ /** One-line description shown under the section title. */
42
+ blurb: string;
43
+ /** Icon name resolved to a lucide component in `SettingsView`. */
44
+ icon: string;
45
+ /** Curated config keys, rendered top-to-bottom. One-line edit to extend. */
46
+ keys: string[];
47
+ }
48
+
49
+ /**
50
+ * The curated sections. Each `keys` entry is a flattened reddb config path
51
+ * (see `flattenConfig`) sourced from `/stats`, `/cluster/status`,
52
+ * `/capabilities`, or the session (`whoami`). Order is the render order.
53
+ */
54
+ export const SECTIONS: SettingsSection[] = [
55
+ {
56
+ id: "overview",
57
+ label: "Overview",
58
+ blurb: "What this reddb instance is and where it runs.",
59
+ icon: "settings",
60
+ keys: [
61
+ "deployment.mode",
62
+ "read_only",
63
+ "system.os",
64
+ "system.arch",
65
+ "system.hostname",
66
+ "system.cpu_cores",
67
+ ],
68
+ },
69
+ {
70
+ id: "storage",
71
+ label: "Storage",
72
+ blurb: "Live store footprint for the active connection.",
73
+ icon: "database",
74
+ keys: [
75
+ "store.collection_count",
76
+ "store.total_entities",
77
+ "store.cross_ref_count",
78
+ "store.total_memory_bytes",
79
+ ],
80
+ },
81
+ {
82
+ id: "cluster",
83
+ label: "Cluster",
84
+ blurb: "Deployment and replication topology.",
85
+ icon: "network",
86
+ keys: [
87
+ "deployment.mode",
88
+ "deployment.file_path",
89
+ "replication.replica_count",
90
+ "replication.lag_ms",
91
+ ],
92
+ },
93
+ {
94
+ id: "capabilities",
95
+ label: "Capabilities",
96
+ blurb: "Endpoints negotiated for this server version.",
97
+ icon: "plug",
98
+ keys: [
99
+ "capabilities.vcs",
100
+ "capabilities.clusterStatus",
101
+ "capabilities.collectionMetadata",
102
+ "capabilities.cdcStream",
103
+ ],
104
+ },
105
+ {
106
+ id: "session",
107
+ label: "Session",
108
+ blurb: "Who red-ui is authenticated as on this connection.",
109
+ icon: "shield",
110
+ keys: ["session.username", "session.role", "session.authenticated"],
111
+ },
112
+ ];
113
+
114
+ /** Curated label overrides, keyed by config path. */
115
+ export const LABELS: Record<string, string> = {
116
+ "deployment.mode": "Deployment mode",
117
+ "deployment.file_path": "Backing file",
118
+ read_only: "Read-only",
119
+ "system.os": "Operating system",
120
+ "system.arch": "Architecture",
121
+ "system.hostname": "Hostname",
122
+ "system.cpu_cores": "CPU cores",
123
+ "store.collection_count": "Collections",
124
+ "store.total_entities": "Entities",
125
+ "store.cross_ref_count": "Cross-references",
126
+ "store.total_memory_bytes": "Memory in use",
127
+ "replication.replica_count": "Replicas",
128
+ "replication.lag_ms": "Replication lag",
129
+ "capabilities.vcs": "Version control",
130
+ "capabilities.clusterStatus": "Cluster status",
131
+ "capabilities.collectionMetadata": "Collection metadata",
132
+ "capabilities.cdcStream": "Change stream",
133
+ "session.username": "Username",
134
+ "session.role": "Role",
135
+ "session.authenticated": "Authenticated",
136
+ };
137
+
138
+ /** Curated descriptions, keyed by config path. */
139
+ export const DESCRIPTIONS: Record<string, string> = {
140
+ "deployment.mode": "How this reddb instance is running.",
141
+ "deployment.file_path": "On-disk store path for an embedded or local server.",
142
+ read_only: "Whether the store rejects writes (a lock or a replica role).",
143
+ "store.total_memory_bytes": "Resident memory the store currently holds.",
144
+ "replication.lag_ms": "How far this replica trails the primary, in ms.",
145
+ "capabilities.vcs": "Commit and diff endpoints — gated when unsupported.",
146
+ "capabilities.cdcStream": "Server-sent change stream over /changes/stream.",
147
+ "session.role": "The role granted to this principal on the active target.",
148
+ };
149
+
150
+ /** Curated enum options, keyed by config path. Presence ⇒ `kind: "enum"`. */
151
+ export const ENUM_OPTIONS: Record<string, readonly string[]> = {
152
+ "deployment.mode": ["embedded", "server", "docker", "replicated"],
153
+ };
154
+
155
+ /**
156
+ * Turn a config path into a human label when nobody curated one:
157
+ * `store.total_memory_bytes` → "Total memory bytes". Uses the last path
158
+ * segment, swaps `_`/`-` for spaces, and sentence-cases the result.
159
+ */
160
+ export function humanizeKey(key: string): string {
161
+ const last = key.split(".").pop() ?? key;
162
+ const words = last.replace(/[_-]+/g, " ").trim();
163
+ if (!words) return key;
164
+ return words.charAt(0).toUpperCase() + words.slice(1);
165
+ }
166
+
167
+ /**
168
+ * Resolve a config key (and its live value) to a rendered control descriptor.
169
+ *
170
+ * Resolution order, each degrading gracefully:
171
+ * - label: `LABELS[key]` → `humanizeKey(key)`
172
+ * - description: `DESCRIPTIONS[key]` → omitted
173
+ * - kind: `ENUM_OPTIONS[key]` ⇒ `"enum"`; else inferred from the value's
174
+ * runtime type (boolean / number) → `"text"` for everything else, including
175
+ * `undefined`. So an unknown key with no value still yields a valid `"text"`
176
+ * descriptor rather than throwing.
177
+ */
178
+ export function resolveControl(
179
+ key: string,
180
+ value?: unknown
181
+ ): ControlDescriptor {
182
+ const options = ENUM_OPTIONS[key];
183
+ const kind: ControlKind = options
184
+ ? "enum"
185
+ : typeof value === "boolean"
186
+ ? "boolean"
187
+ : typeof value === "number"
188
+ ? "number"
189
+ : "text";
190
+ const descriptor: ControlDescriptor = {
191
+ key,
192
+ label: LABELS[key] ?? humanizeKey(key),
193
+ kind,
194
+ };
195
+ const description = DESCRIPTIONS[key];
196
+ if (description) descriptor.description = description;
197
+ if (options) descriptor.options = options;
198
+ return descriptor;
199
+ }
200
+
201
+ /** Which live source a config key is read from — drives permission-awareness. */
202
+ export function sourceForKey(key: string): SettingsSource {
203
+ if (key.startsWith("capabilities.")) return "capabilities";
204
+ if (key.startsWith("session.")) return "session";
205
+ if (
206
+ key.startsWith("deployment.") ||
207
+ key.startsWith("storage.") ||
208
+ key.startsWith("wal.") ||
209
+ key.startsWith("throughput.") ||
210
+ key.startsWith("replication.")
211
+ ) {
212
+ return "cluster";
213
+ }
214
+ return "stats";
215
+ }
216
+
217
+ /**
218
+ * Flatten a nested config snapshot into dotted leaf paths. Nested plain objects
219
+ * recurse (`{ store: { collection_count: 3 } }` → `"store.collection_count"`);
220
+ * arrays and primitives are kept as leaf values. `undefined`/`null` branches
221
+ * are skipped so a server that omits a sub-tree simply yields no keys for it.
222
+ */
223
+ export function flattenConfig(
224
+ input: Record<string, unknown>
225
+ ): Record<string, unknown> {
226
+ const out: Record<string, unknown> = {};
227
+ const walk = (obj: Record<string, unknown>, prefix: string) => {
228
+ for (const [k, v] of Object.entries(obj)) {
229
+ const key = prefix ? `${prefix}.${k}` : k;
230
+ if (v === undefined || v === null) continue;
231
+ if (typeof v === "object" && !Array.isArray(v)) {
232
+ walk(v as Record<string, unknown>, key);
233
+ } else {
234
+ out[key] = v;
235
+ }
236
+ }
237
+ };
238
+ walk(input, "");
239
+ return out;
240
+ }
241
+
242
+ /**
243
+ * Resolve a section by id, falling back to the first section when the id is
244
+ * unknown or null. The settings view drives the active section purely from
245
+ * component state, so this never touches the URL.
246
+ */
247
+ export function resolveSection(id: string | null): SettingsSection {
248
+ return SECTIONS.find((s) => s.id === id) ?? SECTIONS[0];
249
+ }
250
+
251
+ /**
252
+ * Filter a section's curated keys by a free-text query, matching against both
253
+ * the config path AND the resolved human label (case-insensitive). An empty or
254
+ * whitespace-only query returns the keys unchanged. Pure + framework-free so
255
+ * the settings search is unit-testable without rendering. The settings view
256
+ * keeps one query string per section id, so switching sections preserves each
257
+ * section's typed query.
258
+ */
259
+ export function filterKeys(keys: readonly string[], query: string): string[] {
260
+ const q = query.trim().toLowerCase();
261
+ if (!q) return [...keys];
262
+ return keys.filter(
263
+ (key) =>
264
+ key.toLowerCase().includes(q) ||
265
+ resolveControl(key).label.toLowerCase().includes(q)
266
+ );
267
+ }
@@ -0,0 +1,64 @@
1
+ // Thin reactive shell over the pure skin core (`skins.ts`).
2
+ //
3
+ // Holds the selected skin in rune state, applies it to the document, and
4
+ // persists the choice so it survives reloads. All the colour math lives in
5
+ // the pure `skinToCssVars` mapping — this file only does DOM + localStorage.
6
+
7
+ import {
8
+ DEFAULT_SKIN,
9
+ STORAGE_KEY,
10
+ applySkin,
11
+ skinByName,
12
+ type Skin,
13
+ } from "./skins";
14
+
15
+ function readPersisted(): string | null {
16
+ if (typeof localStorage === "undefined") return null;
17
+ return localStorage.getItem(STORAGE_KEY);
18
+ }
19
+
20
+ function persist(name: string) {
21
+ if (typeof localStorage === "undefined") return;
22
+ localStorage.setItem(STORAGE_KEY, name);
23
+ }
24
+
25
+ function rootEl(target?: HTMLElement | null): HTMLElement | null {
26
+ return (
27
+ target ??
28
+ (typeof document !== "undefined" ? document.documentElement : null)
29
+ );
30
+ }
31
+
32
+ class SkinStore {
33
+ /** The currently selected skin (reactive). */
34
+ current = $state<Skin>(DEFAULT_SKIN);
35
+ private target: HTMLElement | null = null;
36
+
37
+ /**
38
+ * Sync the store with the persisted selection and apply it. Call once on
39
+ * mount (after the theme inline script has run). With nothing persisted the
40
+ * store reports the default skin but leaves the inherited theme untouched.
41
+ */
42
+ init(target?: HTMLElement | null) {
43
+ this.target = rootEl(target);
44
+ const persisted = readPersisted();
45
+ if (persisted) {
46
+ this.current = skinByName(persisted);
47
+ if (this.target) applySkin(this.current, this.target);
48
+ }
49
+ }
50
+
51
+ /** Select a skin: apply its vars to the DOM and persist the choice. */
52
+ select(name: string) {
53
+ const skin = skinByName(name);
54
+ this.current = skin;
55
+ const el = rootEl(this.target);
56
+ if (el) {
57
+ this.target = el;
58
+ applySkin(skin, el);
59
+ }
60
+ persist(skin.name);
61
+ }
62
+ }
63
+
64
+ export const skins = new SkinStore();
@@ -0,0 +1,178 @@
1
+ // Skin-as-data theming (#75).
2
+ //
3
+ // A skin is *plain data*: a name, human labels, a handful of colour seeds
4
+ // (dark), and a type pairing. Adding a skin is a single entry in `SKINS` —
5
+ // no render code changes. The pure `skinToCssVars` mapping turns those seeds
6
+ // into the full `--color-*` custom-property set the app already consumes,
7
+ // deriving the `--color-bg-0..bg-3` surface ramp (and the `fg`/`line` ramps)
8
+ // via CSS `color-mix` so the steps stay perceptually monotonic without
9
+ // hand-tuning every level. The DOM application + persistence below is a thin
10
+ // shell over that pure core.
11
+ //
12
+ // Dark-only by design: every seed is a dark surface, and there is no
13
+ // `light` / `system` branch. The default skin keeps reddb's signature
14
+ // `#ff2056` accent.
15
+
16
+ export interface SkinSeeds {
17
+ /** Darkest surface — becomes `--color-bg-0`; every other surface ramps up from it. */
18
+ bg: string;
19
+ /** Surgical accent — `--color-accent` and the primary node role. */
20
+ accent: string;
21
+ /** Primary text (`--color-fg-0`); the fg ramp darkens toward `bg`. */
22
+ fg: string;
23
+ }
24
+
25
+ export interface SkinTypography {
26
+ /** `--font-sans` stack. */
27
+ sans: string;
28
+ /** `--font-mono` stack. */
29
+ mono: string;
30
+ }
31
+
32
+ export interface Skin {
33
+ /** Stable id, persisted in localStorage and used for selection. */
34
+ name: string;
35
+ /** Human label shown on the preview card. */
36
+ label: string;
37
+ /** One-line description of the mood. */
38
+ description: string;
39
+ /** Dark colour seeds. */
40
+ colors: SkinSeeds;
41
+ /** Type pairing. */
42
+ typography: SkinTypography;
43
+ }
44
+
45
+ const FONT_SANS =
46
+ "'Inter Variable', 'Inter', system-ui, -apple-system, sans-serif";
47
+ const FONT_MONO =
48
+ "'JetBrains Mono Variable', 'JetBrains Mono', ui-monospace, 'SF Mono', 'Menlo', monospace";
49
+
50
+ /**
51
+ * The registry. Two curated dark skins — the mechanism, not a buffet.
52
+ * The first entry is the default.
53
+ */
54
+ export const SKINS: readonly Skin[] = [
55
+ {
56
+ name: "reddb",
57
+ label: "Reddb",
58
+ description: "The signature near-black with a surgical rose accent.",
59
+ colors: { bg: "#050607", accent: "#ff2056", fg: "#f7f8fa" },
60
+ typography: { sans: FONT_SANS, mono: FONT_MONO },
61
+ },
62
+ {
63
+ name: "nocturne",
64
+ label: "Nocturne",
65
+ description: "Indigo-tinted midnight with a violet accent.",
66
+ colors: { bg: "#0a0b14", accent: "#7c5cff", fg: "#f5f6fb" },
67
+ typography: { sans: FONT_SANS, mono: FONT_MONO },
68
+ },
69
+ ] as const;
70
+
71
+ export const DEFAULT_SKIN = SKINS[0];
72
+
73
+ export const STORAGE_KEY = "red-ui-skin";
74
+
75
+ /** Look a skin up by name, falling back to the default. */
76
+ export function skinByName(name: string | null | undefined): Skin {
77
+ return SKINS.find((s) => s.name === name) ?? DEFAULT_SKIN;
78
+ }
79
+
80
+ // ─── pure mapping (the unit-testable core) ──────────────────────────────────
81
+
82
+ /**
83
+ * `color-mix(in srgb, <lift> P%, <base>)`. In the sRGB space this is a linear
84
+ * interpolation, so a strictly increasing `pct` of a lighter `lift` yields a
85
+ * strictly lighter result — which is what keeps the surface ramp monotonic.
86
+ */
87
+ function mix(lift: string, pct: number, base: string): string {
88
+ return `color-mix(in srgb, ${lift} ${pct}%, ${base})`;
89
+ }
90
+
91
+ /** `color-mix(in srgb, <color> P%, transparent)` — a translucent wash of `color`. */
92
+ function alpha(color: string, pct: number): string {
93
+ return `color-mix(in srgb, ${color} ${pct}%, transparent)`;
94
+ }
95
+
96
+ /**
97
+ * Surface ramp `bg-0..bg-3`, lightened from the `bg` seed by an increasing
98
+ * fraction of white. `bg-0` is the pure seed (0% lift); the lift percentages
99
+ * are strictly increasing, so the ramp is monotonic by construction.
100
+ */
101
+ const SURFACE_LIFT = [0, 4, 9, 15] as const;
102
+ /** Hairline ramp `line-1..3`, also lightened from `bg` with white. */
103
+ const LINE_LIFT = [6, 13, 22] as const;
104
+ /**
105
+ * Text ramp `fg-0..fg-3`, faded from the `fg` seed toward `bg` by a
106
+ * decreasing fraction of `fg`. `fg-0` is the pure seed (100%); the
107
+ * percentages decrease, so readability steps down monotonically.
108
+ */
109
+ const TEXT_MIX = [100, 78, 58, 45] as const;
110
+
111
+ /**
112
+ * Pure seed → CSS-var mapping. Returns the complete custom-property set the
113
+ * app's tokens expect, with the `bg`/`fg`/`line` ramps derived via `color-mix`
114
+ * and the accent washes derived from the accent seed. No DOM, no I/O — this is
115
+ * what the unit tests exercise.
116
+ */
117
+ export function skinToCssVars(skin: Skin): Record<string, string> {
118
+ const { bg, accent, fg } = skin.colors;
119
+ const white = "#ffffff";
120
+
121
+ const vars: Record<string, string> = {
122
+ // Surfaces — monotonic ramp from the bg seed.
123
+ "--color-bg-0":
124
+ SURFACE_LIFT[0] === 0 ? bg : mix(white, SURFACE_LIFT[0], bg),
125
+ "--color-bg-1": mix(white, SURFACE_LIFT[1], bg),
126
+ "--color-bg-2": mix(white, SURFACE_LIFT[2], bg),
127
+ "--color-bg-3": mix(white, SURFACE_LIFT[3], bg),
128
+
129
+ // Text — monotonic ramp fading toward the bg seed.
130
+ "--color-fg-0": fg,
131
+ "--color-fg-1": mix(fg, TEXT_MIX[1], bg),
132
+ "--color-fg-2": mix(fg, TEXT_MIX[2], bg),
133
+ "--color-fg-3": mix(fg, TEXT_MIX[3], bg),
134
+
135
+ // Hairlines.
136
+ "--color-line-1": mix(white, LINE_LIFT[0], bg),
137
+ "--color-line-2": mix(white, LINE_LIFT[1], bg),
138
+ "--color-line-3": mix(white, LINE_LIFT[2], bg),
139
+
140
+ // Surgical accent + washes derived from the accent seed.
141
+ "--color-accent": accent,
142
+ "--color-accent-soft": alpha(accent, 12),
143
+ "--color-accent-glow": alpha(accent, 45),
144
+ "--color-ambient-glow": alpha(accent, 6),
145
+
146
+ // Node roles — primary tracks the accent; replica/embedded stay legible
147
+ // semantic hues that read on any dark surface.
148
+ "--color-role-primary": accent,
149
+ "--color-role-replica": "#60a5fa",
150
+ "--color-role-embedded": "#4ade80",
151
+
152
+ // Semantic — dark-tuned, shared across skins.
153
+ "--color-ok": "#4ade80",
154
+ "--color-warn": "#fbbf24",
155
+ "--color-danger": "#ff5470",
156
+ "--color-info": "#60a5fa",
157
+
158
+ // Typography.
159
+ "--font-sans": skin.typography.sans,
160
+ "--font-mono": skin.typography.mono,
161
+ };
162
+
163
+ return vars;
164
+ }
165
+
166
+ /**
167
+ * Apply a skin's derived custom properties to a DOM element as inline styles.
168
+ * Inline styles win over the stylesheet's `:root` rules, so this overrides the
169
+ * active theme tokens regardless of `data-theme`. The thin shell
170
+ * (`skins.svelte.ts`) wires this to mount + persistence.
171
+ */
172
+ export function applySkin(skin: Skin, target: HTMLElement) {
173
+ const vars = skinToCssVars(skin);
174
+ for (const [k, v] of Object.entries(vars)) target.style.setProperty(k, v);
175
+ // Skins are dark-only; pin data-theme so the shadcn semantic aliases that
176
+ // key off it stay consistent with the inline surface ramp.
177
+ target.dataset.theme = "dark";
178
+ }
@@ -1 +0,0 @@
1
- /*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:"Inter Variable", "Inter", system-ui, -apple-system, sans-serif;--font-serif:ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;--font-mono:"JetBrains Mono Variable", "JetBrains Mono", ui-monospace, "SF Mono", "Menlo", monospace;--color-yellow-200:oklch(94.5% .129 101.54);--color-lime-500:oklch(76.8% .233 130.85);--color-purple-700:oklch(49.6% .265 301.924);--color-zinc-300:oklch(87.1% .006 286.286);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--container-2xl:42rem;--container-6xl:72rem;--text-xs:11px;--text-xs--line-height:1.45;--text-sm:12px;--text-sm--line-height:1.5;--text-lg:18px;--text-lg--line-height:1.3;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-relaxed:1.625;--radius-md:5px;--radius-lg:8px;--shadow-md:0 4px 12px #0f172a14, 0 0 0 1px var(--color-line-2);--shadow-lg:0 16px 48px #0f172a24, 0 0 0 1px var(--color-line-2);--ease-out:cubic-bezier(.16, 1, .3, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--blur-sm:8px;--blur-md:12px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-bg-0:#fff;--color-bg-1:#fafafa;--color-bg-2:#f4f4f5;--color-bg-3:#e7e7ea;--color-fg-0:#0a0a0b;--color-fg-1:#3f3f46;--color-fg-2:#52525b;--color-fg-3:#71717a;--color-line-1:#ececef;--color-line-2:#d4d4d8;--color-line-3:#a1a1aa;--color-accent:#e11d48;--color-accent-soft:#e11d481a;--color-accent-glow:#e11d484d;--color-ok:#16a34a;--color-warn:#b45309;--color-danger:#dc2626;--color-info:#2563eb;--color-role-primary:#e11d48;--color-role-replica:#2563eb;--color-role-embedded:#16a34a;--color-ambient-glow:#e11d480a;--ease-snap:cubic-bezier(.25, 1, .5, 1)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}:root{--background:var(--color-bg-0);--foreground:var(--color-fg-0);--card:var(--color-bg-1);--card-foreground:var(--color-fg-0);--popover:var(--color-bg-1);--popover-foreground:var(--color-fg-0);--primary:var(--color-accent);--primary-foreground:#fff;--secondary:var(--color-bg-2);--secondary-foreground:var(--color-fg-1);--muted:var(--color-bg-2);--muted-foreground:var(--color-fg-2);--accent:var(--color-bg-3);--accent-foreground:var(--color-fg-0);--destructive:var(--color-danger);--destructive-foreground:#fff;--border:var(--color-line-2);--input:var(--color-line-2);--ring:var(--color-accent);--radius:var(--radius-md)}*{box-sizing:border-box}html,body{background:var(--color-bg-0);color:var(--color-fg-0);font-family:var(--font-sans);font-feature-settings:"cv11","ss01","ss03";letter-spacing:-.005em;-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;margin:0;font-size:13px;line-height:1.5}.type-h1{letter-spacing:-.02em;color:var(--color-fg-0);font-size:22px;font-weight:600;line-height:1.2}.type-h2{letter-spacing:-.015em;color:var(--color-fg-0);font-size:16px;font-weight:600;line-height:1.3}.type-label{font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.1em;color:var(--color-fg-2);font-size:10px;font-weight:500}.type-caption{color:var(--color-fg-2);font-size:11px;line-height:1.45}.type-code{font-family:var(--font-mono);color:var(--color-fg-1);font-size:12px}body:before{content:"";background-image:radial-gradient(ellipse 80% 50% at 50% -10%,var(--color-ambient-glow),transparent),linear-gradient(var(--color-line-1) 1px,transparent 1px),linear-gradient(90deg,var(--color-line-1) 1px,transparent 1px);opacity:.35;pointer-events:none;z-index:0;background-size:100% 100%,96px 96px,96px 96px;position:fixed;top:0;right:0;bottom:0;left:0}::selection{background:var(--color-accent-soft);color:var(--color-fg-0)}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--color-line-2);border:2px solid var(--color-bg-0);border-radius:8px}::-webkit-scrollbar-thumb:hover{background:var(--color-line-3)}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.top-1\/2{top:50%}.top-4{top:calc(var(--spacing) * 4)}.top-\[calc\(100\%\+6px\)\]{top:calc(100% + 6px)}.top-full{top:100%}.right-0{right:calc(var(--spacing) * 0)}.right-1{right:calc(var(--spacing) * 1)}.right-4{right:calc(var(--spacing) * 4)}.bottom-0{bottom:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.left-1\/2{left:50%}.left-2\.5{left:calc(var(--spacing) * 2.5)}.left-4{left:calc(var(--spacing) * 4)}.z-10{z-index:10}.z-20{z-index:20}.z-40{z-index:40}.z-50{z-index:50}.z-\[1\]{z-index:1}.z-\[100\]{z-index:100}.z-\[200\]{z-index:200}.z-\[9999\]{z-index:9999}.col-start-1{grid-column-start:1}.col-start-2{grid-column-start:2}.row-start-1{grid-row-start:1}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.m-0{margin:calc(var(--spacing) * 0)}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.mx-px{margin-inline:1px}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mr-0\.5{margin-right:calc(var(--spacing) * .5)}.-mb-px{margin-bottom:-1px}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-auto{margin-left:auto}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.size-2{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-3\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-11{height:calc(var(--spacing) * 11)}.h-\[18px\]{height:18px}.h-\[82px\]{height:82px}.h-\[180px\]{height:180px}.h-\[320px\]{height:320px}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-\[50vh\]{max-height:50vh}.max-h-\[80vh\]{max-height:80vh}.max-h-\[180px\]{max-height:180px}.max-h-\[320px\]{max-height:320px}.max-h-\[calc\(100vh-96px\)\]{max-height:calc(100vh - 96px)}.min-h-0{min-height:calc(var(--spacing) * 0)}.min-h-\[36px\]{min-height:36px}.min-h-\[160px\]{min-height:160px}.min-h-\[240px\]{min-height:240px}.min-h-\[280px\]{min-height:280px}.min-h-\[720px\]{min-height:720px}.min-h-screen{min-height:100vh}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-4{width:calc(var(--spacing) * 4)}.w-7{width:calc(var(--spacing) * 7)}.w-10{width:calc(var(--spacing) * 10)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-64{width:calc(var(--spacing) * 64)}.w-\[110px\]{width:110px}.w-\[150px\]{width:150px}.w-\[160px\]{width:160px}.w-\[180px\]{width:180px}.w-\[190px\]{width:190px}.w-\[200px\]{width:200px}.w-\[220px\]{width:220px}.w-\[260px\]{width:260px}.w-\[320px\]{width:320px}.w-\[340px\]{width:340px}.w-\[360px\]{width:360px}.w-\[380px\]{width:380px}.w-\[420px\]{width:420px}.w-\[min\(34rem\,90vw\)\]{width:min(34rem,90vw)}.w-\[min\(320px\,48vw\)\]{width:min(320px,48vw)}.w-full{width:100%}.w-px{width:1px}.max-w-2xl{max-width:var(--container-2xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-\[38vw\]{max-width:38vw}.max-w-\[180px\]{max-width:180px}.max-w-\[260px\]{max-width:260px}.max-w-\[280px\]{max-width:280px}.max-w-\[520px\]{max-width:520px}.max-w-\[640px\]{max-width:640px}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-12{min-width:calc(var(--spacing) * 12)}.min-w-\[78px\]{min-width:78px}.min-w-\[92px\]{min-width:92px}.min-w-\[94px\]{min-width:94px}.min-w-\[180px\]{min-width:180px}.min-w-\[220px\]{min-width:220px}.min-w-\[260px\]{min-width:260px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.list-none{list-style-type:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[1fr_1fr_auto_auto\]{grid-template-columns:1fr 1fr auto auto}.grid-cols-\[16px_1fr_auto\]{grid-template-columns:16px 1fr auto}.grid-cols-\[52px_1fr_90px\]{grid-template-columns:52px 1fr 90px}.grid-cols-\[60px_1fr\]{grid-template-columns:60px 1fr}.grid-cols-\[78px_1fr\]{grid-template-columns:78px 1fr}.grid-cols-\[82px_1fr\]{grid-template-columns:82px 1fr}.grid-cols-\[100px_1fr\]{grid-template-columns:100px 1fr}.grid-cols-\[110px_1fr\]{grid-template-columns:110px 1fr}.grid-cols-\[120px_1fr\]{grid-template-columns:120px 1fr}.grid-cols-\[160px_1fr\]{grid-template-columns:160px 1fr}.grid-cols-\[260px_1fr\]{grid-template-columns:260px 1fr}.grid-cols-\[280px_1fr\]{grid-template-columns:280px 1fr}.grid-cols-\[320px_1fr\]{grid-template-columns:320px 1fr}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.grid-cols-\[minmax\(0\,1fr\)_360px\]{grid-template-columns:minmax(0,1fr) 360px}.grid-cols-\[minmax\(160px\,0\.8fr\)_1\.2fr\]{grid-template-columns:minmax(160px,.8fr) 1.2fr}.grid-cols-\[minmax\(280px\,0\.75fr\)_1\.25fr\]{grid-template-columns:minmax(280px,.75fr) 1.25fr}.grid-cols-\[minmax\(320px\,0\.9fr\)_1\.1fr\]{grid-template-columns:minmax(320px,.9fr) 1.1fr}.grid-cols-\[minmax\(360px\,0\.9fr\)_1\.1fr\]{grid-template-columns:minmax(360px,.9fr) 1.1fr}.grid-cols-\[repeat\(auto-fill\,minmax\(180px\,1fr\)\)\]{grid-template-columns:repeat(auto-fill,minmax(180px,1fr))}.grid-cols-\[repeat\(auto-fill\,minmax\(220px\,1fr\)\)\]{grid-template-columns:repeat(auto-fill,minmax(220px,1fr))}.grid-rows-\[44px_32px_1fr\]{grid-template-rows:44px 32px 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.content-start{align-content:flex-start}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-y-0\.5{row-gap:calc(var(--spacing) * .5)}.gap-y-1{row-gap:calc(var(--spacing) * 1)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-line-1>:not(:last-child)){border-color:var(--color-line-1)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-4{border-style:var(--tw-border-style);border-width:4px}.border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent\/30{border-color:#e11d484d}@supports (color:color-mix(in lab,red,red)){.border-accent\/30{border-color:color-mix(in oklab,var(--color-accent) 30%,transparent)}}.border-accent\/35{border-color:#e11d4859}@supports (color:color-mix(in lab,red,red)){.border-accent\/35{border-color:color-mix(in oklab,var(--color-accent) 35%,transparent)}}.border-accent\/40{border-color:#e11d4866}@supports (color:color-mix(in lab,red,red)){.border-accent\/40{border-color:color-mix(in oklab,var(--color-accent) 40%,transparent)}}.border-accent\/60{border-color:#e11d4899}@supports (color:color-mix(in lab,red,red)){.border-accent\/60{border-color:color-mix(in oklab,var(--color-accent) 60%,transparent)}}.border-danger\/30{border-color:#dc26264d}@supports (color:color-mix(in lab,red,red)){.border-danger\/30{border-color:color-mix(in oklab,var(--color-danger) 30%,transparent)}}.border-danger\/40{border-color:#dc262666}@supports (color:color-mix(in lab,red,red)){.border-danger\/40{border-color:color-mix(in oklab,var(--color-danger) 40%,transparent)}}.border-lime-500{border-color:var(--color-lime-500)}.border-line-1{border-color:var(--color-line-1)}.border-line-1\/50{border-color:#ececef80}@supports (color:color-mix(in lab,red,red)){.border-line-1\/50{border-color:color-mix(in oklab,var(--color-line-1) 50%,transparent)}}.border-line-1\/60{border-color:#ececef99}@supports (color:color-mix(in lab,red,red)){.border-line-1\/60{border-color:color-mix(in oklab,var(--color-line-1) 60%,transparent)}}.border-line-2{border-color:var(--color-line-2)}.border-ok\/30{border-color:#16a34a4d}@supports (color:color-mix(in lab,red,red)){.border-ok\/30{border-color:color-mix(in oklab,var(--color-ok) 30%,transparent)}}.border-ok\/40{border-color:#16a34a66}@supports (color:color-mix(in lab,red,red)){.border-ok\/40{border-color:color-mix(in oklab,var(--color-ok) 40%,transparent)}}.border-warn\/30{border-color:#b453094d}@supports (color:color-mix(in lab,red,red)){.border-warn\/30{border-color:color-mix(in oklab,var(--color-warn) 30%,transparent)}}.border-warn\/40{border-color:#b4530966}@supports (color:color-mix(in lab,red,red)){.border-warn\/40{border-color:color-mix(in oklab,var(--color-warn) 40%,transparent)}}.border-zinc-300{border-color:var(--color-zinc-300)}.border-b-accent{border-bottom-color:var(--color-accent)}.bg-accent{background-color:var(--color-accent)}.bg-accent\/5{background-color:#e11d480d}@supports (color:color-mix(in lab,red,red)){.bg-accent\/5{background-color:color-mix(in oklab,var(--color-accent) 5%,transparent)}}.bg-accent\/10{background-color:#e11d481a}@supports (color:color-mix(in lab,red,red)){.bg-accent\/10{background-color:color-mix(in oklab,var(--color-accent) 10%,transparent)}}.bg-accent\/80{background-color:#e11d48cc}@supports (color:color-mix(in lab,red,red)){.bg-accent\/80{background-color:color-mix(in oklab,var(--color-accent) 80%,transparent)}}.bg-bg-0{background-color:var(--color-bg-0)}.bg-bg-0\/70{background-color:#ffffffb3}@supports (color:color-mix(in lab,red,red)){.bg-bg-0\/70{background-color:color-mix(in oklab,var(--color-bg-0) 70%,transparent)}}.bg-bg-1{background-color:var(--color-bg-1)}.bg-bg-1\/20{background-color:#fafafa33}@supports (color:color-mix(in lab,red,red)){.bg-bg-1\/20{background-color:color-mix(in oklab,var(--color-bg-1) 20%,transparent)}}.bg-bg-1\/30{background-color:#fafafa4d}@supports (color:color-mix(in lab,red,red)){.bg-bg-1\/30{background-color:color-mix(in oklab,var(--color-bg-1) 30%,transparent)}}.bg-bg-1\/35{background-color:#fafafa59}@supports (color:color-mix(in lab,red,red)){.bg-bg-1\/35{background-color:color-mix(in oklab,var(--color-bg-1) 35%,transparent)}}.bg-bg-1\/40{background-color:#fafafa66}@supports (color:color-mix(in lab,red,red)){.bg-bg-1\/40{background-color:color-mix(in oklab,var(--color-bg-1) 40%,transparent)}}.bg-bg-1\/60{background-color:#fafafa99}@supports (color:color-mix(in lab,red,red)){.bg-bg-1\/60{background-color:color-mix(in oklab,var(--color-bg-1) 60%,transparent)}}.bg-bg-1\/80{background-color:#fafafacc}@supports (color:color-mix(in lab,red,red)){.bg-bg-1\/80{background-color:color-mix(in oklab,var(--color-bg-1) 80%,transparent)}}.bg-bg-2{background-color:var(--color-bg-2)}.bg-bg-2\/30{background-color:#f4f4f54d}@supports (color:color-mix(in lab,red,red)){.bg-bg-2\/30{background-color:color-mix(in oklab,var(--color-bg-2) 30%,transparent)}}.bg-bg-3{background-color:var(--color-bg-3)}.bg-black\/45{background-color:#00000073}@supports (color:color-mix(in lab,red,red)){.bg-black\/45{background-color:color-mix(in oklab,var(--color-black) 45%,transparent)}}.bg-danger{background-color:var(--color-danger)}.bg-danger\/10{background-color:#dc26261a}@supports (color:color-mix(in lab,red,red)){.bg-danger\/10{background-color:color-mix(in oklab,var(--color-danger) 10%,transparent)}}.bg-fg-3{background-color:var(--color-fg-3)}.bg-line-1{background-color:var(--color-line-1)}.bg-line-2{background-color:var(--color-line-2)}.bg-ok{background-color:var(--color-ok)}.bg-ok\/10{background-color:#16a34a1a}@supports (color:color-mix(in lab,red,red)){.bg-ok\/10{background-color:color-mix(in oklab,var(--color-ok) 10%,transparent)}}.bg-role-embedded{background-color:var(--color-role-embedded)}.bg-role-primary{background-color:var(--color-role-primary)}.bg-role-replica{background-color:var(--color-role-replica)}.bg-transparent{background-color:#0000}.bg-warn\/5{background-color:#b453090d}@supports (color:color-mix(in lab,red,red)){.bg-warn\/5{background-color:color-mix(in oklab,var(--color-warn) 5%,transparent)}}.bg-warn\/10{background-color:#b453091a}@supports (color:color-mix(in lab,red,red)){.bg-warn\/10{background-color:color-mix(in oklab,var(--color-warn) 10%,transparent)}}.bg-warn\/15{background-color:#b4530926}@supports (color:color-mix(in lab,red,red)){.bg-warn\/15{background-color:color-mix(in oklab,var(--color-warn) 15%,transparent)}}.bg-white{background-color:var(--color-white)}.bg-yellow-200{background-color:var(--color-yellow-200)}.fill-bg-1{fill:var(--color-bg-1)}.fill-fg-0{fill:var(--color-fg-0)}.fill-fg-3{fill:var(--color-fg-3)}.p-0{padding:calc(var(--spacing) * 0)}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:calc(var(--spacing) * 1)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-16{padding-block:calc(var(--spacing) * 16)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pr-1\.5{padding-right:calc(var(--spacing) * 1.5)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-2\.5{padding-right:calc(var(--spacing) * 2.5)}.pr-5{padding-right:calc(var(--spacing) * 5)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-2\.5{padding-left:calc(var(--spacing) * 2.5)}.pl-8{padding-left:calc(var(--spacing) * 8)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-top{vertical-align:top}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.font-serif{font-family:var(--font-serif)}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[9px\]{font-size:9px}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[15px\]{font-size:15px}.text-\[18px\]{font-size:18px}.text-\[20px\]{font-size:20px}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.08em\]{--tw-tracking:.08em;letter-spacing:.08em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent{color:var(--color-accent)}.text-black{color:var(--color-black)}.text-danger{color:var(--color-danger)}.text-fg-0{color:var(--color-fg-0)}.text-fg-1{color:var(--color-fg-1)}.text-fg-2{color:var(--color-fg-2)}.text-fg-3{color:var(--color-fg-3)}.text-line-3{color:var(--color-line-3)}.text-ok{color:var(--color-ok)}.text-purple-700{color:var(--color-purple-700)}.text-warn{color:var(--color-warn)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.accent-accent{accent-color:var(--color-accent)}.accent-current{accent-color:currentColor}.opacity-0{opacity:0}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_0_12px_var\(--color-accent-glow\)\]{--tw-shadow:0 0 12px var(--tw-shadow-color,var(--color-accent-glow));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 16px 48px var(--tw-shadow-color,#0f172a24), 0 0 0 1px var(--tw-shadow-color,var(--color-line-2));box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.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-md{--tw-backdrop-blur:blur(var(--blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-fg-3::placeholder{color:var(--color-fg-3)}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media(hover:hover){.hover\:border-accent:hover{border-color:var(--color-accent)}.hover\:border-fg-3:hover{border-color:var(--color-fg-3)}.hover\:border-line-2:hover{border-color:var(--color-line-2)}.hover\:border-line-3:hover{border-color:var(--color-line-3)}.hover\:bg-\[\#ff3868\]:hover{background-color:#ff3868}.hover\:bg-accent\/20:hover{background-color:#e11d4833}@supports (color:color-mix(in lab,red,red)){.hover\:bg-accent\/20:hover{background-color:color-mix(in oklab,var(--color-accent) 20%,transparent)}}.hover\:bg-accent\/90:hover{background-color:#e11d48e6}@supports (color:color-mix(in lab,red,red)){.hover\:bg-accent\/90:hover{background-color:color-mix(in oklab,var(--color-accent) 90%,transparent)}}.hover\:bg-bg-1:hover{background-color:var(--color-bg-1)}.hover\:bg-bg-1\/40:hover{background-color:#fafafa66}@supports (color:color-mix(in lab,red,red)){.hover\:bg-bg-1\/40:hover{background-color:color-mix(in oklab,var(--color-bg-1) 40%,transparent)}}.hover\:bg-bg-1\/50:hover{background-color:#fafafa80}@supports (color:color-mix(in lab,red,red)){.hover\:bg-bg-1\/50:hover{background-color:color-mix(in oklab,var(--color-bg-1) 50%,transparent)}}.hover\:bg-bg-1\/60:hover{background-color:#fafafa99}@supports (color:color-mix(in lab,red,red)){.hover\:bg-bg-1\/60:hover{background-color:color-mix(in oklab,var(--color-bg-1) 60%,transparent)}}.hover\:bg-bg-2:hover{background-color:var(--color-bg-2)}.hover\:bg-bg-2\/40:hover{background-color:#f4f4f566}@supports (color:color-mix(in lab,red,red)){.hover\:bg-bg-2\/40:hover{background-color:color-mix(in oklab,var(--color-bg-2) 40%,transparent)}}.hover\:bg-bg-2\/60:hover{background-color:#f4f4f599}@supports (color:color-mix(in lab,red,red)){.hover\:bg-bg-2\/60:hover{background-color:color-mix(in oklab,var(--color-bg-2) 60%,transparent)}}.hover\:bg-bg-3:hover{background-color:var(--color-bg-3)}.hover\:bg-danger\/20:hover{background-color:#dc262633}@supports (color:color-mix(in lab,red,red)){.hover\:bg-danger\/20:hover{background-color:color-mix(in oklab,var(--color-danger) 20%,transparent)}}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-danger:hover{color:var(--color-danger)}.hover\:text-fg-0:hover{color:var(--color-fg-0)}.hover\:text-fg-1:hover{color:var(--color-fg-1)}}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:border-line-3:focus{border-color:var(--color-line-3)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-accent\/40:focus-visible{--tw-ring-color:#e11d4866}@supports (color:color-mix(in lab,red,red)){.focus-visible\:ring-accent\/40:focus-visible{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:text-fg-3:disabled{color:var(--color-fg-3)}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}@media(prefers-reduced-motion:reduce){.motion-reduce\:backdrop-blur-none{--tw-backdrop-blur: ;-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,)}}@media(min-width:40rem){.sm\:inline{display:inline}}}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-cyrillic-ext-wght-normal.BOeWTOD4.woff2)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-cyrillic-wght-normal.DqGufNeO.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-greek-ext-wght-normal.DlzME5K_.woff2)format("woff2-variations");unicode-range:U+1F??}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-greek-wght-normal.CkhJZR-_.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-vietnamese-wght-normal.CBcvBZtf.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-latin-ext-wght-normal.DO1Apj_S.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./inter-latin-wght-normal.Dx4kXJAl.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(data:font/woff2;base64,d09GMgABAAAAAAfsABQAAAAAEAwAAAeCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhwbHhwoP0hWQVJbBmA/U1RBVIFiJyYAdC9qEQgKhGSEAAsgADCGCAE2AiQDOgQgBYlMB4EUDAcbLQ4onoexrSC/2ZyLAa8p8VHB8/x3Vue+V0hVJalMJg2nx/TCrQXxBeqLjQG7FyM1WEa/X1tEXN7cFz9EJEMmMUz3RihWSSKeQCbcIou0izz/C8v+fq3VfajEa9gDD11CImXS7qL/RJFVzC1qiB6KmKeD6TZdQ6IRGv78dL6uSVVCfgni5mzu7kcgQBgAEAQTQRCoL++STTYybkJxNfQxAAIAGu8OdEB9teW2jh4BpgDqFjAeSEByW3zFP0CBBgNMsMCGEDjgggdhiEAUAeIIED7ABTDUEnkIE9Q9ahFgKttcVhApo4ACB4qobHaccgDfEjFO6aaWUhjMLt2SyIvHKoDqoA4CSUwEIYQCEjhAO9R1G6keDeDZGjNo+AhxOjCEGTr1WeIF3kYBiLAOKvkJSMiKX0VdAyQt3SDJClCkxJCHkCzfqyVTriJZLcolS32JZHUekq2TYNkYtCtjYHMQXSxGjXDz2t/yLWXzDzxz+o3zFwDEaN23F+13pyMdQAEaSKAR9vcGq4A4MTSKCElGW+M7UcY7xqkggITb28ZJhlqc9q2twYKTt0NjixBgYvO9BIihEBLYuOFXQzfIQ7dXGUEEEgFDooBfAzqiQbpJrhiWSuKJCRFKYbHCyJKI2G5GiZbNAvgAu5pc3vwx4G+g3aDkhklABiSz0BICXrYghtYhx/cdJ+44rY2oZ0aMNRFz3VZjb6W33F3gzltqtOCV8tTHSpOeXuItfvr5lCdfzFpqtEitvqdcdGGFd28ZqqC0tPbeChGXgrIlnhSWu/eUso4uKWFLugyDzQJhflY4659+WjQ++6x72WUMv9G8mw6QJl7BVxX5fe/kpUsOvnZwee9uQ0cGXYd0o89XB2748sDSnt8d2VphdOTTgceDVvOds0v9P/s7HPq15aGun/6Vllb56f1dl0t1LejqrNkpdRZsG8TOnM5vkBG5oiVyVGnS8LHps5cfNWJs6qKPfaNSxiQNBUm3cKNWROr0GSur7Za31k1vieq7LH11VF+jXdRIasRKflc7jkobm1Z9te1IyZA0pDkhLR98+H37Zf1c/8at+dB7x+7GfVyTfJMPiYztsnl59Y5l4j+0n1RXlpHnF3Tq7HecmNF/CJodEMAikruxiyJaGLvHOdAfoA+oDvpjBm2b91cHGRZMU9n25xEU0A8fgEEAdKI3Q1iDtc034sug5YVMkE2jsE+BIkwSoQ3gxXMqz9tELp48bd0cFKOKS7xYjEuXBnZP5ia7DyiO/X/YI+PQSbt2uSdqAkWL9nQbV1XB94/+uPfdZz8dnXYFBYrcTl2SIR/ybxJNJPz/Gupb0JaZeens2ekC7EKr8t+Ls/P5VJPYJdHKyqfg2nqU6bhlidzcddQV/7MmecTzJ5VPcKXkNKSEogHjYFx6QZ7rQ+FSe8njaiNuOnXS8H2ScQ619c2mC3VTtauL0rRbXd/CkSOP37FY9Zkjz8+GibYUMOEWF+RdrFS8Ecv1SHOpPUPZGEIpjPvFyU5cXKjd6OXqorTqy9GwRd++HVufPGnVsW+aO3vggKZ18jR9sXaTC1PWTEsVUaK0FkNySbTQDqlm2PfDjZcu4aalnSLKjnOoYQ0nUlqqXcGpPu/4VgV/xU2pAqW4BW3qzhQ8/hFKhV2qE3+BKAtDqBXjfgnVdH4y0wg5tbVNRenNdTWOrenWLcupQdmsbq5b+18piTe/xRdp1xbILxNPJGInm2z6hoB21Lal0i+ePTtd7B45+3XhFJ329evskXm7qurUVREotqSluSo/L29d3qDhI4YOQqWhI4YNvBNfsMHeXKemXrxQfKeuPOGRVayA3JtkJKEgbPp+dXUDluddutRYLFoXGXWX6N3WFaGLbQtRSitVYNacTNSdy7AaG/HSaUEANcBoGXNdcZvZsOqQ1icBDv21/gzAoYPHH/WDW0qNR3QTYKEAEHig6o13NXbND06CQPlRtYjGNnSktRc09k1mAMDvAlDKfQjgy6fssInlfzmNAjKkDxoxHOBLdVRAIVt9j4qo+hA1w9T1aNBNTUOTTNUHLbqokE+UAfJXCIGw/IxCSL5GRUJeR40rL/UxTm4Q08H6MbCs70ObuNyIIXrINHQYInF06UUlevTjbQzTh5upiDMzMMogUtEnjPs/Y7jAHCJeB0GBHh04tC6FiB6ZFB1oArUSIoFoqhzCeAN6lHwm0T4C3VVPWvjpSMXReuWesMEcoqrmgtNBGd2noWeV0hNAz9rFeShNJxHGsPa3HXeKTk8b55hahySYHaYKKFFLpCfN8rsoaJn01CR04Gkc+5k7KVTCmClX8Q10HCrUEkVlSX+XO33oQR9609tJ516H497WSobWs5Up6TLaS10/dessIskgJSLiDlWvHVUywpkQ7hdPZqGyiEF0uVQerVcPamT1A3eKXdyI1vG9OoflrSXihZ1qqGE3nhmAgiIbRCQgPLEPtOM3UQwTLYaYYomNlpA44opnjV6jkD6id80OOrzf6BzmMD6eEa1zKyeYG1fzfEf16V6jw9XYOaar1/b2kP/IYX8oR2mcFvv2GtBV3JXgd437AQAA)format("woff2-variations");unicode-range:U+460-52F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(./jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2)format("woff2-variations");unicode-range:U+301,U+400-45F,U+490-491,U+4B0-4B1,U+2116}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(./jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2)format("woff2-variations");unicode-range:U+370-377,U+37A-37F,U+384-38A,U+38C,U+38E-3A1,U+3A3-3FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(./jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2)format("woff2-variations");unicode-range:U+102-103,U+110-111,U+128-129,U+168-169,U+1A0-1A1,U+1AF-1B0,U+300-301,U+303-304,U+308-309,U+323,U+329,U+1EA0-1EF9,U+20AB}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(./jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(./jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root[data-theme=dark]{--color-bg-0:#050607;--color-bg-1:#0d0f13;--color-bg-2:#181b21;--color-bg-3:#232730;--color-fg-0:#f7f8fa;--color-fg-1:#c8ccd4;--color-fg-2:#9ca1a9;--color-fg-3:#7a7f87;--color-line-1:#181b21;--color-line-2:#2a2e36;--color-line-3:#3d424b;--color-accent:#ff2056;--color-accent-soft:#ff20561f;--color-accent-glow:#ff205673;--color-ok:#4ade80;--color-warn:#fbbf24;--color-danger:#ff5470;--color-info:#60a5fa;--color-role-primary:#ff2056;--color-role-replica:#60a5fa;--color-role-embedded:#4ade80;--color-ambient-glow:#ff20560f;--shadow-md:0 4px 12px #0006, 0 0 0 1px var(--color-line-2);--shadow-lg:0 16px 48px #0009, 0 0 0 1px var(--color-line-2)}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}