From ff66e1871acdbf08700c7a0d28bd87a57dcbf772 Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Wed, 27 Aug 2025 14:37:42 +0300 Subject: [PATCH 01/24] readme --- doc/deployment.md | 216 +++++++++++++++++++++++++--------------------- 1 file changed, 119 insertions(+), 97 deletions(-) diff --git a/doc/deployment.md b/doc/deployment.md index ca1f4c16..5b22d73a 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -11,46 +11,62 @@ just certs just gen-curve ``` -- If you intend to public face Bridge, properly obtain certificates from a trusted authority + + > [!TIP] + > If you intend to deploy Bridge publicly, properly obtain certificates from a trusted authority. 3. Copy or rename the provided configuration files: - `config/configurations_sample.toml` → `config/configurations.toml` - `config/database_sample.toml` → `config/database.toml` +4. Adjust the relevant variables: + + `configurations.toml` + + - `redirect_url` → Set to their localhost versions (commented out) + - `client_id` / `client_secret` → ?? + + `database.toml` + + - AAA + ### Running Bridge locally -1. Start a local DB instances +1. Start a local DB instance - Ensure you have Podman installed on your local machine. If you prefer Docker, updated "podman" commands to "docker" commands + > **Docker Support:** Ensure you have Podman installed and running on your local machine. If you prefer Docker, updated "podman" commands to "docker" commands in the [justfile](../justfile). + + > **Apple Silicon Support:** Recent Apple devices should run `just local-mongo-arm` instead. ```shell just local-mongo ``` - Optionally you can start a cache instance +2. Optionally you can start a cache instance ```shell just local-keydb ``` -2. Start the Bridge server +3. Start the Bridge server ```shell - cargo run --feature=full --release + cargo run --features=full --release ``` - The release flag will enable all optimizations and compilation will take a longer time - - Look in the Cargo.toml for the available feature flags + The `--release` flag will enable all optimizations and compilation will take a longer time. + Refer to [Cargo.toml](../Cargo.toml) for the available feature flags + +4. See the result at [localhost:8080](https://localhost:8080) (HTTPS required) -3. See the result at [localhost:8080](https://localhost:8080) +
### Destroying Bridge running locally 1. Stop the Bridge server - Press `Ctrl + C` in the terminal where the server is running or send a sigterm. + Simply press `Ctrl` + `C` in the terminal where the server is running or send a sigterm. 2. Stop the local DB instances @@ -64,13 +80,17 @@ cargo clean ``` +
+ ### Deployment to Kubernetes / Openshift + > [!NOTE] > This is one possible way to deploy and it is not a hard requirement. 1. Build the Bridge container image Check what features you want to enable for your deployment + ```shell just build-full ``` @@ -78,91 +98,93 @@ 2. Tag and push the image to your choice of Image repository 3. Apply this service as a deployment - - Ensure you give it the proper permission to access various namespaces and create CRDs - - The following was generated with Helm - ```yaml - kind: Deployment - metadata: - annotations: - deployment.kubernetes.io/revision: "39" - meta.helm.sh/release-name: bridge-openad - meta.helm.sh/release-namespace: openbridge - creationTimestamp: "2025-05-15T03:42:42Z" - generation: 39 - labels: - app.kubernetes.io/instance: bridge-openad - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: bridge-openad - app.kubernetes.io/version: 1.16.0 - helm.sh/chart: bridge-openad-0.1.0 - name: bridge-openad - namespace: bridge - resourceVersion: "" - uid: "" - spec: - progressDeadlineSeconds: 600 - replicas: 1 - revisionHistoryLimit: 10 - selector: - matchLabels: - app.kubernetes.io/instance: bridge-openad - app.kubernetes.io/name: bridge-openad - strategy: - rollingUpdate: - maxSurge: 25% - maxUnavailable: 25% - type: RollingUpdate - template: + + - Ensure you give it the proper permission to access various namespaces and create CRDs + - The following was generated with Helm: + + ```yaml + kind: Deployment metadata: - annotations: - kubectl.kubernetes.io/restartedAt: "2025-07-04T22:24:19-04:00" - creationTimestamp: null - labels: - app.kubernetes.io/instance: bridge-openad - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: bridge-openad - app.kubernetes.io/version: 1.16.0 - helm.sh/chart: bridge-openad-0.1.0 - spec: - containers: - - image: xxx.amazonaws.com/bridge/openad:v0.0.1 - imagePullPolicy: Always - livenessProbe: - failureThreshold: 3 - httpGet: - path: /health - port: 8080 - scheme: HTTPS - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 + annotations: + deployment.kubernetes.io/revision: "39" + meta.helm.sh/release-name: bridge-openad + meta.helm.sh/release-namespace: openbridge + creationTimestamp: "2025-05-15T03:42:42Z" + generation: 39 + labels: + app.kubernetes.io/instance: bridge-openad + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: bridge-openad + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: bridge-openad-0.1.0 name: bridge-openad - ports: - - containerPort: 8080 - name: http - protocol: TCP - readinessProbe: - failureThreshold: 3 - httpGet: - path: /health - port: 8080 - scheme: HTTPS - periodSeconds: 10 - successThreshold: 1 - timeoutSeconds: 1 - resources: - requests: - cpu: 100m - memory: 1Gi - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - dnsPolicy: ClusterFirst - imagePullSecrets: - - name: ecr-registry-openad - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - serviceAccount: bridge-openad - serviceAccountName: bridge-openad - terminationGracePeriodSeconds: 30 - ``` + namespace: bridge + resourceVersion: "" + uid: "" + spec: + progressDeadlineSeconds: 600 + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app.kubernetes.io/instance: bridge-openad + app.kubernetes.io/name: bridge-openad + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + annotations: + kubectl.kubernetes.io/restartedAt: "2025-07-04T22:24:19-04:00" + creationTimestamp: null + labels: + app.kubernetes.io/instance: bridge-openad + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: bridge-openad + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: bridge-openad-0.1.0 + spec: + containers: + - image: xxx.amazonaws.com/bridge/openad:v0.0.1 + imagePullPolicy: Always + livenessProbe: + failureThreshold: 3 + httpGet: + path: /health + port: 8080 + scheme: HTTPS + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + name: bridge-openad + ports: + - containerPort: 8080 + name: http + protocol: TCP + readinessProbe: + failureThreshold: 3 + httpGet: + path: /health + port: 8080 + scheme: HTTPS + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + resources: + requests: + cpu: 100m + memory: 1Gi + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + imagePullSecrets: + - name: ecr-registry-openad + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + serviceAccount: bridge-openad + serviceAccountName: bridge-openad + terminationGracePeriodSeconds: 30 + ``` From a51d61e4b4badc3462ddd1d1b081000217b5cef3 Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Wed, 27 Aug 2025 15:11:18 +0300 Subject: [PATCH 02/24] readme --- doc/deployment.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/doc/deployment.md b/doc/deployment.md index 5b22d73a..e5090dee 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -20,14 +20,14 @@ - `config/configurations_sample.toml` → `config/configurations.toml` - `config/database_sample.toml` → `config/database.toml` -4. Adjust the relevant variables: +4. Update the relevant variables: - `configurations.toml` + **configurations.toml** - `redirect_url` → Set to their localhost versions (commented out) - `client_id` / `client_secret` → ?? - `database.toml` + **database.toml** - AAA @@ -35,14 +35,23 @@ 1. Start a local DB instance - > **Docker Support:** Ensure you have Podman installed and running on your local machine. If you prefer Docker, updated "podman" commands to "docker" commands in the [justfile](../justfile). - - > **Apple Silicon Support:** Recent Apple devices should run `just local-mongo-arm` instead. - ```shell just local-mongo ``` + > **Docker Support:** Ensure you have Podman installed and running on your local machine. If you prefer Docker, updated "podman" commands to "docker" commands in the [justfile](../justfile). + + > [!NOTE] + > Recent Apple devices should use the ARM install command instead, and remove the auth from the mongodb url in `database.toml`: + > + > ``` + > just local-mongo-arm + > ``` + > + > ``` + > url = "mongodb://127.0.0.1:27017/bridge" + > ``` + 2. Optionally you can start a cache instance ```shell From 9c3cd792ef3d65a177112a5bc3e45803720e9aa7 Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Wed, 27 Aug 2025 15:12:20 +0300 Subject: [PATCH 03/24] readme --- doc/deployment.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/deployment.md b/doc/deployment.md index e5090dee..fc2293c5 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -39,8 +39,6 @@ just local-mongo ``` - > **Docker Support:** Ensure you have Podman installed and running on your local machine. If you prefer Docker, updated "podman" commands to "docker" commands in the [justfile](../justfile). - > [!NOTE] > Recent Apple devices should use the ARM install command instead, and remove the auth from the mongodb url in `database.toml`: > @@ -52,6 +50,8 @@ > url = "mongodb://127.0.0.1:27017/bridge" > ``` + + 2. Optionally you can start a cache instance ```shell From 0b06a42f02901f2552a5011d6f44b868cfbcdaaf Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Wed, 27 Aug 2025 15:12:49 +0300 Subject: [PATCH 04/24] readme --- doc/deployment.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/deployment.md b/doc/deployment.md index fc2293c5..d5f9cccb 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -41,14 +41,15 @@ > [!NOTE] > Recent Apple devices should use the ARM install command instead, and remove the auth from the mongodb url in `database.toml`: - > - > ``` + > A + + From b2ab0aeb8a222f8c0a354d6a79f1d56690a82c82 Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Wed, 27 Aug 2025 15:13:16 +0300 Subject: [PATCH 05/24] readme --- doc/deployment.md | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/doc/deployment.md b/doc/deployment.md index d5f9cccb..7c3ac6bb 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -39,19 +39,18 @@ just local-mongo ``` - > [!NOTE] - > Recent Apple devices should use the ARM install command instead, and remove the auth from the mongodb url in `database.toml`: - > A - - - - + > **Docker Support:** Ensure you have Podman installed and running on your local machine. If you prefer Docker, updated "podman" commands to "docker" commands in the [justfile](../justfile). + +> [!NOTE] +> Recent Apple devices should use the ARM install command instead, and remove the auth from the mongodb url in `database.toml`: +> +> ``` +> just local-mongo-arm +> ``` +> +> ``` +> url = "mongodb://127.0.0.1:27017/bridge" +> ``` 2. Optionally you can start a cache instance From 9f68040a282b653e7811d0baa10acfdef367d37a Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Wed, 27 Aug 2025 15:18:49 +0300 Subject: [PATCH 06/24] readme --- config/database_sample.toml | 6 ++++++ doc/deployment.md | 38 +++++++++++++++++++++---------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/config/database_sample.toml b/config/database_sample.toml index 85a2f502..9f72b28d 100644 --- a/config/database_sample.toml +++ b/config/database_sample.toml @@ -2,6 +2,12 @@ url = "mongodb://bridge-user:admin123456789@127.0.0.1:27017/?authSource=bridge" url_local = "mongodb://bridge-user:admin123456789@127.0.0.1:27017/?authSource=bridge" url_prod = "mongodb://bridge-user:admin123456789@127.0.0.1:27017/?authSource=bridge" + + # Apple Silicon: + # url = "mongodb://127.0.0.1:27017/bridge" + # url_local = "mongodb://127.0.0.1:27017/bridge" + # url_prod = "mongodb://127.0.0.1:27017/bridge" + name = "bridge" [keydb] diff --git a/doc/deployment.md b/doc/deployment.md index 7c3ac6bb..52dbb8b9 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -12,8 +12,8 @@ just gen-curve ``` - > [!TIP] - > If you intend to deploy Bridge publicly, properly obtain certificates from a trusted authority. +> [!TIP] +> If you intend to deploy Bridge publicly, properly obtain certificates from a trusted authority. 3. Copy or rename the provided configuration files: @@ -39,26 +39,32 @@ just local-mongo ``` + > **Apple Silicon Support:** Use the ARM install instead, and set the DB urls in `database.toml` without auth: `url="mongodb://127.0.0.1:27017/bridge"` + > + > ``` + > just local-mongo-arm + > ``` + > **Docker Support:** Ensure you have Podman installed and running on your local machine. If you prefer Docker, updated "podman" commands to "docker" commands in the [justfile](../justfile). -> [!NOTE] -> Recent Apple devices should use the ARM install command instead, and remove the auth from the mongodb url in `database.toml`: -> -> ``` -> just local-mongo-arm -> ``` -> -> ``` -> url = "mongodb://127.0.0.1:27017/bridge" -> ``` - -2. Optionally you can start a cache instance +[!NOTE] +Recent Apple devices should use the ARM install command instead, and remove the auth from the mongodb url in `database.toml`: + +``` +just local-mongo-arm +``` + +``` +url = "mongodb://127.0.0.1:27017/bridge" +``` + +1. Optionally you can start a cache instance ```shell just local-keydb ``` -3. Start the Bridge server +2. Start the Bridge server ```shell cargo run --features=full --release @@ -67,7 +73,7 @@ The `--release` flag will enable all optimizations and compilation will take a longer time. Refer to [Cargo.toml](../Cargo.toml) for the available feature flags -4. See the result at [localhost:8080](https://localhost:8080) (HTTPS required) +3. See the result at [localhost:8080](https://localhost:8080) (HTTPS required)
From e740416c3b3efa2d02286f15e2130b05ef17ad1c Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Wed, 27 Aug 2025 15:19:27 +0300 Subject: [PATCH 07/24] readme --- doc/deployment.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/deployment.md b/doc/deployment.md index 52dbb8b9..4d6293ed 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -12,8 +12,7 @@ just gen-curve ``` -> [!TIP] -> If you intend to deploy Bridge publicly, properly obtain certificates from a trusted authority. + > **Note:** If you intend to deploy Bridge publicly, properly obtain certificates from a trusted authority. 3. Copy or rename the provided configuration files: From 8d9e5a793ba1a5455f693b4940db5c3128f92383 Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Wed, 27 Aug 2025 15:25:50 +0300 Subject: [PATCH 08/24] readme --- doc/deployment.md | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/doc/deployment.md b/doc/deployment.md index 4d6293ed..fe5fa102 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -23,17 +23,22 @@ **configurations.toml** - - `redirect_url` → Set to their localhost versions (commented out) - - `client_id` / `client_secret` → ?? + - `redirect_url`: Set to their localhost versions (commented out) + - `client_id` / `client_secret`: ?? **database.toml** - - AAA + - `sub` / `email`: Set to your IBM ID's email + - `[mongodb]`: Use the urls without auth if you're using an Apple Silicon device (M1/M2/M3 etc.) + +
### Running Bridge locally 1. Start a local DB instance + Ensure you have Podman installed and running on your local machine. + ```shell just local-mongo ``` @@ -44,26 +49,15 @@ > just local-mongo-arm > ``` - > **Docker Support:** Ensure you have Podman installed and running on your local machine. If you prefer Docker, updated "podman" commands to "docker" commands in the [justfile](../justfile). - -[!NOTE] -Recent Apple devices should use the ARM install command instead, and remove the auth from the mongodb url in `database.toml`: - -``` -just local-mongo-arm -``` - -``` -url = "mongodb://127.0.0.1:27017/bridge" -``` + > **Docker Support:** If you prefer Docker, updated "podman" commands to "docker" commands in the [justfile](../justfile). -1. Optionally you can start a cache instance +2. Optionally you can start a cache instance ```shell just local-keydb ``` -2. Start the Bridge server +3. Start the Bridge server ```shell cargo run --features=full --release @@ -72,7 +66,7 @@ url = "mongodb://127.0.0.1:27017/bridge" The `--release` flag will enable all optimizations and compilation will take a longer time. Refer to [Cargo.toml](../Cargo.toml) for the available feature flags -3. See the result at [localhost:8080](https://localhost:8080) (HTTPS required) +4. See the result at [localhost:8080](https://localhost:8080) (HTTPS required)
From 1588ce12c3a7270b0e787fe59cee924c972a0593 Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Wed, 27 Aug 2025 17:35:17 +0300 Subject: [PATCH 09/24] readme --- doc/deployment.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/deployment.md b/doc/deployment.md index fe5fa102..ef694856 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -28,8 +28,7 @@ **database.toml** - - `sub` / `email`: Set to your IBM ID's email - - `[mongodb]`: Use the urls without auth if you're using an Apple Silicon device (M1/M2/M3 etc.) + - `[mongodb]`: Use the urls without auth (commented out) if you're using an Apple Silicon device (M1/M2/M3 etc.)
From 7e9514b0b7b3a2fd61f2e0316479ec626959f0cb Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Wed, 27 Aug 2025 17:40:42 +0300 Subject: [PATCH 10/24] readme --- doc/deployment.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/deployment.md b/doc/deployment.md index ef694856..6cbe8c63 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -24,7 +24,8 @@ **configurations.toml** - `redirect_url`: Set to their localhost versions (commented out) - - `client_id` / `client_secret`: ?? + - `client_id` / `client_secret`: If you're with IBM, you can find instructions on how to generate these [here](https://github.com/acceleratedscience/configurations/tree/main/bridge/prod). + If you're developing your own application, you will need to register it with [IBM ID](https://www.ibm.com/docs/en/controller/11.0.1?topic=authentication-ibmid-registration) to use the IBM ID authentication. For now, no other auth methods are supported (PRs welcome) **database.toml** From b1b06a467b43457344feb3e1da75cdd80755cc02 Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Wed, 27 Aug 2025 18:01:07 +0300 Subject: [PATCH 11/24] readme --- doc/deployment.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/deployment.md b/doc/deployment.md index 6cbe8c63..8dd706c8 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -25,7 +25,7 @@ - `redirect_url`: Set to their localhost versions (commented out) - `client_id` / `client_secret`: If you're with IBM, you can find instructions on how to generate these [here](https://github.com/acceleratedscience/configurations/tree/main/bridge/prod). - If you're developing your own application, you will need to register it with [IBM ID](https://www.ibm.com/docs/en/controller/11.0.1?topic=authentication-ibmid-registration) to use the IBM ID authentication. For now, no other auth methods are supported (PRs welcome) + If you're developing your own application, you will need to register it with IBM ID to use the IBM ID authentication. For now, no other auth methods are supported (PRs welcome) **database.toml** From 168ba06ce364529644b79386ce7d6aa57d966d17 Mon Sep 17 00:00:00 2001 From: Moenen Erbuer Date: Fri, 29 Aug 2025 17:23:17 +0300 Subject: [PATCH 12/24] Reworked homepage (profile + subscriptions) layout --- doc/deployment.md | 13 + justfile | 6 +- package-lock.json | 1150 +++++++++++++++++ package.json | 29 + src/config/mod.rs | 14 +- src/web/route/portal/group_admin/mod.rs | 15 +- src/web/route/portal/profile_htmx.rs | 16 +- src/web/route/portal/system_admin/mod.rs | 48 +- src/web/route/portal/token.rs | 1 + src/web/route/portal/user_htmx.rs | 15 +- src/web/route/proxy/services.rs | 4 +- static/css/carbon-bridge.css | 7 + static/css/carbon-skin.css | 338 +++++ static/css/input.css | 63 +- static/css/output.css | 4 +- templates/base.html | 2 + templates/components/code_block.html | 5 + templates/components/group_create.html | 4 +- templates/components/group_edit.html | 4 +- templates/components/group_view.html | 4 +- templates/components/member_add.html | 2 +- templates/components/member_manage.html | 2 +- templates/components/member_view.html | 4 +- templates/components/members.html | 12 +- templates/components/notebook/notebook.html | 4 +- templates/components/owui/owui.html | 4 +- templates/components/profile.html | 68 +- .../components/subscription_details.html | 18 + templates/components/systems.html | 4 +- templates/components/systems_group.html | 24 +- templates/components/systems_user.html | 2 +- templates/components/token.html | 80 +- templates/components/user_edit.html | 4 +- templates/foundation.html | 4 +- templates/pages/nav_base.html | 48 +- 35 files changed, 1843 insertions(+), 179 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 static/css/carbon-bridge.css create mode 100644 static/css/carbon-skin.css create mode 100644 templates/components/code_block.html create mode 100644 templates/components/subscription_details.html diff --git a/doc/deployment.md b/doc/deployment.md index 8dd706c8..11dc2391 100644 --- a/doc/deployment.md +++ b/doc/deployment.md @@ -66,6 +66,19 @@ The `--release` flag will enable all optimizations and compilation will take a longer time. Refer to [Cargo.toml](../Cargo.toml) for the available feature flags + > **Development:** + > To have the server restart on change, use cargo-watch: + > + > ``` + > cargo install cargo-watch + > ``` + > + > ``` + > cargo watch -x 'run --features=full --release' + > ``` + > + > **Note:** Be patient as the initial build may take multiple minutes. + 4. See the result at [localhost:8080](https://localhost:8080) (HTTPS required)
diff --git a/justfile b/justfile index a88970e4..3126121d 100644 --- a/justfile +++ b/justfile @@ -76,9 +76,9 @@ mini-js: uglifyjs ./static/js/main.js -o ./static/js/main.js -c -m build-front: - tailwindcss -i ./static/css/input.css -o ./static/css/output.css --minify - tsc - uglifyjs ./static/js/main.js -o ./static/js/main.js -c -m + npx tailwindcss -i ./static/css/input.css -o ./static/css/output.css --minify + npx tsc + npx uglifyjs ./static/js/main.js -o ./static/js/main.js -c -m # --- Local Development Services --- local-mongo: diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..5793c229 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1150 @@ +{ + "name": "bridge", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@tailwindcss/cli": "^4.1.12", + "tailwindcss": "^4.1.12", + "uglify-js": "^3.19.3" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/cli": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.12.tgz", + "integrity": "sha512-2PyJ5MGh/6JPS+cEaAq6MGDx3UemkX/mJt+/phm7/VOpycpecwNnHuFZbbgx6TNK/aIjvFOhhTVlappM7tmqvQ==", + "license": "MIT", + "dependencies": { + "@parcel/watcher": "^2.5.1", + "@tailwindcss/node": "4.1.12", + "@tailwindcss/oxide": "4.1.12", + "enhanced-resolve": "^5.18.3", + "mri": "^1.2.0", + "picocolors": "^1.1.1", + "tailwindcss": "4.1.12" + }, + "bin": { + "tailwindcss": "dist/index.mjs" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.12.tgz", + "integrity": "sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.5.1", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.12" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.12.tgz", + "integrity": "sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.12", + "@tailwindcss/oxide-darwin-arm64": "4.1.12", + "@tailwindcss/oxide-darwin-x64": "4.1.12", + "@tailwindcss/oxide-freebsd-x64": "4.1.12", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.12", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.12", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.12", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.12", + "@tailwindcss/oxide-linux-x64-musl": "4.1.12", + "@tailwindcss/oxide-wasm32-wasi": "4.1.12", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.12", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.12" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.12.tgz", + "integrity": "sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.12.tgz", + "integrity": "sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.12.tgz", + "integrity": "sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.12.tgz", + "integrity": "sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.12.tgz", + "integrity": "sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.12.tgz", + "integrity": "sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.12.tgz", + "integrity": "sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.12.tgz", + "integrity": "sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.12.tgz", + "integrity": "sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.12.tgz", + "integrity": "sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.5", + "@emnapi/runtime": "^1.4.5", + "@emnapi/wasi-threads": "^1.0.4", + "@napi-rs/wasm-runtime": "^0.2.12", + "@tybys/wasm-util": "^0.10.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.12.tgz", + "integrity": "sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.12.tgz", + "integrity": "sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide/node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/magic-string": { + "version": "0.30.18", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", + "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", + "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz", + "integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "license": "BSD-2-Clause", + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..f2b749db --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "dependencies": { + "@tailwindcss/cli": "^4.1.12", + "tailwindcss": "^4.1.12", + "uglify-js": "^3.19.3" + }, + "name": "bridge", + "version": "1.0.0", + "description": "
", + "main": "index.js", + "directories": { + "doc": "doc" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/acceleratedscience/openbridge.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/acceleratedscience/openbridge/issues" + }, + "homepage": "https://github.com/acceleratedscience/openbridge#readme" +} diff --git a/src/config/mod.rs b/src/config/mod.rs index f326a71a..082ef763 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -137,14 +137,10 @@ pub fn init_once() -> Configuration { validation.set_audience(&AUD); validation.leeway = 0; - let (config_location_str, database_location_str) = if cfg!(debug_assertions) { - ( - "config/configurations_sample.toml", - "config/database_sample.toml", - ) - } else { - ("config/configurations.toml", "config/database.toml") - }; + let (config_location_str, database_location_str) = ( + "config/configurations.toml", + "config/database.toml", + ); let conf_table: toml::Table = toml::from_str(&read_to_string(PathBuf::from_str(config_location_str).unwrap()).unwrap()) @@ -281,7 +277,7 @@ mod tests { ); } - assert_eq!(config.app_name, "Open Accelerated Discovery"); + assert_eq!(config.app_name, "OpenAD"); } #[test] diff --git a/src/web/route/portal/group_admin/mod.rs b/src/web/route/portal/group_admin/mod.rs index 06f690fc..857c7c10 100644 --- a/src/web/route/portal/group_admin/mod.rs +++ b/src/web/route/portal/group_admin/mod.rs @@ -97,12 +97,25 @@ pub(super) async fn group( Err(_) => (vec![], "".to_string(), "".to_string(), "".to_string()), }; + // Placeholder: need to fetch subscription parameters from services.toml + let subs_expanded: Vec = subs + .iter() + .map(|service_name| { + serde_json::json!({ + "type": "openad_model", + "url": "https://dummy.url", + "name": service_name, + "nickname": &service_name.strip_prefix("mcp-").unwrap_or(service_name)[0..4], + }) + }) + .collect(); + let mut ctx = (**context).clone(); ctx.insert("name", &user.user_name); ctx.insert("user_type", &user.user_type); ctx.insert("email", &user.email); ctx.insert("group", &user.groups); - ctx.insert("subscriptions", &subs); + ctx.insert("subscriptions", &subs_expanded); ctx.insert("group_created_at", &group_created_at); ctx.insert("group_updated_at", &group_updated_at); ctx.insert("group_last_updated", &group_last_updated); diff --git a/src/web/route/portal/profile_htmx.rs b/src/web/route/portal/profile_htmx.rs index dbf92792..a01fa92c 100644 --- a/src/web/route/portal/profile_htmx.rs +++ b/src/web/route/portal/profile_htmx.rs @@ -31,8 +31,22 @@ impl Profile { pub fn render(&self, tera: Data) -> Result { let mut context = tera::Context::new(); + + // Placeholder: need to fetch subscription parameters from services.toml + let subs_expanded: Vec = self.subscriptions + .iter() + .map(|service_name| { + serde_json::json!({ + "type": "openad_model", + "url": "https://dummy.url", + "name": service_name, + "nickname": &service_name.strip_prefix("mcp-").unwrap_or(service_name)[0..4], + }) + }) + .collect(); + context.insert("group", &self.groups.join(", ")); - context.insert("subscriptions", &self.subscriptions); + context.insert("subscriptions", &subs_expanded); context.insert("name", &self.name); Ok(tera.render(PROFILE, &context)?) diff --git a/src/web/route/portal/system_admin/mod.rs b/src/web/route/portal/system_admin/mod.rs index 5be97483..28dc47c0 100644 --- a/src/web/route/portal/system_admin/mod.rs +++ b/src/web/route/portal/system_admin/mod.rs @@ -99,12 +99,58 @@ pub(super) async fn system( Err(_) => (vec![], "".to_string(), "".to_string(), "".to_string()), }; + // // Expand subs into objects with service details + // let expanded_subs_1: Vec = subs + // .iter() + // .map(|service_name| { + // match CATALOG.get_service(service_name) { + // Ok(service_details) => { + // serde_json::json!({ + // "service_details": service_details, + // }) + // } + // Err(_) => { + // serde_json::json!({ + // "service_name": service_name, + // }) + // } + // } + // }) + // .collect(); + + // @placeholder: need to fetch subscription parameters from services.toml + let subs_expanded: Vec = subs + .iter() + .enumerate() + .map(|(i, service_name)| { + if i % 2 == 1 { + serde_json::json!({ + "type": "mcp", + "url": "https://dummy.url", + "name": service_name, + "code": format!("http://openad.accelerate.science/mcp/{}/mcp", service_name) + }) + } else { + serde_json::json!({ + "type": "openad_model", + "url": "https://dummy.url", + "name": service_name, + "code": format!( + "catalog model service from remote 'https://open.accelerate.science/proxy' as {} using (auth_group=default inference-service={})", + "foobar", + service_name + ) + }) + } + }) + .collect(); + let mut ctx = (**context).clone(); ctx.insert("name", &user.user_name); ctx.insert("user_type", &user.user_type); ctx.insert("email", &user.email); ctx.insert("group", &user.groups); - ctx.insert("subscriptions", &subs); + ctx.insert("subscriptions", &subs_expanded); ctx.insert("group_created_at", &group_created_at); ctx.insert("group_updated_at", &group_updated_at); ctx.insert("group_last_updated", &group_last_updated); diff --git a/src/web/route/portal/token.rs b/src/web/route/portal/token.rs index 3d5e1a97..63485e48 100644 --- a/src/web/route/portal/token.rs +++ b/src/web/route/portal/token.rs @@ -103,6 +103,7 @@ pub async fn get_token_for_user( let mut context = tera::Context::new(); context.insert("token", &Some(token)); + context.insert("fresh", &true); context.insert("token_exp", &exp); let content = helper::log_with_level!(data.render("components/token.html", &context), error)?; diff --git a/src/web/route/portal/user_htmx.rs b/src/web/route/portal/user_htmx.rs index add6b2f6..cfbd600c 100644 --- a/src/web/route/portal/user_htmx.rs +++ b/src/web/route/portal/user_htmx.rs @@ -57,10 +57,23 @@ impl<'p> Profile<'p> { return Ok((tera.render(EMPTY_PROFILE, &context)?, None)); } + // Placeholder: need to fetch subscription parameters from services.toml + let subs_expanded: Vec = self.subscriptions + .iter() + .map(|service_name| { + serde_json::json!({ + "type": "openad_model", + "url": "https://dummy.url", + "name": service_name, + "nickname": &service_name.strip_prefix("mcp-").unwrap_or(service_name)[0..4], + }) + }) + .collect(); + context.insert("user_type", &self.user.user_type); context.insert("email", &self.user.email); context.insert("group", &self.groups); - context.insert("subscriptions", &self.subscriptions); + context.insert("subscriptions", &subs_expanded); context.insert("token", &self.user.token); // add in the expiration time if token is present if let Some(t) = &self.user.token { diff --git a/src/web/route/proxy/services.rs b/src/web/route/proxy/services.rs index 507e4abb..9041fca6 100644 --- a/src/web/route/proxy/services.rs +++ b/src/web/route/proxy/services.rs @@ -9,9 +9,7 @@ use crate::errors::{BridgeError, Result}; pub struct Catalog(pub toml::Table); pub static CATALOG: LazyLock = LazyLock::new(|| { - let service_config = if cfg!(debug_assertions) { - "config/services_sample.toml" - } else { + let service_config = { "config/services.toml" }; diff --git a/static/css/carbon-bridge.css b/static/css/carbon-bridge.css new file mode 100644 index 00000000..b10b656f --- /dev/null +++ b/static/css/carbon-bridge.css @@ -0,0 +1,7 @@ +html { + font-size: 14px; +} +#navigation { + background: var(--cb-main); + color: white; +} diff --git a/static/css/carbon-skin.css b/static/css/carbon-skin.css new file mode 100644 index 00000000..627e1827 --- /dev/null +++ b/static/css/carbon-skin.css @@ -0,0 +1,338 @@ + +/* @import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@100..700&display=swap"); */ + +body { + /* Colors - light */ + --cb-blue: #0F62FE; + --cb-blue-hover: #0353E9; + --cb-blue-active: #0043CE; + --cb-main: #393939; + --cb-main-weak: #4C4C4C; + --cb-main-strong: #161616; + --cb-soft-text: #BBBBBB; + --cb-soft-border: #E5E5E5; + --cb-soft-bg: #F4F4F4; + --cb-highlight: #FFF7CC; + + /* Font styles */ + --cb-font-fam: "IBM Plex Sans", sans-serif; + --cb-font-size: 14px; + --cb-line-height: 18px; +} + +@media (prefers-color-scheme: dark) { + body { + /* Colors - dark */ + --cb-blue: #0f62fe; + --cb-blue-hover: #0353e9; + --cb-blue-active: #0043ce; + --cb-main: #393939; + --cb-main-weak: #4c4c4c; + --cb-main-strong: #161616; + --cb-soft-text: #BBBBBB; + --cb-soft-border: #E5E5E5; + --cb-soft-bg: #F4F4F4; + } +} + +/** + * Style shortcuts + */ + +.soft-text { + color: var(--cb-soft-text); +} + +/** + * Layout + */ + +/* Section headers */ +.section-header { + border-bottom: solid 1px var(--cb-soft-text); + font-weight: bold; + padding-bottom: 0.5rem; + margin-bottom: 0.75rem; +} +.section-header-right { + display: flex; + flex-direction: row; + justify-content: end; + flex-grow: 1; +} + +/* Page columns */ +.page-column { + padding: 2rem; + margin: 0 0.25rem 0.5rem 0.25rem; + background: var(--cb-soft-bg); +} + + +/** + * Links + */ + +a.cb-link { + color: var(--cb-blue); + text-decoration: none; +} +a.cb-link:hover { + color: var(--cb-blue-active); +} + +/** + * Tables + */ + +.table-display { + width: calc(100% + 2rem); + /* border-left: solid 1px var(--cb-soft-border); */ + /* border-top: solid 1px var(--cb-soft-border); */ + background: white; + padding: 0.5rem 1rem; + margin: -1rem; + margin-top: 0; + text-align: left; +} + +/* Row borders */ +.table-display tr { + border-bottom: solid 1px var(--cb-soft-border); +} +.table-display tr:not(.expandable):last-child, +.table-display tr.expandable:nth-last-child(2) { + border-bottom: none; +} + +/* Header */ +.table-display tr.header { + background: var(--cb-soft-border); +} + +/* Cells */ +.table-display td, +.table-display th { + padding: 0.5rem 1rem; +} + +/* Expandable row */ +.table-display tr.expandable { + cursor: pointer; + position: relative; +} +.table-display tr.expandable:not(.expanded) + tr { + display: none; +} + +/* Expanded state */ +.table-display tr.expanded { + border-bottom: none; + font-weight: bold; +} +.table-display tr.expanded, +.table-display tr.expanded + tr { + position: relative; +} +.table-display tr.expanded td::before, +.table-display tr.expanded + tr td::before { + content: ''; + display: block; + position: absolute; + top: 0; + left: 0; + width: 3px; + height: calc(100% + 1px); + background: var(--cb-blue); +} +.table-display tr:not(.expandable):last-child td::before { + /* Last row doesn't have bottom border */ + height: 100%; +} + +/* Expandable tray */ +.table-display tr.expandable + tr { + font-size: 0.9rem; + position: relative; +} +.table-display tr.expandable + tr td { + padding-bottom: 2rem; +} +.table-display tr.expandable + tr::after { + content: ''; + display: block; + position: absolute; + top: 0; + left: 1rem; + width: calc(100% - 2rem); + border-bottom: dashed 1px var(--cb-soft-border); +} + +/* Code blocks */ +.table-display code { + margin: 0.25rem 0; +} + +@media (hover: hover) { + .table-display tr.expandable:not(.expanded):hover { + background: var(--cb-highlight); + position: relative; + z-index: 1; + } +} + +/** + * Buttons + */ + +.cb_button { + height: 40px; + background: var(--cb-blue); + border: none; + color: #fff; + padding: 0 32px 0 16px; + font-family: var(--cb-font-fam); + font-size: var(--cb-font-size); + cursor: pointer; + + /* For icons */ + display: flex; + align-items: center; + justify-content: center; + gap: 0.5em; +} +.cb_button:hover { + background: var(--cb-blue-hover); +} +.cb_button.secondary { + background: var(--cb-main); + color: #fff; +} +.cb_button.secondary:hover { + background: var(--cb-main-weak); +} +.cb_button.tertiary { + background: transparent; + color: var(--cb-main); + border: 1px solid var(--cb-main); +} +.cb_button.tertiary:hover { + border-color: var(--cb-blue-hover); +} + +/** + * Dropdowns + */ +.ibm-dropdown { + display: flex; + flex-direction: column; + position: relative; + width: 240px; + color: var(--cb-main); +} +.ibm-dropdown .ibm-label-txt { + font-size: 12px; + line-height: 16px; + margin-bottom: 8px; +} +.ibm-dropdown .ibm-dd-display { + height: 40px; + background: var(--cb-soft-bg); + position: absolute; + left: 0; + right: 0; + bottom: 0; + z-index: 1; + border-bottom: solid 1px #8d8d8d; + box-sizing: border-box; + font-size: 14px; + line-height: 40px; + padding: 0 16px; + pointer-events: none; + user-select: none; +} +.ibm-dropdown .ibm-dd-display::after { + content: ""; + display: block; + height: 40px; + width: 50px; + background: url("data:image/svg+xml;utf8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22%23161616%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M8%2011L3%205.99999L3.7%205.29999L8%209.59999L12.3%205.29999L13%205.99999L8%2011Z%22%2F%3E%3C%2Fsvg%3E") + center center no-repeat; + position: absolute; + right: 0; + top: 0; +} +.ibm-dropdown select { + height: 40px; + width: 100%; + /* visibility: hidden; */ +} +.ibm-icn-caret { + background: url("data:image/svg+xml;utf8,%3Csvg%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22%23161616%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M8%2011L3%205.99999L3.7%205.29999L8%209.59999L12.3%205.29999L13%205.99999L8%2011Z%22%2F%3E%3C%2Fsvg%3E") + 0 0 no-repeat; +} + +/** + * Code blocks + */ + +code { + background: var(--cb-main); + color: var(--cb-highlight); + position: relative; + cursor: pointer; +} +code.block { + display: block; + border-radius: 3px; + padding: 0.7rem 1rem; +} +code .copy { + position: absolute; + z-index: 1; + top: 5px; + right: 8px; + text-align: right; + display: none; + color: white; +} +code .copy::before { + content: ''; + position: absolute; + z-index: -1; + top: 0; + right: 0; + bottom: 0; + left: 0; + background: var(--cb-main); + filter: blur(4px); +} +code.copied, +code.copied .copy::before { + animation: code-copied 120ms 3; + color: #9C9882; +} +code.copied .copy { + display: block; +} + +@media (hover: hover) { + code:not(.copied):hover { + background: var(--cb-main-strong); + } +} + +@keyframes code-copied { + 0% { + background: green; + } + 49% { + background: green; + } + 50% { + background: var(--cb-main); + } + 100% { + background: var(--cb-main); + } +} \ No newline at end of file diff --git a/static/css/input.css b/static/css/input.css index 6b9e93f9..2e850974 100644 --- a/static/css/input.css +++ b/static/css/input.css @@ -1,51 +1,52 @@ -@import 'tailwindcss'; +@import "tailwindcss"; -/* - The default border color has changed to `currentColor` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. +/** + * Base styles + */ + + + +body { + @apply text-[var(--cb-main)] dark:text-[var(--cb-soft-bg)]; +} - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. -*/ @layer base { - *, - ::after, - ::before, - ::backdrop, - ::file-selector-button { - border-color: var(--color-gray-200, currentColor); - } + p { + @apply mb-2; + } + /* *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + @apply border-[var(--cb-soft-border)]; + } */ } +/** + * Navigation + */ + .menu_selected { - @apply bg-[#c6c6c6] dark:bg-[#4d5358] border-l-2 border-[#4589ff]; + @apply bg-[rgba(0,0,0,.08)] dark:bg-[rgba(255,255,255,.1)] border-l-2 border-[var(--cb-blue)]; } .mobile_menu_selected { - @apply border-l-4 border-[#4589ff]; -} - -.cb_button { - @apply bg-[#0050e6] hover:bg-blue-700 text-slate-200 - focus:ring-3 dark:focus:outline-hidden active:bg-[#002d9c] - dark:focus:ring-white focus:ring-[#0050e6]; + @apply border-l-4 border-[var(--cb-blue)]; } -.cb_button_secondary { - @apply bg-[#ffffff] hover:bg-blue-700 hover:text-slate-200 text-slate-900 - focus:ring-3 dark:focus:outline-hidden active:bg-[#002d9c] active:text-[#ffffff] - dark:focus:ring-white focus:ring-[#0050e6]; -} +/** + * Various + */ .htmx-indicator { - opacity:0; + opacity: 0; } .htmx-request .htmx-indicator { - opacity:1; + opacity: 1; transition: opacity 200ms ease-in; } .htmx-request.htmx-indicator { - opacity:1; + opacity: 1; transition: opacity 200ms ease-in; } diff --git a/static/css/output.css b/static/css/output.css index a29c48ea..b78bf0f1 100644 --- a/static/css/output.css +++ b/static/css/output.css @@ -1,2 +1,2 @@ -/*! tailwindcss v4.1.4 | 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-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight: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-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-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-green-900:oklch(39.3% .095 152.535);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-700:oklch(48.8% .243 264.376);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-900:oklch(20.8% .042 265.755);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-700:oklch(37.3% .034 259.733);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5/2.25);--font-weight-medium:500;--font-weight-bold:700;--leading-tight:1.25;--radius-md:.375rem;--drop-shadow-md:0 3px 3px #0000001f;--ease-in:cubic-bezier(.4,0,1,1);--animate-spin:spin 1s linear infinite;--animate-bounce:bounce 1s infinite;--blur-xs:4px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;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;-webkit-text-decoration: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}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*,:after,:before,::backdrop{border-color:var(--color-gray-200,currentColor)}::file-selector-button{border-color:var(--color-gray-200,currentColor)}}@layer components;@layer utilities{.visible{visibility:visible}.sr-only{clip:rect(0,0,0,0);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\.5{inset:calc(var(--spacing)*-.5)}.inset-y-0{inset-block:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.top-12{top:calc(var(--spacing)*12)}.left-0{left:calc(var(--spacing)*0)}.z-10{z-index:10}.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-3{margin-inline:calc(var(--spacing)*3)}.mx-5{margin-inline:calc(var(--spacing)*5)}.mx-auto{margin-inline:auto}.my-2{margin-block:calc(var(--spacing)*2)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-4{margin-top:calc(var(--spacing)*4)}.mr-1{margin-right:calc(var(--spacing)*1)}.mr-2{margin-right:calc(var(--spacing)*2)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.ml-2{margin-left:calc(var(--spacing)*2)}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.table{display:table}.size-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.h-10{height:calc(var(--spacing)*10)}.h-12{height:calc(var(--spacing)*12)}.h-16{height:calc(var(--spacing)*16)}.h-\[42px\]{height:42px}.h-\[50px\]{height:50px}.h-full{height:100%}.max-h-80{max-height:calc(var(--spacing)*80)}.min-h-60{min-height:calc(var(--spacing)*60)}.min-h-96{min-height:calc(var(--spacing)*96)}.min-h-\[calc\(100vh-3rem\)\]{min-height:calc(100vh - 3rem)}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-16{width:calc(var(--spacing)*16)}.w-56{width:calc(var(--spacing)*56)}.w-64{width:calc(var(--spacing)*64)}.w-\[220px\]{width:220px}.w-\[384px\]{width:384px}.w-full{width:100%}.max-w-7xl{max-width:var(--container-7xl)}.min-w-52{min-width:calc(var(--spacing)*52)}.min-w-full{min-width:100%}.flex-1{flex:1}.flex-none{flex:none}.shrink-0{flex-shrink:0}.flex-grow,.grow{flex-grow:1}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-bounce{animation:var(--animate-bounce)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.self-center{align-self:center}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.rounded-br-md{border-bottom-right-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-t-4{border-top-style:var(--tw-border-style);border-top-width:4px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-4{border-bottom-style:var(--tw-border-style);border-bottom-width:4px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-\[\#4589ff\]{border-color:#4589ff}.border-\[\#e0e0e0\]{border-color:#e0e0e0}.border-blue-500{border-color:var(--color-blue-500)}.bg-\[\#f4f4f4\]{background-color:#f4f4f4}.bg-\[\#f4f4f4\]\/70{background-color:oklab(96.7153% -5.96046e-8 5.96046e-8/.7)}.bg-\[\#ffffff\]{background-color:#fff}.bg-inherit{background-color:inherit}.bg-slate-300{background-color:var(--color-slate-300)}.bg-white{background-color:var(--color-white)}.p-0{padding:calc(var(--spacing)*0)}.p-1{padding:calc(var(--spacing)*1)}.p-2{padding:calc(var(--spacing)*2)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-2{padding-block:calc(var(--spacing)*2)}.py-3{padding-block:calc(var(--spacing)*3)}.py-4{padding-block:calc(var(--spacing)*4)}.py-6{padding-block:calc(var(--spacing)*6)}.pt-2{padding-top:calc(var(--spacing)*2)}.pt-3{padding-top:calc(var(--spacing)*3)}.pt-4{padding-top:calc(var(--spacing)*4)}.pt-10{padding-top:calc(var(--spacing)*10)}.pr-2{padding-right:calc(var(--spacing)*2)}.pr-8{padding-right:calc(var(--spacing)*8)}.pb-0\.5{padding-bottom:calc(var(--spacing)*.5)}.pb-4{padding-bottom:calc(var(--spacing)*4)}.pb-5{padding-bottom:calc(var(--spacing)*5)}.pb-10{padding-bottom:calc(var(--spacing)*10)}.pb-20{padding-bottom:calc(var(--spacing)*20)}.pl-1{padding-left:calc(var(--spacing)*1)}.pl-2{padding-left:calc(var(--spacing)*2)}.pl-4{padding-left:calc(var(--spacing)*4)}.text-center{text-align:center}.text-left{text-align:left}.align-top{vertical-align:top}.font-mono{font-family:var(--font-mono)}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.break-all{word-break:break-all}.text-black{color:var(--color-black)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-green-600{color:var(--color-green-600)}.text-green-900{color:var(--color-green-900)}.text-red-600{color:var(--color-red-600)}.text-slate-900{color:var(--color-slate-900)}.capitalize{text-transform:capitalize}.ring{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.drop-shadow-md{--tw-drop-shadow-size:drop-shadow(0 3px 3px var(--tw-drop-shadow-color,#0000001f));--tw-drop-shadow:drop-shadow(var(--drop-shadow-md));filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.backdrop-blur-xs{--tw-backdrop-blur:blur(var(--blur-xs));-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;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))}.ease-in{--tw-ease:var(--ease-in);transition-timing-function:var(--ease-in)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.focus-within\:border-transparent:focus-within{border-color:#0000}.focus-within\:ring-2:focus-within{--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-within\:ring-blue-500:focus-within{--tw-ring-color:var(--color-blue-500)}.focus-within\:outline-none:focus-within{--tw-outline-style:none;outline-style:none}@media (hover:hover){.hover\:border-gray-400:hover{border-color:var(--color-gray-400)}.hover\:bg-\[\#c6c6c6\]:hover{background-color:#c6c6c6}.hover\:bg-gray-700:hover{background-color:var(--color-gray-700)}.hover\:text-white:hover{color:var(--color-white)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:border-blue-500:focus{border-color:var(--color-blue-500)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-white:focus{--tw-ring-color:var(--color-white)}.focus\:outline-hidden:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.focus\:outline-hidden:focus{outline-offset:2px;outline:2px solid #0000}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus\:ring-inset:focus{--tw-ring-inset:inset}@media not all and (min-width:64rem){.max-lg\:hidden{display:none}}@media not all and (min-width:40rem){.max-sm\:hidden{display:none}}@media (min-width:40rem){.sm\:items-stretch{align-items:stretch}.sm\:px-6{padding-inline:calc(var(--spacing)*6)}}@media (min-width:48rem){.md\:block{display:block}.md\:hidden{display:none}.md\:w-\[384px\]{width:384px}.md\:justify-center{justify-content:center}.md\:justify-start{justify-content:flex-start}.md\:pt-0{padding-top:calc(var(--spacing)*0)}.md\:pb-0{padding-bottom:calc(var(--spacing)*0)}.md\:pl-56{padding-left:calc(var(--spacing)*56)}.md\:pl-64{padding-left:calc(var(--spacing)*64)}.md\:text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}}@media (min-width:64rem){.lg\:w-\[300px\]{width:300px}.lg\:w-\[500px\]{width:500px}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:px-8{padding-inline:calc(var(--spacing)*8)}.lg\:py-2{padding-block:calc(var(--spacing)*2)}}@media (min-width:80rem){.xl\:my-0{margin-block:calc(var(--spacing)*0)}.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (prefers-color-scheme:dark){.dark\:border-\[\#4d5358\]{border-color:#4d5358}.dark\:bg-\[\#343a3f\]{background-color:#343a3f}.dark\:bg-\[\#21272a\]{background-color:#21272a}.dark\:bg-\[\#42484e\]{background-color:#42484e}.dark\:bg-\[\#121619\]{background-color:#121619}.dark\:bg-\[\#121619\]\/70{background-color:oklab(19.7278% -.00427963 -.00752458/.7)}.dark\:text-gray-400{color:var(--color-gray-400)}.dark\:text-green-700{color:var(--color-green-700)}.dark\:text-red-500{color:var(--color-red-500)}.dark\:text-slate-200{color:var(--color-slate-200)}@media (hover:hover){.dark\:hover\:bg-\[\#4d5358\]:hover{background-color:#4d5358}}}}.menu_selected{border-left-style:var(--tw-border-style);background-color:#c6c6c6;border-color:#4589ff;border-left-width:2px}@media (prefers-color-scheme:dark){.menu_selected{background-color:#4d5358}}.mobile_menu_selected{border-left-style:var(--tw-border-style);border-color:#4589ff;border-left-width:4px}.cb_button{color:var(--color-slate-200);background-color:#0050e6}@media (hover:hover){.cb_button:hover{background-color:var(--color-blue-700)}}.cb_button:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + 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);--tw-ring-color:#0050e6}.cb_button:active{background-color:#002d9c}@media (prefers-color-scheme:dark){.cb_button:focus{--tw-ring-color:var(--color-white);--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.cb_button:focus{outline-offset:2px;outline:2px solid #0000}}}.cb_button_secondary{color:var(--color-slate-900);background-color:#fff}@media (hover:hover){.cb_button_secondary:hover{background-color:var(--color-blue-700);color:var(--color-slate-200)}}.cb_button_secondary:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + 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);--tw-ring-color:#0050e6}.cb_button_secondary:active{color:#fff;background-color:#002d9c}@media (prefers-color-scheme:dark){.cb_button_secondary:focus{--tw-ring-color:var(--color-white);--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.cb_button_secondary:focus{outline-offset:2px;outline:2px solid #0000}}}.htmx-indicator{opacity:0}.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{opacity:1;transition:opacity .2s ease-in}@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-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{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:"";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:"";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:"";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-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:"";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-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}} \ No newline at end of file +/*! tailwindcss v4.1.12 | 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-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight: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-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-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-green-900:oklch(39.3% .095 152.535);--color-blue-500:oklch(62.3% .214 259.815);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-900:oklch(20.8% .042 265.755);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height:calc(1.5/1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5/2.25);--font-weight-medium:500;--font-weight-bold:700;--leading-tight:1.25;--radius-md:.375rem;--drop-shadow-md:0 3px 3px #0000001f;--ease-in:cubic-bezier(.4,0,1,1);--animate-spin:spin 1s linear infinite;--animate-bounce:bounce 1s infinite;--blur-xs:4px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;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;-webkit-text-decoration: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]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}p{margin-bottom:calc(var(--spacing)*2)}}@layer components;@layer utilities{.visible{visibility:visible}.sr-only{clip:rect(0,0,0,0);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\.5{inset:calc(var(--spacing)*-.5)}.inset-y-0{inset-block:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.top-12{top:calc(var(--spacing)*12)}.left-0{left:calc(var(--spacing)*0)}.z-10{z-index:10}.col-span-1{grid-column:span 1/span 1}.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-1{margin-inline:calc(var(--spacing)*1)}.mx-3{margin-inline:calc(var(--spacing)*3)}.mx-5{margin-inline:calc(var(--spacing)*5)}.mx-auto{margin-inline:auto}.my-2{margin-block:calc(var(--spacing)*2)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-4{margin-top:calc(var(--spacing)*4)}.mr-1{margin-right:calc(var(--spacing)*1)}.mr-2{margin-right:calc(var(--spacing)*2)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.ml-2{margin-left:calc(var(--spacing)*2)}.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-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.h-10{height:calc(var(--spacing)*10)}.h-12{height:calc(var(--spacing)*12)}.h-16{height:calc(var(--spacing)*16)}.h-\[42px\]{height:42px}.h-\[50px\]{height:50px}.h-full{height:100%}.max-h-80{max-height:calc(var(--spacing)*80)}.min-h-60{min-height:calc(var(--spacing)*60)}.min-h-96{min-height:calc(var(--spacing)*96)}.min-h-\[calc\(100vh-3rem\)\]{min-height:calc(100vh - 3rem)}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-16{width:calc(var(--spacing)*16)}.w-56{width:calc(var(--spacing)*56)}.w-64{width:calc(var(--spacing)*64)}.w-\[220px\]{width:220px}.w-\[384px\]{width:384px}.w-full{width:100%}.max-w-7xl{max-width:var(--container-7xl)}.min-w-52{min-width:calc(var(--spacing)*52)}.min-w-full{min-width:100%}.flex-1{flex:1}.flex-none{flex:none}.shrink-0{flex-shrink:0}.flex-grow,.grow{flex-grow:1}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-bounce{animation:var(--animate-bounce)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.self-center{align-self:center}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-br-md{border-bottom-right-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-t-4{border-top-style:var(--tw-border-style);border-top-width:4px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-4{border-bottom-style:var(--tw-border-style);border-bottom-width:4px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-\[\#0f62fe\]{border-color:#0f62fe}.border-\[\#e0e0e0\]{border-color:#e0e0e0}.border-blue-500{border-color:var(--color-blue-500)}.bg-\[\#f4f4f4\]{background-color:#f4f4f4}.bg-\[\#f4f4f4\]\/70{background-color:oklab(96.7153% -5.96046e-8 5.96046e-8/.7)}.bg-\[\#ffffff\]{background-color:#fff}.bg-inherit{background-color:inherit}.bg-slate-300{background-color:var(--color-slate-300)}.bg-white{background-color:var(--color-white)}.p-0{padding:calc(var(--spacing)*0)}.p-1{padding:calc(var(--spacing)*1)}.p-2{padding:calc(var(--spacing)*2)}.p-7{padding:calc(var(--spacing)*7)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-2{padding-block:calc(var(--spacing)*2)}.py-3{padding-block:calc(var(--spacing)*3)}.py-4{padding-block:calc(var(--spacing)*4)}.py-6{padding-block:calc(var(--spacing)*6)}.pt-2{padding-top:calc(var(--spacing)*2)}.pt-3{padding-top:calc(var(--spacing)*3)}.pt-4{padding-top:calc(var(--spacing)*4)}.pt-10{padding-top:calc(var(--spacing)*10)}.pr-2{padding-right:calc(var(--spacing)*2)}.pr-8{padding-right:calc(var(--spacing)*8)}.pb-0\.5{padding-bottom:calc(var(--spacing)*.5)}.pb-4{padding-bottom:calc(var(--spacing)*4)}.pb-5{padding-bottom:calc(var(--spacing)*5)}.pb-10{padding-bottom:calc(var(--spacing)*10)}.pb-20{padding-bottom:calc(var(--spacing)*20)}.pl-1{padding-left:calc(var(--spacing)*1)}.pl-2{padding-left:calc(var(--spacing)*2)}.pl-4{padding-left:calc(var(--spacing)*4)}.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)}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.break-all{word-break:break-all}.text-black{color:var(--color-black)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-green-600{color:var(--color-green-600)}.text-green-900{color:var(--color-green-900)}.text-red-600{color:var(--color-red-600)}.text-slate-900{color:var(--color-slate-900)}.capitalize{text-transform:capitalize}.ring{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.drop-shadow-md{--tw-drop-shadow-size:drop-shadow(0 3px 3px var(--tw-drop-shadow-color,#0000001f));--tw-drop-shadow:drop-shadow(var(--drop-shadow-md));filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.backdrop-blur-xs{--tw-backdrop-blur:blur(var(--blur-xs));-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,visibility,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))}.ease-in{--tw-ease:var(--ease-in);transition-timing-function:var(--ease-in)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.focus-within\:border-transparent:focus-within{border-color:#0000}.focus-within\:ring-2:focus-within{--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-within\:ring-blue-500:focus-within{--tw-ring-color:var(--color-blue-500)}.focus-within\:outline-none:focus-within{--tw-outline-style:none;outline-style:none}@media (hover:hover){.hover\:border-gray-400:hover{border-color:var(--color-gray-400)}.hover\:bg-\[\#c6c6c6\]:hover{background-color:#c6c6c6}.hover\:bg-\[rgba\(0\,0\,0\,\.2\)\]:hover{background-color:#0003}.hover\:text-white:hover{color:var(--color-white)}.hover\:underline:hover{text-decoration-line:underline}}.focus\:border-blue-500:focus{border-color:var(--color-blue-500)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-white:focus{--tw-ring-color:var(--color-white)}.focus\:outline-hidden:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.focus\:outline-hidden:focus{outline-offset:2px;outline:2px solid #0000}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus\:ring-inset:focus{--tw-ring-inset:inset}@media not all and (min-width:64rem){.max-lg\:hidden{display:none}}@media not all and (min-width:40rem){.max-sm\:hidden{display:none}}@media (min-width:40rem){.sm\:items-stretch{align-items:stretch}.sm\:px-6{padding-inline:calc(var(--spacing)*6)}}@media (min-width:48rem){.md\:col-start-1{grid-column-start:1}.md\:row-start-2{grid-row-start:2}.md\:block{display:block}.md\:hidden{display:none}.md\:w-\[384px\]{width:384px}.md\:justify-center{justify-content:center}.md\:justify-start{justify-content:flex-start}.md\:pt-0{padding-top:calc(var(--spacing)*0)}.md\:pb-0{padding-bottom:calc(var(--spacing)*0)}.md\:pl-56{padding-left:calc(var(--spacing)*56)}.md\:pl-65{padding-left:calc(var(--spacing)*65)}.md\:text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}}@media (min-width:64rem){.lg\:col-start-1{grid-column-start:1}.lg\:col-start-2{grid-column-start:2}.lg\:block{display:block}.lg\:hidden{display:none}.lg\:w-\[300px\]{width:300px}.lg\:w-\[500px\]{width:500px}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:px-8{padding-inline:calc(var(--spacing)*8)}.lg\:py-2{padding-block:calc(var(--spacing)*2)}}@media (min-width:80rem){.xl\:col-span-2{grid-column:span 2/span 2}.xl\:col-start-2{grid-column-start:2}.xl\:col-start-3{grid-column-start:3}.xl\:row-span-2{grid-row:span 2/span 2}.xl\:row-start-1{grid-row-start:1}.xl\:my-0{margin-block:calc(var(--spacing)*0)}.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (prefers-color-scheme:dark){.dark\:border-\[\#4d5358\]{border-color:#4d5358}.dark\:bg-\[\#343a3f\]{background-color:#343a3f}.dark\:bg-\[\#21272a\]{background-color:#21272a}.dark\:bg-\[\#42484e\]{background-color:#42484e}.dark\:bg-\[\#121619\]{background-color:#121619}.dark\:bg-\[\#121619\]\/70{background-color:oklab(19.7278% -.00427963 -.00752458/.7)}.dark\:text-gray-400{color:var(--color-gray-400)}.dark\:text-green-700{color:var(--color-green-700)}.dark\:text-red-500{color:var(--color-red-500)}.dark\:text-slate-200{color:var(--color-slate-200)}@media (hover:hover){.dark\:hover\:bg-\[\#4d5358\]:hover{background-color:#4d5358}}}}body{color:var(--cb-main)}@media (prefers-color-scheme:dark){body{color:var(--cb-soft-bg)}}.menu_selected{border-left-style:var(--tw-border-style);border-left-width:2px;border-color:var(--cb-blue);background-color:#00000014}@media (prefers-color-scheme:dark){.menu_selected{background-color:#ffffff1a}}.mobile_menu_selected{border-left-style:var(--tw-border-style);border-left-width:4px;border-color:var(--cb-blue)}.htmx-indicator{opacity:0}.htmx-request .htmx-indicator,.htmx-request.htmx-indicator{opacity:1;transition:opacity .2s ease-in}@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-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{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:"";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:"";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:"";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-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:"";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-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index 4864dd00..f003d72d 100644 --- a/templates/base.html +++ b/templates/base.html @@ -8,6 +8,8 @@ {% block title %}{% endblock title %} + + {% block htmx %} diff --git a/templates/components/code_block.html b/templates/components/code_block.html new file mode 100644 index 00000000..c0430666 --- /dev/null +++ b/templates/components/code_block.html @@ -0,0 +1,5 @@ +
✅ copied
{{ code }}
\ No newline at end of file diff --git a/templates/components/group_create.html b/templates/components/group_create.html index 188957e4..bec3237c 100644 --- a/templates/components/group_create.html +++ b/templates/components/group_create.html @@ -1,6 +1,6 @@
-

Group Create

-
+

Group Create

+
-

Group Edit {{ group_name | capitalize }}

-
+

Group Edit {{ group_name | capitalize }}

+
-

Group View

-
+

Group View

+
Add Members

+

Add Members

-

Group View

-
+

Group View

+
-
-

Your Group Info

+
+

Your Group Info

Name: {{ group | first }}

Created at: {{ group_created_at | truncate(length=15) }}

Update at: {{ group_updated_at | truncate(length=15) }}

Last Updated by: {{ group_last_updated }}

-
-

Group Details

+
+

Group Details

@@ -15,7 +15,7 @@ {% if subscriptions | length > 0 %}
    {% for sub in subscriptions %} -
  • +
  • {{ sub }}
  • {% endfor %} @@ -27,7 +27,7 @@
Subscriptions:
-
+
{% include 'components/member_manage.html' %}
diff --git a/templates/components/notebook/notebook.html b/templates/components/notebook/notebook.html index 93bdfaa3..ce8588ce 100644 --- a/templates/components/notebook/notebook.html +++ b/templates/components/notebook/notebook.html @@ -1,7 +1,7 @@
-
-

Your Workbench

+

Your Workbench

{% if notebook.start_time == "None" %} {# No notebook up #} diff --git a/templates/components/owui/owui.html b/templates/components/owui/owui.html index 2cce013f..6cbf08a6 100644 --- a/templates/components/owui/owui.html +++ b/templates/components/owui/owui.html @@ -1,7 +1,7 @@
-
-

Your Open Web UI

+

Your Open Web UI

You currently have a owui running.

diff --git a/templates/components/profile.html b/templates/components/profile.html index 526ee06f..dd6fcccd 100644 --- a/templates/components/profile.html +++ b/templates/components/profile.html @@ -1,36 +1,48 @@
-
-

Your Info

-

Name: {{ name }}

-

Email: {{ email }}

-

User type: {{ user_type }}

+ +
+

Your Info

+

Name: {{ name }}

+

Email: {{ email }}

+

User type: {{ user_type }}

+ +

+ {%include "components/token.html" %}
-
-

Group Info

- - - - + {# xl:col-start-3 lg:col-start-2 col-start-1 #} + {# md:row-start-2 row-start-1 lg:col-start-1 md:col-start-1 col-start-2 col-span-1 #} + + {#
+ {%include "components/token.html" %} +
#} + + {# xl:row-start-1 xl:row-span-2 #} +
+
+

Your Subscriptions

+
Group: {{ group | first }}
+
+ {% if subscriptions | length > 0 %} +
Name:{{ group | first }}
+ + + + + {% for sub in subscriptions %} + + + - - + {% endfor %}
Service NameType
Subscriptions: - {% if subscriptions | length > 0 %} -
    - {% for sub in subscriptions %} -
  • - {{ sub }} -
  • - {% endfor %} -
- {% else %} - None - {% endif %} +
+ {% include 'components/subscription_details.html' %}
+ {% else %} + This group has no subscriptions + {% endif %}
-
- {%include "components/token.html" %} -
-
+ +
\ No newline at end of file diff --git a/templates/components/subscription_details.html b/templates/components/subscription_details.html new file mode 100644 index 00000000..e94c05f7 --- /dev/null +++ b/templates/components/subscription_details.html @@ -0,0 +1,18 @@ +{# OpenAD model #} +{% if sub.type == 'openad_model' %} + {% set code = sub.code %} + {% include 'components/code_block.html' %} +

Use the command above to catalog this model in OpenAD.

+ Consult the OpenAD docs for more instructions. + +{# MCP #} +{% elif sub.type == 'mcp' %} + {% set code = sub.code %} + {% include 'components/code_block.html' %} + Connect to the MCP server with the link above. + +{# Other #} +{% elif sub.type == 'other' %} + This subscription does not have any additional details. + +{% endif %} \ No newline at end of file diff --git a/templates/components/systems.html b/templates/components/systems.html index bf2bc174..081ac61a 100644 --- a/templates/components/systems.html +++ b/templates/components/systems.html @@ -1,10 +1,10 @@
+ class="p-7 mx-1 mb-2 transition-all xl:my-0 dark:bg-[#343a3f] bg-[#f4f4f4]"> {% include 'components/systems_group.html' %}
+ class="p-7 mx-1 mb-2 transition-all xl:my-0 dark:bg-[#343a3f] bg-[#f4f4f4]"> {% include 'components/systems_user.html' %}
diff --git a/templates/components/systems_group.html b/templates/components/systems_group.html index 9c5cac10..e4ba9f60 100644 --- a/templates/components/systems_group.html +++ b/templates/components/systems_group.html @@ -1,13 +1,21 @@ -

Group Management

-
- +

Group Management

+
diff --git a/templates/components/systems_user.html b/templates/components/systems_user.html index d2c1f7ac..fec796e2 100644 --- a/templates/components/systems_user.html +++ b/templates/components/systems_user.html @@ -1,4 +1,4 @@ -

User Management

+

User Management