From ab91056a680b9cc8c78aa69bdd9bbf6b41c4c217 Mon Sep 17 00:00:00 2001 From: Rotimi Best Date: Wed, 17 Jun 2026 20:23:00 +0100 Subject: [PATCH 1/6] docs(prd): add reset student course progress plan (#670) --- PRD-TRACKER.md | 1 + prd/reset-student-course-progress/README.md | 392 ++++++++++++++++++++ 2 files changed, 393 insertions(+) create mode 100644 prd/reset-student-course-progress/README.md diff --git a/PRD-TRACKER.md b/PRD-TRACKER.md index c0fa5065..2c66a11f 100644 --- a/PRD-TRACKER.md +++ b/PRD-TRACKER.md @@ -21,6 +21,7 @@ Use this file to keep a single prioritized view of all PRDs. | - | - | `prd/customer-course-documentation` | todo | | - | - | `prd/walkthrough-widget` | draft | | - | - | `prd/copy-page-as-markdown` | todo | +| - | - | `prd/reset-student-course-progress` | todo | | - | 15 | `prd/webhooks` | todo | ## DONE (Completed PRDs) diff --git a/prd/reset-student-course-progress/README.md b/prd/reset-student-course-progress/README.md new file mode 100644 index 00000000..ecf03739 --- /dev/null +++ b/prd/reset-student-course-progress/README.md @@ -0,0 +1,392 @@ +# Reset Student Course Progress + +## Purpose + +Give course admins/tutors a safe, well-scoped way to **clear a single student's +progress in a single course** from the student's profile page (Course → +People → student detail). This is intended for cases like: + +- Re-running a learner through a course after a failed cohort attempt. +- Letting a learner retake a compliance/certification cycle from scratch. +- Cleaning up test data accidentally produced by a real account. + +This PRD documents only the new behavior; it does **not** modify the existing +"remove member from course" flow (that is destructive and removes the +`groupmember` row). + +## Scope + +In scope: + +- A **Reset progress** action on the course people detail page (`/courses/[id]/people/[personId]`). +- A confirmation **dialog** (using `Dialog.Footer`) that explicitly lists what + will be deleted, and offers **Cancel** / **Delete** actions. +- A backend endpoint that performs the reset for one `(courseId, profileId)` + pair inside a single DB transaction. +- Telemetry / audit logging so we can trace who reset whom. + +Out of scope (for v1): + +- Bulk reset (multiple students at once). +- Resetting only a subset of progress (e.g. only exercises). v1 is "reset + everything for this student in this course". +- Restoring/undoing a reset. The action is final. +- Resetting program-level goal assignments. Program goals re-evaluate from + course-level state, so clearing course progress will indirectly recompute + program goal status on the next evaluation; we do not delete + `program_goal_assignment` rows. + +## User Story + +> As a course admin or tutor, when I open a student in **Course → People → +> [student]**, I want a clearly labeled button to **clear that student's +> progress in this course** (lesson completion, video progress, exercise +> submissions, comments, certificate state, …). Before anything is deleted I +> want a confirmation modal that spells out **exactly** what will be removed, +> with a **Cancel** and a destructive **Delete** action. The student should +> remain enrolled (still appear in the People list) so they can restart the +> course. + +## UX Flow + +1. Admin/tutor opens `/courses/:courseId/people/:personId`. +2. In the page header (next to the existing back/refresh actions in the people + layout), a new destructive-styled **Reset progress** button is shown. + - Only visible for roles `ADMIN` (`1`) and `TUTOR` (`2`) — gated via the + existing `RoleBasedSecurity` wrapper used in + `routes/(app)/courses/[id]/people/+layout.svelte`. + - The button is hidden / disabled if the analytics fail to load (we do not + want to allow reset without seeing the impact). +3. Clicking the button opens a **Reset progress dialog**. + - Title: e.g. *"Reset progress for {studentName}?"* + - Body: + - One sentence framing: *"This permanently deletes this student's + progress in this course. They will stay enrolled and can restart from + lesson 1."* + - A bullet list spelling out what will be deleted, populated with the + counts from the loaded analytics (so the teacher sees real numbers): + - **Lessons completed** — _N_ of _M_ + - **Exercises submitted** — _N_ submissions + - **Lesson comments** by this student — _N_ + - **Newsfeed and community posts/replies** by this student — _N_ + - **Video watch progress** — _N_ lessons tracked + - **Attendance entries** — _N_ + - **Certification / compliance records** — _yes / no_ + - A small destructive callout: *"This cannot be undone."* + - `Dialog.Footer`: + - **Cancel** — `variant="outline"`, closes the dialog. + - **Delete** — `variant="destructive"`, runs the reset and shows a + loading state. On success the dialog closes and a snackbar confirms + *"Progress reset"*; the page reloads the analytics so the counts and + UI reflect the cleared state. +4. After reset, the student profile page re-renders with empty progress + (0% complete, 0 exercises, no completed lessons, etc.) but the user is + still listed in `Course → People`. + +## What Gets Deleted + +The reset is scoped to a single `(courseId, profileId)` pair. The +corresponding `groupmember` row in this course is identified by joining +`groupmember` → `course` on `course.group_id` and using the page's +`personId` (which today is a `profile.id`). + +The following rows are deleted inside a single transaction: + +### Direct learner progress + +- `lesson_completion` where `profile_id = student.profileId` and + `lesson_id` belongs to a `lesson` whose `course_id = courseId`. +- `lesson_video_progress` where `profile_id = student.profileId` and + `lesson_id` belongs to a `lesson` whose `course_id = courseId`. +- `submission` where `course_id = courseId` and `submitted_by = + groupmember.id` (the student's `groupmember.id` for **this** course). + - Cascades take care of related `question_answer` rows that are linked to + submissions via existing FKs. +- `group_attendance` where `course_id = courseId` and `student_id = + groupmember.id`. + +### Student-authored social content tied to this course + +- `lesson_comment` where `groupmember_id = student.groupmember.id`. +- `course_newsfeed` rows authored by the student in this course + (`course_id = courseId` AND `author_id = student.profileId`). +- `course_newsfeed_comment` authored by the student on newsfeed posts that + belong to this course (join through `course_newsfeed.course_id`). +- `community_question` and `community_answer` authored by the student in + this course (community questions filter on `course_id`; community answers + filter via the question's `course_id`). + +### Certification & compliance state (course-scoped) + +- `course_certificate_issue` for `(course_id = courseId, profile_id = + student.profileId)`. +- `course_completion_notification_event` cascaded via + `course_completion_record` for `(course_id, profile_id)`. +- `course_completion_record` for `(course_id = courseId, profile_id = + student.profileId)`. +- `groupmember.certificate_earned_at` and + `groupmember.certification_email_sent_at` are reset to `NULL` for the + student's groupmember row in this course. + +### AI / chat state scoped to this course + +- `ai_chat_conversation` rows for `(course_id = courseId, user_id = + student.profileId)`. + - Connected `ai_chat_document` etc. fall away through their FKs if any; + if no cascade is wired we delete dependents explicitly inside the + transaction. + +### Explicitly NOT deleted + +- `groupmember` itself (the student stays enrolled). +- `profile` / `user` / `organization_member` rows. +- `course_invite` history and invite audit logs. +- Program-level rows: `program_member`, `program_goal`, + `program_goal_assignment`. Program goals are re-evaluated from course + state on their next run, so the goal status will naturally update. +- AI tutor monthly counters (`ai_tutor_message_count`, + `ai_tutor_cap_event`). Those are billing/abuse signals, not progress. +- Org-wide analytics aggregates (`analytics_course_daily`, etc.). Those + are point-in-time aggregates and should not be retroactively rewritten. + +The PRD update step during implementation must add any newly introduced +"progress-like" tables to this list and to the reset transaction. + +## Implementation Plan + +This follows the route conventions in `AGENTS.md`. + +### 1. Validation schema + +`packages/utils/src/validation/course/people.ts`: + +```ts +export const ZResetCourseMemberProgressParam = z.object({ + courseId: z.string().uuid(), + memberId: z.string().uuid() +}); +export type TResetCourseMemberProgressParam = z.infer< + typeof ZResetCourseMemberProgressParam +>; +``` + +We key the route on `memberId` (the `groupmember.id`) to stay consistent +with the existing `PUT /course/:courseId/members/:memberId` and `DELETE +/course/:courseId/members/:memberId` shape. The service resolves the +`profileId` server-side. + +### 2. DB queries + +New file `packages/db/src/queries/course/reset-progress.ts` with a single +exported function: + +```ts +export async function resetStudentCourseProgress(input: { + courseId: string; + groupMemberId: string; + profileId: string; +}): Promise; +``` + +- Runs everything inside `db.transaction(async (tx) => { ... })`. +- Performs the deletes listed in **What Gets Deleted** above. +- Returns a small summary object with the row counts deleted per table so + the service can log it and the API can return it for the snackbar / + audit trail. +- Each delete is implemented with explicit, narrow `where(...)` filters + joined through the schema so we cannot accidentally delete rows from + another course. +- Wrapped in `try/catch` with `console.error('resetStudentCourseProgress + error:', error)` per repo convention. + +### 3. Service + +`apps/api/src/services/course/people.ts` gets a new function: + +```ts +export async function resetMemberCourseProgress( + courseId: string, + memberId: string +): Promise; +``` + +- Loads the member via `getCourseMember(courseId, memberId)`. +- Throws `AppError('Course member not found', ErrorCodes.NOT_FOUND, 404)` + if missing or if `profileId` is null (invite-only ghost member — nothing + to reset). +- Calls `resetStudentCourseProgress({ courseId, groupMemberId: memberId, + profileId: member.profileId })`. +- Logs `{ actorProfileId, courseId, memberId, summary }` so audit grep is + easy. + +### 4. Route + +In `apps/api/src/routes/course/people.ts`, mount a new endpoint: + +``` +POST /course/:courseId/members/:memberId/reset-progress +``` + +- Uses `courseTeamMemberMiddleware` (admin/tutor only) — same gate as the + other destructive member routes. +- Validates params with `ZResetCourseMemberProgressParam`. +- Calls `resetMemberCourseProgress(...)`. +- Returns `{ success: true, data: summary }` on success and uses + `handleError(c, error, 'Failed to reset course member progress')` in + the catch. + +Method choice: `POST` (rather than `DELETE`) because the action is +**state-changing on multiple tables** and we want the body to carry a +summary response. A `DELETE` on `…/progress` would technically work but +clients (and Hono RPC type inference) handle `POST … success/data` more +cleanly. + +### 5. Register + +The `membersRouter` is already mounted under `/course/:courseId/members`. +No changes to `app.ts` are needed. + +### 6. Build & frontend types + +After `pnpm --filter @cio/api build`, add to +`apps/dashboard/src/lib/features/course/utils/types.ts`: + +```ts +export type ResetMemberCourseProgressRequest = + (typeof classroomio.course)[':courseId']['members'][':memberId']['reset-progress']['$post']; +``` + +### 7. Frontend API class + +Add a method to `apps/dashboard/src/lib/features/course/api/people.svelte.ts`: + +```ts +async resetCourseProgress(courseId: string, memberId: string) { + await this.execute({ + requestFn: () => + classroomio.course[':courseId']['members'][':memberId']['reset-progress'].$post({ + param: { courseId, memberId } + }), + logContext: 'resetting course member progress', + onSuccess: () => { + snackbar.success('snackbar.course.people.progress_reset'); + this.success = true; + this.errors = {}; + }, + onError: (result) => { + if (typeof result === 'string') { + snackbar.error('snackbar.course.people.progress_reset_failed'); + } + } + }); +} +``` + +The page that calls this also invalidates `+page.server.ts` so the +analytics are re-fetched after success. + +### 8. UI + +Two new files under +`apps/dashboard/src/lib/features/course/components/people/`: + +- `reset-progress-button.svelte` — a destructive-styled `Button` that + opens the dialog. Uses `RoleBasedSecurity allowedRoles={[1, 2]}`. +- `reset-progress-dialog.svelte` — the `Dialog.Root` confirmation modal. + - Uses `Dialog.Header` (title + description), a list of impact bullets + built from `data.userCourseAnalytics`, and `Dialog.Footer` with + **Cancel** (`variant="outline"`) and **Delete** (`variant="destructive"`). + - Disables the **Delete** button while `peopleApi.isLoading` is true and + shows a spinner on the button. Closes the dialog and snackbars on + completion. + +Mount points: + +- The **Reset progress** button is rendered in the people **layout** when + `data.personId` is present (so it appears next to the back arrow and + refresh action). The dialog itself can live alongside it. + + Alternative: place the button inside the person `+page.svelte` next to + the hero card. Layout placement keeps the destructive action visually + grouped with the rest of the per-person actions and matches where the + back/refresh controls already are. + + Decision: **layout placement**, so the action is consistently positioned + for every person detail view. + +### 9. Translations + +Add the following keys to +`apps/dashboard/src/lib/utils/translations/en.json` (exact text TBD with +copy review): + +- `course.navItem.people.reset_progress.button` +- `course.navItem.people.reset_progress.dialog.title` +- `course.navItem.people.reset_progress.dialog.intro` +- `course.navItem.people.reset_progress.dialog.bullets.lessons` +- `course.navItem.people.reset_progress.dialog.bullets.exercises` +- `course.navItem.people.reset_progress.dialog.bullets.comments` +- `course.navItem.people.reset_progress.dialog.bullets.community` +- `course.navItem.people.reset_progress.dialog.bullets.video_progress` +- `course.navItem.people.reset_progress.dialog.bullets.attendance` +- `course.navItem.people.reset_progress.dialog.bullets.certificate` +- `course.navItem.people.reset_progress.dialog.warning` +- `course.navItem.people.reset_progress.dialog.cancel` +- `course.navItem.people.reset_progress.dialog.confirm` +- `snackbar.course.people.progress_reset` +- `snackbar.course.people.progress_reset_failed` + +Bullet copy uses `{count}` placeholders (e.g. *"Delete {count} exercise +submissions"*) and is fed from the analytics that already power the +person page. Per repo workflow, after editing `en.json` run `cd +apps/dashboard && pnpm translate` and review the generated locale files +to make sure `{count}` placeholders survived. + +## Authorization & Safety + +- **Auth**: the route is behind `courseTeamMemberMiddleware`. Only course + admins/tutors can call it. The UI button is gated by `RoleBasedSecurity + allowedRoles={[1, 2]}` to match. +- **Confirmation**: destructive action is gated behind a modal with an + explicit *"This cannot be undone."* warning and a *Delete* (not "OK") + action button. +- **Idempotency**: re-running the action on an already-cleared student is + a no-op (all `delete` queries simply match zero rows). +- **Atomicity**: all deletes happen inside one DB transaction. Either the + student's whole course state is cleared or nothing is. +- **Audit**: server logs `{ actorProfileId, courseId, memberId, summary + }` on every successful reset. We do not (in v1) write a new audit row; + if the team wants persistent auditing we can add a `course_audit_log` + later (see Future Work). + +## Testing + +- **Unit (`packages/db`)**: a Vitest test that seeds a course with two + students, fills in lessons completed / submissions / lesson comments / + newsfeed comments / certificate / completion record for both, calls + `resetStudentCourseProgress` for one, and asserts: + - The targeted student has 0 rows left in every affected table for this + course. + - The other student is **untouched**. + - Rows from a second course owned by the same student are **untouched**. + - `groupmember.certificate_earned_at` and `certification_email_sent_at` + are `NULL` for the targeted student in this course. + - `groupmember` row itself is still present. +- **Service**: returns 404 `AppError` when called with an unknown + `memberId` or with a member whose `profileId` is null. +- **API integration**: a request from a non-team member returns 403 via + the existing middleware; a request from an admin returns 200 and the + expected summary shape. +- **Dashboard (Playwright/manual)**: open a populated student profile, + click **Reset progress**, confirm the modal, verify analytics show + zeroed counts after refresh. + +## Future Work + +- Bulk reset across selected students. +- "Reset cycle only" mode for compliance courses with cycles — clear the + current cycle but keep prior `course_completion_record` rows for + history. +- Persistent audit log surfaced in the org admin panel. +- Granular reset (e.g. "only exercise submissions" or "only lesson + progress") if user research shows demand. From 0a6db37566685dad93e4d2b469c6fdb4eedcac28 Mon Sep 17 00:00:00 2001 From: Rotimi Best Date: Thu, 18 Jun 2026 09:56:45 +0100 Subject: [PATCH 2/6] docs(prd): add Zapier integration PRD (#667) * docs(prd): add Zapier integration PRD Draft PRD for Zapier integration with locked decisions on private-first distribution, Early Adopter+ plan gating, zapier:read/zapier:write scopes, polling-only triggers for v1, and apps/zapier app location. Covers trigger/action/search catalog, public API surface gaps, dashboard tab, and rollout plan. Co-authored-by: Rotimi Best * docs(prd): revise Zapier integration PRD with OAuth and binary plan gating Update PRD per planning decisions: - Auth: switch from API key paste to OAuth 2.0 (authorization_code + refresh_token) shipping in v1; drop type: 'zapier' from organization_api_key.type enum. - Plan gating: binary feature (Early Adopter+); no monthly Zapier credits, only per-minute rate limits. Plan downgrade revokes all grants immediately. - Invite link: single shared private invite URL (we want adoption). - Revoke UX: per-grant revoke in dashboard for safety net only; no bulk Disconnect button. - Triggers: drop program_completed from v1 (now 5 triggers); deferred to v2. - Add OAuth schema (oauth_authorization_code, oauth_access_token, oauth_refresh_token), routes, consent screen, plan-guard hook into license.ts. Co-authored-by: Rotimi Best --------- --- PRD-TRACKER.md | 1 + prd/zapier/README.md | 657 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 658 insertions(+) create mode 100644 prd/zapier/README.md diff --git a/PRD-TRACKER.md b/PRD-TRACKER.md index 2c66a11f..54d50b03 100644 --- a/PRD-TRACKER.md +++ b/PRD-TRACKER.md @@ -23,6 +23,7 @@ Use this file to keep a single prioritized view of all PRDs. | - | - | `prd/copy-page-as-markdown` | todo | | - | - | `prd/reset-student-course-progress` | todo | | - | 15 | `prd/webhooks` | todo | +| - | - | `prd/zapier` | draft | ## DONE (Completed PRDs) diff --git a/prd/zapier/README.md b/prd/zapier/README.md new file mode 100644 index 00000000..717097bc --- /dev/null +++ b/prd/zapier/README.md @@ -0,0 +1,657 @@ +# Zapier Integration PRD + +## Status + +- Draft + +## Purpose + +Ship a Zapier integration that lets non-engineering teams connect ClassroomIO to the tools they already use (CRMs, HRIS, Slack, spreadsheets, email platforms, ticketing) without writing code. The integration must work today against the existing public API and silently upgrade to real-time delivery as the webhooks platform lands. + +## Problem Statement + +ClassroomIO already exposes a versioned public REST API at `/public-api/v1/*` and ships an MCP server, but those surfaces only serve engineering teams. The customers who run training programs (HR, customer success, sales enablement) cannot: + +- Enroll learners automatically when a contact reaches a CRM stage. +- Sync course completions and certificates to HRIS, Drive, or BI warehouses. +- Trigger Slack/email workflows on learner activity. +- Connect ClassroomIO into the no-code stacks (Zapier, Make, n8n, Pipedream) that those teams already operate. + +The dashboard already advertises Zapier as an `Automation` tab (`/org/[slug]/automation/zapier`) and the automation-key system supports `type: 'zapier'`, but the page is a coming-soon callout and no Zapier app exists. We have customers who need this integration shipped now. + +## Confirmed Decisions + +These are locked before implementation begins: + +1. **Distribution**: ship as a private Zapier app via a single shared invite URL first; promote to the public Zapier directory after ~5 paying orgs are using it and v1 is stable. +2. **Plan gating**: Early Adopter+ only. Access is binary — either your plan includes Zapier or it doesn't. No monthly task credits. Per-minute rate limits still apply as abuse protection. +3. **Plan downgrade behavior**: hard cutoff. When an org drops below Early Adopter, all existing OAuth grants are revoked immediately. No grace period. +4. **Authentication**: OAuth 2.0 authorization code flow with refresh tokens, shipping in v1. No API-key-paste fallback for Zapier. Direct API consumers (Make, n8n, Pipedream, raw curl) keep using existing `type: 'api'` automation keys; Zapier exclusively uses OAuth. +5. **Scopes**: `zapier:read` and `zapier:write` exist as OAuth scopes. Zapier requests both at connection time; the consent screen lets admins downgrade to read-only. +6. **Triggers in v1**: polling only. No webhook dependency. Real-time REST Hooks ship in v1.1 once the webhooks PRD lands. +7. **Trigger scope**: org-wide by default, with optional `Course` and `Tag` dropdown filters per trigger. No separate per-course trigger duplicates. +8. **iPaaS parity**: the public REST API is the integration surface. Zapier connects via OAuth; Make / n8n / Pipedream can use OAuth too (all three support it) or `type: 'api'` keys for raw HTTP. The Zapier app is packaging only — no Zapier-specific endpoints or payloads. +9. **Repo location**: `apps/zapier`. The Zapier app is a deployable that gets `zapier push`-ed to Zapier's cloud. Nothing else in the monorepo imports from it, so it sits next to `apps/api` and `apps/dashboard` rather than in `packages/`. +10. **Revoke UX**: per-grant revoke is available in the dashboard for the safety-net case (compromised Zapier account, employee offboarding). No bulk "Disconnect Zapier" button — customers managing their integration normally do so from inside Zapier. + +## Current-State Audit + +| Capability | Current State | Notes | +| --- | --- | --- | +| Org-scoped automation keys | available | `organization_api_key` already supports `type: 'mcp' \| 'api' \| 'zapier'`. Rotation, revoke, last-used tracking all shipped. The `'zapier'` value becomes unused under the OAuth model (see Technical Design). | +| Bearer auth middleware | available | `automationKeyMiddleware` + `automationKeyScopesMiddleware` in `apps/api/src/middlewares/`. Will be extended to also accept OAuth access tokens. | +| OAuth 2.0 server | missing | No OAuth authorization-code flow exists on the API. Required for v1. | +| OAuth consent screen | missing | No dashboard consent screen for third-party app authorization. Required for v1. | +| Public REST API | partial | `/public-api/v1/courses` and `/public-api/v1/audience` shipped. Tags, announcements, certificates, course clone, full audience update still missing. | +| Test-connection endpoint | missing | No `GET /public-api/v1/me` for Zapier's auth-test step. | +| Polling cursor / since filter | missing | List endpoints support `page/limit` but no `?since=` or `?cursor=` for stable Zapier polling. | +| Email/slug search filters | missing | Audience list does not accept `?email=`; courses list does not accept `?slug=` or `?title=`. | +| Webhooks delivery | missing | `prd/webhooks/README.md` written but unshipped. Not a v1 dependency. | +| Dashboard Zapier tab | partial | `/org/[slug]/automation/zapier` route exists but renders a `coming_soon` callout. Will become an OAuth-grant management page, not a key-management page. | +| Automation usage tracking | available | `organization_automation_usage` already records `read \| write \| publish` per key. Will be extended to record per OAuth grant. | +| Plan gating utilities | available | `MCP_AUTOMATION_LIMITS_BY_PLAN` pattern in `packages/utils/src/plans/automation.ts` is the reference for Zapier rate limits. | +| Marketing positioning | partial | `apps/website/src/routes/automation/+page.svelte` advertises API + Webhooks + MCP. Does not yet mention Zapier. | + +## Data Sources Checked + +- `packages/db/src/schema.ts` (`organization_api_key`, `organization_automation_usage`) +- `packages/utils/src/validation/organization/automation-key.ts` +- `packages/utils/src/validation/public-api/audience.ts` +- `packages/utils/src/validation/public-api/course.ts` +- `packages/utils/src/plans/automation.ts` +- `apps/api/src/middlewares/automation-key.ts` +- `apps/api/src/middlewares/automation-key-scopes.ts` +- `apps/api/src/routes/v1/courses.ts` +- `apps/api/src/routes/v1/audience.ts` +- `apps/api/src/services/v1/course.ts` +- `apps/api/src/services/v1/audience.ts` +- `apps/api/src/services/organization/automation-key.ts` +- `apps/api/src/services/course/{invite,people,certificate,completion,clone,compliance}.ts` +- `apps/api/src/services/submission/submission.ts` +- `apps/api/src/services/newsfeed/newsfeed.ts` +- `apps/api/src/services/tag.ts` +- `apps/dashboard/src/lib/features/automation/pages/{mcp,zapier}.svelte` +- `apps/website/src/routes/automation/+page.svelte` +- `prd/public-api [DONE]/README.md` +- `prd/webhooks/README.md` + +## Product Goals + +1. An org admin can connect ClassroomIO from inside Zapier in under 60 seconds without copying or pasting any token. The flow is: click Connect on Zapier → log into ClassroomIO → consent → done. +2. Non-engineering customers can build the three canonical Zaps without code: + - CRM new customer → enroll in onboarding course. + - Certificate issued → upload to HRIS / Drive. + - Exercise submitted → notify tutor in Slack. +3. The Zapier app exposes a useful but small surface: 5 triggers, 5 actions, 2 searches in v1. +4. Same OAuth flow and REST endpoints work for Make, n8n, and Pipedream — they support OAuth natively, so no additional development is needed beyond the Zapier package. +5. Connected Zapier instances are visible to admins in the dashboard, with per-grant revoke for the safety-net case. +6. The integration is forward-compatible with webhooks: when REST Hooks become available, high-volume triggers (exercise submitted, lesson completed) upgrade with no UX change for the Zapier user. + +## Non-Goals (v1) + +1. Public listing in the Zapier directory (deferred until v1 is validated with ~5 customers). +2. Real-time triggers via REST Hooks (deferred to v1.1, gated on `prd/webhooks`). +3. High-volume triggers (`exercise.submitted`, `lesson.completed`) that are impractical on polling. +4. Make / n8n / Pipedream apps as separate packaged listings (the REST API + OAuth supports them; no curated app yet). +5. Free / Basic plan access (gated to Early Adopter+). +6. Inbound webhooks from Zapier to ClassroomIO (Zapier writes via REST actions, not webhooks). +7. Monthly task credits or Zapier-specific credit budgets (Zapier is a binary plan feature; per-minute rate limits remain for abuse protection only). +8. Custom triggers / dynamic events authored by the customer. +9. PKCE / device-code / implicit OAuth grants (only authorization_code + refresh_token grants ship in v1). +10. OAuth dynamic client registration (Zapier is a hard-coded confidential client; other iPaaS vendors are added by hand in v1). +11. Bulk "Disconnect Zapier" button in the dashboard (customers disconnect from Zapier's side; admins use per-grant revoke for safety-net cases). +12. Branding review and Zapier marketplace screenshots (post-private validation). + +## User Stories + +1. As an HR ops admin, I want a new hire in BambooHR to auto-enroll in the onboarding course so I don't manage a spreadsheet. +2. As a sales engineer, I want a HubSpot deal moving to "Customer" to enroll the buyer in the product training so onboarding starts on day zero. +3. As an L&D admin, I want every `certificate.issued` to upload a PDF to the employee's Google Drive folder so my audit trail lives in the source-of-truth. +4. As a tutor, I want every `exercise.submitted` for my course to DM me in Slack so I can grade quickly. +5. As a finance ops admin, I want every `payment_request.created` to create a HubSpot deal so I don't reconcile manually. +6. As an org admin, I want a Zapier-scoped key separate from my raw API keys so I can revoke Zapier without breaking my internal integrations. +7. As an org admin, I want my Zapier usage to count against the same plan limits as MCP and API so I'm not over-billed by tool sprawl. + +## UX Requirements + +### Dashboard Zapier Tab + +Route: `/org/[slug]/automation/zapier`. Diverges from the MCP page because Zapier authenticates via OAuth grants, not bearer keys. + +Required sections (top to bottom): + +1. **Admin permission callout** for non-admin users. +2. **Plan gating callout** for orgs below Early Adopter — copy "Upgrade to Early Adopter to use Zapier" with an upgrade CTA. No connect flow visible. +3. **"Connect on Zapier" CTA** linking to the shared private invite URL (later the public listing). +4. **Connected Zapier instances table** — one row per active OAuth grant. Columns: label (e.g. "Zapier — workspace abc.com"), scopes (`read` / `read+write`), last used, connected at, status. Row action: revoke. +5. **Rate limit summary** — current per-minute read and write caps for the org's plan. +6. **Setup guide** — step-by-step screenshots of the Connect flow from inside Zapier (click Connect → log in → consent → done). +7. **Docs callout** linking to `apps/docs` Zapier guide. + +Reuse where possible: + +- Read OAuth grants and usage via a new `automationOauth.svelte.ts` API class in `apps/dashboard/src/lib/features/automation/api/`. +- Shared types live in `apps/dashboard/src/lib/features/automation/utils/types.ts`. +- Replace the current placeholder in `apps/dashboard/src/lib/features/automation/pages/zapier.svelte`. + +### Consent Screen + +Route: `/oauth/consent` in the dashboard. Triggered by Zapier's `authorize` redirect. + +Behavior: + +1. If the user is not logged in, redirect to the existing login flow with a `redirect_to=/oauth/consent?...` parameter so they return here after auth. +2. Render the consenting org's name, the requesting app (Zapier), the requested scopes (`zapier:read`, `zapier:write`), and the redirect URI. +3. For multi-org users, show an org picker — only orgs where the user is admin AND the plan is Early Adopter+ appear. +4. Show two buttons: `Authorize` and `Deny`. On `Authorize`, the dashboard POSTs to the API to issue an authorization code, then redirects to Zapier's callback with `?code=…&state=…`. On `Deny`, redirects to Zapier's callback with `?error=access_denied&state=…`. +5. Admins can untick `zapier:write` on the consent screen to grant a read-only connection. + +### Zapier App UX + +The Zapier app surface, as seen by a Zap author: + +- **App name**: ClassroomIO +- **Auth flow**: OAuth 2.0. User clicks `Connect` in Zapier → Zapier opens our `/oauth/authorize` URL → user logs in (if needed) and consents → redirected back to Zapier with a code → Zapier exchanges for tokens silently. No copy-paste. +- **Test step**: after token exchange, Zapier calls `GET /public-api/v1/me` with the new access token. Shows `{org.name}` on Zapier's connections page. +- **Trigger picker** lists the 5 triggers below with one-line descriptions matching the website's voice. +- **Action picker** lists the 5 actions below. +- **Search picker** lists the 2 searches below. +- **Dynamic dropdowns**: + - `Course` dropdown is powered by `GET /public-api/v1/courses?fields=id,title&limit=100`. + - `Tag` dropdown is powered by `GET /public-api/v1/tags?limit=100` (new endpoint, see Technical Design). +- **Sample data**: every trigger ships a static sample record so Zap authors can build downstream steps without firing a real event. +- **Token refresh**: the Zapier app uses Zapier's built-in `refresh_token` handling — Zapier auto-refreshes access tokens via our `/oauth/token` endpoint when they expire. + +### Marketing Surface + +Update `apps/website/src/routes/automation/+page.svelte` and the home page automation band to mention Zapier alongside REST API + Webhooks + MCP. Add a `Connect via Zapier` row to the integrations section. Update the `automate-section.svelte` copy to name Zapier explicitly ("New hire joins BambooHR → enrolled via Zapier"). + +This marketing work is a follow-up PR after the integration is private-listed. Tracked in this PRD but does not gate v1 ship. + +## Trigger Catalog (v1) + +All triggers ship as polling. Each trigger emits `createdAt`-ordered records and dedupes by `id` on the Zapier side. + +| Trigger | Description | Source endpoint | Optional filters | +| --- | --- | --- | --- | +| `new_audience_member` | New student added to the organization audience | `GET /public-api/v1/audience?sortBy=createdAt&sortOrder=desc` | none | +| `student_enrolled_in_course` | A student was added to a course (invite accepted or direct add) | `GET /public-api/v1/audience/enrollments?sortBy=createdAt&sortOrder=desc` (new) | `courseId`, `tagId` | +| `course_completed` | A student completed all required lessons in a course | `GET /public-api/v1/course-completions?sortBy=completedAt&sortOrder=desc` (new) | `courseId`, `tagId` | +| `certificate_issued` | A certificate was issued for a learner | `GET /public-api/v1/certificates?sortBy=issuedAt&sortOrder=desc` (new) | `courseId` | +| `payment_request_created` | A learner submitted a payment request form | `GET /public-api/v1/payment-requests?sortBy=createdAt&sortOrder=desc` (new) | `courseId` | + +Deferred to v1.1 (require webhooks for sane volume / latency): + +- `exercise_submitted` +- `exercise_graded` +- `lesson_completed` +- `newsfeed_post_created` +- `community_question_created` +- `compliance_course_overdue` + +Deferred to v2 (no current customer ask): + +- `program_completed` + +## Action Catalog (v1) + +Each action is a thin Zapier wrapper over an existing or new public API write endpoint. + +| Action | Description | Endpoint | Scope | +| --- | --- | --- | --- | +| `enroll_student_in_course` | Find-or-create the student by email and assign to one or more courses | `POST /public-api/v1/audience` + `POST /public-api/v1/audience/assign-courses` | `zapier:write` | +| `add_student` | Create an audience member without course assignment | `POST /public-api/v1/audience` | `zapier:write` | +| `update_student` | Update audience member profile (name, email, custom attributes) | `PUT /public-api/v1/audience/:memberId` (extend payload schema) | `zapier:write` | +| `remove_student` | Remove a student from the organization | `DELETE /public-api/v1/audience/:memberId` | `zapier:write` | +| `tag_student` | Apply or remove a tag on an audience member | `POST /public-api/v1/audience/:memberId/tags` (new) | `zapier:write` | + +Deferred to v1.1 (need new public API routes that aren't critical-path): + +- `send_announcement` (newsfeed post) +- `issue_certificate` +- `clone_course_from_template` +- `publish_course_draft` (already an MCP tool; trivial to expose later) +- `create_payment_request` + +## Search Catalog (v1) + +| Search | Description | Endpoint | +| --- | --- | --- | +| `find_student_by_email` | Look up audience member by exact email | `GET /public-api/v1/audience?email=…` (new filter) | +| `find_course` | Look up a course by slug or title | `GET /public-api/v1/courses?slug=…` or `?title=…` (new filters) | + +Both searches power Zapier's find-or-create pattern; together with the create actions, Zapier auto-generates "Find or Create Student" and "Find or Create Course" steps with no extra Zapier app code. + +## Authentication and Scopes + +### OAuth 2.0 server (new) + +Implement the authorization_code + refresh_token grants from RFC 6749 only. No PKCE, implicit, device, or client_credentials grants in v1. Zapier is registered as a single confidential OAuth client. + +Endpoints (hosted on the API): + +| Endpoint | Method | Purpose | +| --- | --- | --- | +| `/oauth/authorize` | `GET` | Validates `client_id`, `redirect_uri`, `response_type=code`, `scope`, `state`. Redirects the browser to the dashboard consent screen `/oauth/consent`. | +| `/oauth/authorize/issue` | `POST` | Called by the dashboard consent screen after the admin clicks `Authorize`. Issues a single-use authorization code (TTL 60 seconds) bound to `org_id`, `client_id`, `scopes`, `redirect_uri`, and the consenting user. Returns the code to the dashboard, which redirects the browser to `redirect_uri?code=…&state=…`. | +| `/oauth/token` | `POST` | Exchanges an authorization code for an access token (TTL 1 hour) + refresh token (TTL 90 days). Also handles `grant_type=refresh_token`. | +| `/oauth/revoke` | `POST` | Revokes an access or refresh token (RFC 7009). | + +Library choice: lean on `oauth4webapi` or roll a minimal implementation. The scope is narrow enough that hand-rolling is reasonable; pick during implementation kickoff. + +### OAuth client registration + +Zapier client credentials are stored as environment variables, not in the database, in v1: + +- `ZAPIER_OAUTH_CLIENT_ID` +- `ZAPIER_OAUTH_CLIENT_SECRET` +- `ZAPIER_OAUTH_REDIRECT_URIS` (comma-separated list of allowed callbacks from Zapier's docs) + +A `packages/utils/src/oauth/clients.ts` resolver returns the registered clients keyed by `client_id`. Adding Make / n8n / Pipedream later is a config-only change. + +### Token storage + +New tables (see Technical Design): + +- `oauth_authorization_code` — short-lived single-use codes. +- `oauth_access_token` — hashed `Bearer` tokens. +- `oauth_refresh_token` — hashed long-lived tokens. + +Every token row carries: `id`, `client_id`, `organization_id`, `granted_by_profile_id`, `scopes`, `created_at`, `expires_at`, `revoked_at`, `last_used_at`. + +### Middleware integration + +Extend `automationKeyMiddleware` to a unified `bearerAuthMiddleware` that: + +1. Reads `Authorization: Bearer …`. +2. Tries to resolve the token as an OAuth access token (hash-and-lookup against `oauth_access_token`). If found and not expired or revoked, sets `c.set('orgId')`, `c.set('actorId', granted_by_profile_id)`, `c.set('authSource', 'oauth')`, `c.set('scopes', grant.scopes)`. +3. Falls back to the existing automation-key path (`organization_api_key`) for `type: 'api'` / `type: 'mcp'` consumers. +4. Returns 401 if neither path matches. + +This means existing API keys keep working unchanged for Make / n8n / Pipedream users who prefer raw bearer tokens. Zapier-only consumers go through OAuth. + +### Scopes + +Two OAuth scopes: + +- `zapier:read` — list, get, search on courses, audience, submissions, certificates, tags, completions, payment requests. +- `zapier:write` — create, update, delete on audience, course assignments, tags. + +Scope-to-route map: + +| Endpoint | Required scopes (OAuth) | Required scopes (API key fallback) | +| --- | --- | --- | +| `GET /public-api/v1/me` | `zapier:read` | `public_api:*` | +| All `GET /public-api/v1/*` triggers and searches | `zapier:read` | `public_api:*` | +| Audience / course / tag write endpoints | `zapier:write` | `public_api:*` | + +`automationKeyScopesMiddleware` is extended to check whichever scope set applies based on `c.get('authSource')`. + +### Dropping `type: 'zapier'` from API key types + +Under the OAuth model, the dashboard never issues Zapier API keys. Update `ZOrganizationApiKeyType` in `packages/utils/src/validation/organization/automation-key.ts` to remove `'zapier'`. Existing rows are zero (the dashboard tab has always been a placeholder), so no migration is needed beyond the schema/enum change. + +## Polling Contract + +Every list endpoint exposed to Zapier triggers must guarantee: + +1. **Stable sort**: `sortBy` and `sortOrder` defaulted to newest-first. +2. **Stable record ID**: each record returns an `id` that does not change across pages. +3. **`since` cursor**: accept an optional `?since=` query parameter so Zapier can request only records newer than the highest `createdAt` it has already seen. If `since` is absent, return the most recent page only. +4. **`limit` <= 100** with a default of 50. +5. **Idempotent**: identical query returns identical results within the polling window. + +Zapier polls every 1–15 minutes depending on the customer's Zapier plan. Our endpoints must remain cheap to poll under that cadence. + +## Future REST Hooks Upgrade Path + +When `prd/webhooks/README.md` ships, we add to the Zapier app: + +1. Replace the existing `subscribe` / `unsubscribe` no-ops with calls to the webhook management API (`POST /organization/webhooks` with a Zapier-managed endpoint). +2. Move the high-volume triggers (`exercise_submitted`, `lesson_completed`, `newsfeed_post_created`) to REST Hook mode and ship them in v1.1. +3. Keep the existing polling triggers as a fallback when the webhook URL is unreachable. + +This is a Zapier-app-only change in v1.1 — the public API surface does not change shape. + +## Plan Gating + +Zapier is a binary plan feature. No monthly credit budgets. + +Add `ZAPIER_AUTOMATION_LIMITS_BY_PLAN` to `packages/utils/src/plans/automation.ts`: + +| Plan | Zapier enabled | Max active grants | Per-org reads / min | Per-org writes / min | +| --- | --- | --- | --- | --- | +| Basic | no | 0 | 0 | 0 | +| Early Adopter | yes | 5 | 120 | 40 | +| Enterprise | yes | 25 | 360 | 120 | + +Enforcement points: + +1. **At `/oauth/authorize`**: reject the request with `error=access_denied` if the consenting org's plan does not include Zapier, or if `max active grants` is already reached. +2. **At `bearerAuthMiddleware`** for OAuth tokens: reject with 403 + `code: PLAN_GATED` if the org's plan has dropped below Early Adopter since the grant was issued. +3. **At route entry**: rate-limit against the per-minute caps using the existing rate-limiter middleware, keyed by `(org_id, scope_category)`. + +Usage tracking: every Zapier API call still increments `organization_automation_usage` with category `read` or `write` for visibility, but no credits are deducted. + +Plan downgrade flow: + +1. The plan-change service emits an internal event `organization.plan.changed`. +2. A handler in `apps/api/src/services/oauth/` checks whether the new plan disables Zapier. +3. If yes, revoke all active OAuth grants for the org by setting `revoked_at` on every related access and refresh token. +4. The dashboard Zapier tab then shows the plan-gating callout with an upgrade CTA. + +Basic / free plan users still see the dashboard Zapier tab so they understand the feature exists. The Connect CTA is replaced by an upgrade CTA. No connect link is rendered. + +## Technical Design + +### Schema additions + +In `packages/db/src/schema.ts`: + +1. `oauth_authorization_code` + - `id` (UUID, primary) + - `code_hash` (string, indexed unique) + - `client_id` (string) + - `organization_id` (UUID, FK) + - `granted_by_profile_id` (UUID, FK) + - `redirect_uri` (string) + - `scopes` (text[]) + - `created_at`, `expires_at` (60 s TTL) + - `consumed_at` (nullable; codes are single-use) +2. `oauth_access_token` + - `id` (UUID, primary) + - `token_hash` (string, indexed unique) + - `token_prefix` (first 6 chars for dashboard display) + - `client_id` + - `organization_id` (FK) + - `granted_by_profile_id` (FK) + - `refresh_token_id` (FK to `oauth_refresh_token`) + - `scopes` + - `created_at`, `expires_at` (1 h TTL) + - `revoked_at`, `last_used_at` +3. `oauth_refresh_token` + - `id` (UUID, primary) + - `token_hash` (string, indexed unique) + - `client_id` + - `organization_id` (FK) + - `granted_by_profile_id` (FK) + - `scopes` + - `label` (e.g., "Zapier — workspace abc.com" — derived from the Zapier callback URI host) + - `created_at`, `expires_at` (90 d TTL, sliding) + - `revoked_at`, `last_used_at` + +Remove `'zapier'` from the `organization_api_key.type` enum (no migration since no rows use it). + +### Validation Layer + +Add new files: + +- `packages/utils/src/validation/oauth/oauth.ts` — `ZOauthAuthorizeQuery`, `ZOauthIssueCodeBody`, `ZOauthTokenBody`, `ZOauthRevokeBody`, `ZOauthScope`. +- `packages/utils/src/validation/public-api/tag.ts` +- `packages/utils/src/validation/public-api/me.ts` +- `packages/utils/src/validation/public-api/enrollments.ts` +- `packages/utils/src/validation/public-api/completions.ts` +- `packages/utils/src/validation/public-api/certificates.ts` +- `packages/utils/src/validation/public-api/payment-requests.ts` + +Extend: + +- `packages/utils/src/validation/public-api/audience.ts` — accept `email` filter on `ZPublicApiAudienceQuery` and broaden `ZPublicApiUpdateAudience` to support full profile (name, locale, custom attributes). +- `packages/utils/src/validation/public-api/course.ts` — accept `slug` and `title` filters on the list query. +- `packages/utils/src/validation/organization/automation-key.ts` — remove `'zapier'` from `ZOrganizationApiKeyType`. The `'zapier:read'` / `'zapier:write'` scope strings live in the new OAuth scope enum, not in the automation-key scope enum. + +### Query Layer + +Add: + +- `packages/db/src/queries/oauth/authorization-code.ts` — issue, consume, expire. +- `packages/db/src/queries/oauth/access-token.ts` — issue, lookup by hash, revoke, touch `last_used_at`. +- `packages/db/src/queries/oauth/refresh-token.ts` — issue, lookup by hash, revoke, list active grants per org. +- `packages/db/src/queries/course/completions.ts` — list completions ordered by `completedAt` with `since` cursor. +- `packages/db/src/queries/course/certificates.ts` — list issued certificates with `since` cursor. +- `packages/db/src/queries/course/payment-requests.ts` — list payment requests with `since` cursor. +- `packages/db/src/queries/organization/me.ts` — read org + grant metadata for the test-connection endpoint. + +### Service Layer + +New services: + +- `apps/api/src/services/oauth/clients.ts` — load Zapier client config from env. +- `apps/api/src/services/oauth/authorize.ts` — validate authorize request, issue code on consent. +- `apps/api/src/services/oauth/token.ts` — exchange code for tokens, refresh tokens. +- `apps/api/src/services/oauth/revoke.ts` — revoke tokens. +- `apps/api/src/services/oauth/plan-guard.ts` — revoke all grants when an org drops below Early Adopter. +- `apps/api/src/services/v1/me.ts` +- `apps/api/src/services/v1/tag.ts` +- `apps/api/src/services/v1/enrollments.ts` +- `apps/api/src/services/v1/completions.ts` +- `apps/api/src/services/v1/certificates.ts` +- `apps/api/src/services/v1/payment-requests.ts` + +Extend `apps/api/src/services/v1/audience.ts` to handle the broadened `update` payload and the `tag/untag` action. + +Wire `oauth/plan-guard.ts` into the existing plan-change pathway in `apps/api/src/services/license.ts` so downgrades immediately revoke grants. + +### Middleware Layer + +- New: rename `automationKeyMiddleware` to `bearerAuthMiddleware` (or wrap it) so it tries OAuth tokens first, then falls back to `organization_api_key`. +- Extend `automationKeyScopesMiddleware` to honor `c.get('authSource')` and check OAuth scopes vs API-key scopes accordingly. + +### Route Layer + +New OAuth routes (mounted at the API root, not under `/public-api`): + +- `GET /oauth/authorize` +- `POST /oauth/authorize/issue` (called by the dashboard consent screen with session auth, not bearer) +- `POST /oauth/token` +- `POST /oauth/revoke` + +New public API routes (all under `/public-api/v1`): + +- `GET /public-api/v1/me` +- `GET /public-api/v1/audience/enrollments` +- `GET /public-api/v1/course-completions` +- `GET /public-api/v1/certificates` +- `GET /public-api/v1/payment-requests` +- `GET /public-api/v1/tags` +- `POST /public-api/v1/audience/:memberId/tags` +- `DELETE /public-api/v1/audience/:memberId/tags/:tagId` + +Public API routes follow the existing v1 pattern: `bearerAuthMiddleware` + `automationKeyScopesMiddleware` + `describeRoute` + `validator`. Each route returns a single response type per the routing rules in `AGENTS.md`. + +### Dashboard Routes + +New routes: + +- `apps/dashboard/src/routes/(app)/oauth/consent/+page.svelte` — consent screen. +- `apps/dashboard/src/routes/(app)/oauth/consent/+page.server.ts` — load consent context (client, scopes, redirect URI, eligible orgs). + +Replace: + +- `apps/dashboard/src/lib/features/automation/pages/zapier.svelte` — new OAuth grant management page. +- `apps/dashboard/src/routes/(app)/org/[slug]/zapier/+page.svelte` and any associated `+page.server.ts` — hydrate grants list and rate-limit data. + +New API class: + +- `apps/dashboard/src/lib/features/automation/api/automation-oauth.svelte.ts` — list grants, revoke a grant, consent action. + +### Zapier App (`apps/zapier`) + +New workspace package: + +``` +apps/zapier/ +├── package.json +├── tsconfig.json +├── index.ts # Zapier app entry +├── authentication.ts +├── triggers/ +│ ├── new-audience-member.ts +│ ├── student-enrolled.ts +│ ├── course-completed.ts +│ ├── certificate-issued.ts +│ ├── payment-request-created.ts +│ └── program-completed.ts +├── creates/ # Zapier name for "actions" +│ ├── enroll-student-in-course.ts +│ ├── add-student.ts +│ ├── update-student.ts +│ ├── remove-student.ts +│ └── tag-student.ts +├── searches/ +│ ├── find-student-by-email.ts +│ └── find-course.ts +├── utils/ +│ └── client.ts # shared fetch wrapper, base URL, headers +└── test/ + └── *.test.ts +``` + +Dependencies (not introduced into root): + +- `zapier-platform-core` (Zapier-required runtime). +- `@cio/utils` for typed payload schemas via workspace protocol. + +Build/release flow: + +- `pnpm --filter @cio/zapier build` — typechecks the app. +- `pnpm --filter @cio/zapier zapier:push` — uploads to Zapier under a private app version. +- `pnpm --filter @cio/zapier zapier:promote` — manual step to promote a tested version. + +No CI auto-push. Promotion is a manual step gated on the on-call engineer. + +## API and Docs + +1. Every new `/public-api/v1/*` route added under this PRD is annotated with `describeRoute` so it lands in the existing OpenAPI generator. +2. Run `pnpm --filter @cio/api upload:openapi` after route additions. +3. Add a Zapier guide in `apps/docs`: + - Connecting your account (create key in dashboard, paste in Zapier). + - Trigger catalog with sample payloads. + - Action catalog with required fields. + - Search catalog. + - Rate limits and plan limits. + - Troubleshooting (key revoked, scope missing, plan downgrade). +4. Update `apps/website/src/routes/automation/+page.svelte` to add a Zapier section alongside REST API + Webhooks + MCP. Include the canonical Zaps as copy. +5. Add a `Connect on Zapier` button to `apps/website/src/lib/components/automate-section.svelte`. + +## Rollout Plan + +### Phase 1: OAuth server foundation + +1. Schema: `oauth_authorization_code`, `oauth_access_token`, `oauth_refresh_token`. +2. Queries, services, validation for OAuth. +3. Routes: `/oauth/authorize`, `/oauth/authorize/issue`, `/oauth/token`, `/oauth/revoke`. +4. Extend `bearerAuthMiddleware` to resolve OAuth tokens before falling back to automation keys. +5. Add `zapier:read` / `zapier:write` scope enforcement to `automationKeyScopesMiddleware`. +6. Plan-guard hook into `license.ts` for downgrade revocation. +7. Drop `'zapier'` from `organization_api_key.type` enum. + +### Phase 2: Consent screen + dashboard + +1. Build `/oauth/consent` page in the dashboard with org picker, scope-edit, Authorize / Deny. +2. Replace `pages/zapier.svelte` placeholder with the OAuth grant management page. +3. Add `automation.zapier.*` translations (followed by `pnpm translate`). +4. Plan-gating callout for Basic plan. + +### Phase 3: Public API surface + +1. Add `GET /public-api/v1/me`. +2. Extend audience update payload + add `?email=` filter. +3. Add course list `?slug=` / `?title=` filters. +4. Add tag list + tag/untag audience endpoints. +5. Add `enrollments`, `course-completions`, `certificates`, `payment-requests` list endpoints with `?since=` cursors. +6. Build and upload OpenAPI spec. + +### Phase 4: Zapier app + +1. Scaffold `apps/zapier` with `zapier-platform-core` configured for OAuth 2.0. +2. Implement triggers, creates, searches against the public API. +3. Add dynamic dropdowns powered by `/courses` and `/tags`. +4. Add sample data for each trigger. +5. `zapier push` private app version 1.0.0. + +### Phase 5: Private validation + +1. Distribute the shared private invite URL to paying orgs. +2. Collect usage data via `organization_automation_usage`. +3. Iterate on copy, scopes UX, and field defaults based on Zap author feedback. +4. Update docs and marketing. + +### Phase 6: Public listing + +1. Submit to Zapier directory review. +2. Promote app version once approved. +3. Update marketing site and announce. + +### Phase 7 (v1.1): REST Hooks upgrade + +1. Wait for `prd/webhooks` ship. +2. Wire `subscribe` / `unsubscribe` to the webhook management API. +3. Promote `exercise_submitted`, `lesson_completed`, `newsfeed_post_created` to instant triggers. + +### Phase 8 (v2): Programs, more actions, more iPaaS apps + +1. Add `program_completed` trigger and `apps/zapier` integration. +2. Add `send_announcement`, `issue_certificate`, `clone_course_from_template`, `publish_course_draft`, `create_payment_request` actions. +3. Register Make / n8n / Pipedream as additional OAuth clients (config-only). +4. Consider native Make and Pipedream packages if customers ask. + +## Success Metrics + +1. >= 5 orgs connect a Zapier key within 30 days of private invite. +2. >= 100 Zap runs/week within 60 days of private invite. +3. p95 trigger latency under 5 minutes on the Early Adopter plan (Zapier polling cadence). +4. < 2% of Zap runs fail due to API errors (excluding user misconfiguration). +5. >= 80% of connected orgs use at least one trigger and one action (i.e., the integration is bidirectional, not one-way data export). +6. Zero security incidents related to leaked or misused Zapier keys. + +## Risks and Mitigations + +1. **OAuth server is a new attack surface.** + - Mitigation: keep the implementation minimal (authorization_code + refresh_token only). Hash tokens at rest. Single-use authorization codes with 60-second TTL. Server-side scope validation. Add OAuth-specific security tests. Run a security review of the implementation before public listing. +2. **Polling latency dissatisfies customers expecting real-time.** + - Mitigation: set expectation in dashboard and docs ("delivered within ~5 minutes on polling, instant after webhooks v1.1"). Prioritize webhooks PRD ship. +3. **`exercise_submitted` demand on polling.** + - Mitigation: do not ship it in v1. Document that it lands with v1.1 / webhooks. +4. **Zapier's marketplace review rejects public listing.** + - Mitigation: stay private until v1 is polished. Use private validation period to fix UX issues Zapier reviewers commonly flag (sample data, error messages, dropdown UX, OAuth flow edge cases). +5. **Plan gating frustrates Basic users who see the tab but cannot use it.** + - Mitigation: clear upgrade CTA copy, and a docs link explaining why Zapier sits on Early Adopter+. +6. **Plan downgrade silently revokes grants and breaks live Zaps.** + - Mitigation: surface a banner in the dashboard 7 days before a known billing-driven downgrade fires (where the billing system gives notice). For immediate downgrades, send a notification email naming each revoked grant and the Zaps that may be affected. +7. **Drift between Zapier app schema and public API schema.** + - Mitigation: `apps/zapier` consumes types from `@cio/utils/validation/public-api` directly so a schema change at the API breaks the Zapier build at CI time. +8. **Shared private invite URL leaks publicly.** + - Mitigation: enforce plan gating at the `/oauth/authorize` step regardless of who clicks Connect. Leakage of the invite URL is harmless because the OAuth flow still verifies the user is an admin of an Early Adopter+ org. + +## Build and Verification Commands + +1. `pnpm --filter @cio/utils build` +2. `pnpm --filter @cio/db build` +3. `pnpm --filter @cio/api build` +4. `pnpm --filter @cio/api upload:openapi` +5. `pnpm --filter @cio/dashboard build` +6. `pnpm --filter @cio/zapier build` +7. `pnpm --filter @cio/zapier zapier:push` (manual, gated) + +Manual verification: + +1. Install the Zapier app via the private invite URL while logged out — confirm Zapier prompts for ClassroomIO login during the OAuth handshake. +2. Complete the OAuth flow as an org admin on Early Adopter — confirm `Test Connection` in Zapier shows the org name returned by `GET /public-api/v1/me`. +3. Try the OAuth flow as a non-admin of the same org — confirm `Authorize` is hidden or disabled and Deny redirects with `error=access_denied`. +4. Try the OAuth flow on a Basic-plan org — confirm `/oauth/authorize` rejects with the upgrade CTA visible. +5. Untick `zapier:write` on the consent screen — confirm the resulting token only allows read endpoints and `403`s on write endpoints. +6. Build a Zap: `New audience member` → Slack message. Trigger by adding an audience member; receive Slack message within 5 minutes. +7. Build a Zap: HubSpot deal → `Enroll student in course`. Add a deal; confirm the audience member appears and is assigned. +8. Build a Zap: `Certificate issued` → Google Drive upload. Issue a cert; confirm the file appears. +9. Revoke the grant from the dashboard; confirm all three Zaps surface authentication errors on next run and Zapier shows a re-connect prompt. +10. Downgrade the org to Basic; confirm the dashboard tab shows the upgrade CTA, the existing grants are revoked immediately, and Zaps fail with a `PLAN_GATED` error. +11. Force an access token expiry; confirm Zapier transparently refreshes via `/oauth/token` without user interaction. + +## Open Questions + +1. Should we use `oauth4webapi` (lighter, OAuth-spec-compliant), `node-oauth2-server` (heavier but battle-tested), or hand-roll the minimal authorization_code + refresh_token grants? Decide at implementation kickoff. +2. Refresh-token rotation strategy: rotate on every refresh (safer, more complex) or keep the same refresh token across refreshes (simpler, Zapier-compatible)? Zapier supports both — confirm with Zapier docs during build. +3. Should the consent screen support cross-org consent in a single screen (one Zapier connection covers multiple orgs), or strictly one OAuth grant per org? v1 is one grant per org; cross-org is a v2 question if multi-org admins ask for it. +4. Where do we display `last_used_at` for a grant? Inside the dashboard grants table only, or also in an email digest? v1 is dashboard-only. +5. Do we expose any OAuth telemetry (token issue / refresh / revoke counts) to the internal admin tooling, or rely on database queries on demand? From 5320f1eb44b958c52a1fe59e827a07010c8dd447 Mon Sep 17 00:00:00 2001 From: Rotimi Best Date: Fri, 19 Jun 2026 14:50:37 +0100 Subject: [PATCH 3/6] fix(dashboard): use verified custom domain for view-as-student handoff (#677) * fix(dashboard): use verified custom domain for view-as-student handoff Prefer the org's verified custom domain over window.location.origin when resolving the public tenant host. This prevents admin URLs like app.example.com from being used for the student login-link handoff when the org's public site is example.com. Co-authored-by: Rotimi Best * fix(dashboard): keep self-hosted org origin on window.location Self-hosted deployments serve admin and LMS from the same URL, so getOrgPublicOrigin should always return window.location.origin there rather than preferring a configured custom domain. Co-authored-by: Rotimi Best --------- Co-authored-by: Cursor Agent Co-authored-by: Rotimi Best --- .../features/course/utils/course-preview.ts | 6 ++- apps/dashboard/src/lib/utils/store/org.ts | 37 +++++++++++++------ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/apps/dashboard/src/lib/features/course/utils/course-preview.ts b/apps/dashboard/src/lib/features/course/utils/course-preview.ts index a32a6f9e..023be090 100644 --- a/apps/dashboard/src/lib/features/course/utils/course-preview.ts +++ b/apps/dashboard/src/lib/features/course/utils/course-preview.ts @@ -1,7 +1,9 @@ +import { get } from 'svelte/store'; import { goto } from '$app/navigation'; import { resolve } from '$app/paths'; import { snackbar } from '$features/ui/snackbar/store'; import { accountApi } from '$features/account/api/account.svelte'; +import { currentOrg, getOrgPublicOrigin } from '$lib/utils/store/org'; interface OpenCoursePreviewOptions { courseId: string; @@ -21,7 +23,7 @@ export function getPublicCoursePageUrl(courseSlug: string, currentOrgDomain = '' } const trimmedDomain = currentOrgDomain?.trim(); - const origin = trimmedDomain || window.location.origin; + const origin = trimmedDomain || getOrgPublicOrigin(get(currentOrg)); return new URL(resolve(`/course/${courseSlug}`, {}), origin).toString(); } @@ -73,7 +75,7 @@ export async function viewAsStudent({ courseId, currentOrgDomain = '' }: ViewAsS return false; } - const origin = currentOrgDomain?.trim() || window.location.origin; + const origin = currentOrgDomain?.trim() || getOrgPublicOrigin(get(currentOrg)); const loginLinkUrl = new URL('/api/auth/login-link', origin); loginLinkUrl.searchParams.set('token', token); loginLinkUrl.searchParams.set('redirect', `/courses/${courseId}/lessons?next=true`); diff --git a/apps/dashboard/src/lib/utils/store/org.ts b/apps/dashboard/src/lib/utils/store/org.ts index 2c5f758d..2fdf0349 100644 --- a/apps/dashboard/src/lib/utils/store/org.ts +++ b/apps/dashboard/src/lib/utils/store/org.ts @@ -77,19 +77,34 @@ export const currentOrgPath = derived(currentOrg, ($currentOrg) => $currentOrg.siteName ? `/org/${$currentOrg.siteName}` : '#' ); -export const currentOrgDomain = derived(currentOrg, ($currentOrg) => { - if (PUBLIC_IS_SELFHOSTED === 'true') return window.location.origin; +type OrgPublicOrigin = Pick; - const browserOrigin = dev && browser && window.location.origin; +/** + * Public origin for an org's tenant site (student LMS, public course pages, login-link handoff). + * Self-hosted uses the current deployment URL. On cloud, verified custom domains win over the + * admin host so `app.classroomio.com` still hands off to the org's `example.com` tenant site. + */ +export function getOrgPublicOrigin(org: OrgPublicOrigin): string { + if (PUBLIC_IS_SELFHOSTED === 'true') { + return browser ? window.location.origin : ''; + } - return browserOrigin - ? browserOrigin - : $currentOrg.customDomain && $currentOrg.isCustomDomainVerified - ? `https://${$currentOrg.customDomain}` - : $currentOrg.siteName - ? `https://${$currentOrg.siteName}.${TENANT_ROOT_DOMAIN}` - : ''; -}); + if (org.customDomain && org.isCustomDomainVerified) { + return `https://${org.customDomain}`; + } + + if (dev && browser) { + return window.location.origin; + } + + if (org.siteName) { + return `https://${org.siteName}.${TENANT_ROOT_DOMAIN}`; + } + + return browser ? window.location.origin : ''; +} + +export const currentOrgDomain = derived(currentOrg, ($currentOrg) => getOrgPublicOrigin($currentOrg)); export const isFreePlan = derived(currentOrg, ($currentOrg) => { if (!$currentOrg.id || PUBLIC_IS_SELFHOSTED === 'true') return false; From 3547901de662fe2e271ac99ecacee3dba018147c Mon Sep 17 00:00:00 2001 From: Rotimi Best Date: Sun, 21 Jun 2026 17:42:02 +0100 Subject: [PATCH 4/6] fix(dashboard): redirect students on app domain to org LMS (#675) * fix(dashboard): redirect students on app domain to org LMS When a student logs in on app.classroomio.com, send them to their org tenant domain with a full page reload instead of staying on /lms at the app host. Org sites and self-hosted installs keep the existing behavior. Students who explicitly open /onboarding while already belonging to an org are no longer redirected away, so they can still create their own academy with the same email. Co-authored-by: Rotimi Best * refactor(dashboard): use getOrgPublicUrl instead of duplicate helper Main added getOrgPublicOrigin for tenant URLs; extend it with getOrgPublicUrl for path-based redirects and drop the parallel getOrgSiteUrl helper from org utils. Co-authored-by: Rotimi Best --------- --- .../src/lib/features/app/init.svelte.ts | 20 ++++++++++++++++--- apps/dashboard/src/lib/utils/store/org.ts | 20 +++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/apps/dashboard/src/lib/features/app/init.svelte.ts b/apps/dashboard/src/lib/features/app/init.svelte.ts index 9d35ffe9..2be743d2 100644 --- a/apps/dashboard/src/lib/features/app/init.svelte.ts +++ b/apps/dashboard/src/lib/features/app/init.svelte.ts @@ -1,5 +1,5 @@ import { BaseApi, classroomio } from '$lib/utils/services/api'; -import { currentOrg, mergeAccountOrgFromServer, orgs } from '$lib/utils/store/org'; +import { currentOrg, getOrgPublicUrl, mergeAccountOrgFromServer, orgs } from '$lib/utils/store/org'; import { defaultProfileState, defaultUserState, profile, user } from '$lib/utils/store/user'; import type { AccountResponse } from './types'; @@ -201,12 +201,26 @@ class AppInitApi extends BaseApi { if (!shouldRedirectOnAuth(page.url.pathname)) return; + // Students with existing org memberships who open /onboarding may intend to create their own academy. + if (path.includes('/onboarding') && isStudent && userHasOrganizations) { + return; + } + const shouldGoToLMS = isCloud ? isOrgSite || !!isStudent : !!isStudent; console.log('redirecting to', shouldGoToLMS ? 'lms' : 'org'); - return shouldGoToLMS ? this.goToLMS() : this.goToOrg(); + return shouldGoToLMS ? this.goToLMS(isOrgSite) : this.goToOrg(); } - goToLMS() { + goToLMS(isOrgSite: boolean) { + const isCloud = PUBLIC_IS_SELFHOSTED !== 'true'; + const isStudent = get(isOrgStudent); + const selectedOrg = get(currentOrg); + + if (isCloud && !isOrgSite && isStudent && selectedOrg.siteName) { + window.location.href = getOrgPublicUrl(selectedOrg, '/lms'); + return; + } + goto(resolve('/lms', {})); } diff --git a/apps/dashboard/src/lib/utils/store/org.ts b/apps/dashboard/src/lib/utils/store/org.ts index 2fdf0349..d26ad994 100644 --- a/apps/dashboard/src/lib/utils/store/org.ts +++ b/apps/dashboard/src/lib/utils/store/org.ts @@ -104,6 +104,26 @@ export function getOrgPublicOrigin(org: OrgPublicOrigin): string { return browser ? window.location.origin : ''; } +/** Absolute URL on an org's public tenant site (e.g. `/lms`, `/course/{slug}`). Client-only. */ +export function getOrgPublicUrl(org: OrgPublicOrigin, pathname = '/'): string { + if (!browser) { + return pathname; + } + + const origin = getOrgPublicOrigin(org); + if (!origin) { + return pathname; + } + + const url = new URL(pathname, origin); + + if (window.location.host.includes('localhost') && org.siteName) { + url.searchParams.set('org', org.siteName); + } + + return url.toString(); +} + export const currentOrgDomain = derived(currentOrg, ($currentOrg) => getOrgPublicOrigin($currentOrg)); export const isFreePlan = derived(currentOrg, ($currentOrg) => { From 81294a47f9a877e370b1ec13aced1cb17d6650b8 Mon Sep 17 00:00:00 2001 From: Rotimi Best Date: Mon, 22 Jun 2026 05:43:48 +0100 Subject: [PATCH 5/6] feat: live class sessions, CE workflow, and docs (#683) Adds live-class session scheduling on lessons (join link, date/time, timezone) with automatic 24h and 1h reminder emails plus a calendar invite (.ics), a time-change notification with an updated invite, a teacher-authored welcome email and session invite on enrollment, and a "Notify students" quiz nudge. LMS gets an upcoming live-sessions card and Join buttons, plus a reusable live-session card component (3 states) in @cio/ui with a Storybook story. The sidebar content tree now reflects sequential progression locking like the content list, and the course-completion confetti regression is fixed. Org-based emails no longer reference ClassroomIO by name. Docs add live-class, welcome-email, and course-progression guides, expand the certificates guide (design, signatures, corrected labels), move plan-required callouts to the top, flatten how-to-guides to the docs root with redirects, and add screenshots. Includes an add-docs-image skill. --- .gitignore | 9 +- .slim.yaml | 6 - PRD-TRACKER.md | 2 + README.md | 2 +- apps/api/src/routes/course/course.ts | 8 + apps/api/src/routes/course/exercise.ts | 28 ++ apps/api/src/routes/course/lesson.ts | 19 + apps/api/src/routes/internal/compliance.ts | 10 + apps/api/src/services/course/invite.ts | 51 ++- .../src/services/course/notify-exercise.ts | 90 ++++ .../api/src/services/course/notify-session.ts | 16 + .../src/services/course/payment-request.ts | 13 +- apps/api/src/services/course/people.ts | 26 +- .../api/src/services/course/session-invite.ts | 37 ++ apps/api/src/services/jobs/email-jobs.ts | 5 +- apps/api/src/services/newsfeed/newsfeed.ts | 18 +- .../api/src/services/organization/audience.ts | 35 +- apps/api/src/services/organization/invite.ts | 13 +- apps/api/src/services/program/goal.ts | 8 +- .../api/src/services/submission/submission.ts | 121 ++--- apps/api/src/utils/course-completion.ts | 9 +- apps/dashboard/README.md | 2 +- .../features/course/api/exercise.svelte.ts | 70 +++ .../ceritficate/certificate-settings.svelte | 1 + .../course-completion-modal.svelte | 71 ++- .../unlocked-certificate.svelte | 37 +- .../course/components/course-header.svelte | 20 +- .../components/exercise/edit-mode.svelte | 2 +- .../components/exercise/view-mode.svelte | 18 +- .../components/lesson/content-list.svelte | 2 +- .../lesson/content-navigation-actions.svelte | 18 +- .../components/lesson/content-row.svelte | 13 + .../lesson/content-section-list.svelte | 2 +- .../lesson/lesson-settings-tab.svelte | 238 ++++++++-- .../lesson/live-session-card.svelte | 35 ++ .../sidebar/course-content-tree.svelte | 23 +- .../lib/features/course/pages/exercise.svelte | 23 +- .../lib/features/course/pages/lesson.svelte | 17 +- .../lib/features/course/pages/settings.svelte | 132 ++++-- .../course/store/course-completion-modal.ts | 18 +- .../course/utils/certificate-utils.ts | 41 ++ .../features/course/utils/settings-store.ts | 4 +- .../components/upcoming-sessions-card.svelte | 56 +++ .../lib/features/lms/pages/dashboard.svelte | 63 ++- .../lib/features/settings/components/index.ts | 1 + .../org-settings-inline-tabs.svelte | 52 +++ .../lib/features/settings/pages/org.svelte | 53 +-- .../lib/features/settings/pages/teams.svelte | 119 ++--- .../src/lib/features/settings/utils/store.ts | 14 + .../lib/features/ui/navigation/breadcrumb.ts | 18 +- .../features/ui/navigation/org-navigation.ts | 28 +- .../src/lib/features/ui/question/grade.svelte | 5 + .../dashboard/src/lib/utils/functions/date.ts | 35 ++ .../src/lib/utils/functions/metaTags.ts | 14 +- .../src/lib/utils/translations/da.json | 74 ++- .../src/lib/utils/translations/de.json | 74 ++- .../src/lib/utils/translations/en.json | 73 ++- .../src/lib/utils/translations/es.json | 76 +++- .../src/lib/utils/translations/fr.json | 74 ++- .../src/lib/utils/translations/hi.json | 74 ++- .../src/lib/utils/translations/pl.json | 74 ++- .../src/lib/utils/translations/pt.json | 74 ++- .../src/lib/utils/translations/ru.json | 74 ++- .../src/lib/utils/translations/vi.json | 74 ++- .../(app)/org/[slug]/settings/+layout.svelte | 36 +- .../settings/customize-lms/+page.svelte | 42 +- .../org/[slug]/settings/domains/+page.svelte | 34 +- .../org/[slug]/settings/org/+page.svelte | 40 +- .../org/[slug]/settings/teams/+page.svelte | 34 +- apps/dashboard/src/routes/+page.svelte | 2 +- apps/docs/app/root.tsx | 29 +- apps/docs/app/routes/docs.tsx | 9 +- apps/docs/content/docs/audience.mdx | 14 +- apps/docs/content/docs/certificates.mdx | 100 ++++ apps/docs/content/docs/community.mdx | 2 +- .../{how-to-guides => }/course-enrollment.mdx | 15 +- .../course-landingpage.mdx | 18 +- apps/docs/content/docs/course-progression.mdx | 103 +++++ .../docs/{how-to-guides => }/course-types.mdx | 9 +- apps/docs/content/docs/course.mdx | 18 +- .../{how-to-guides => }/create-exercise.mdx | 24 +- .../create-first-course.mdx | 0 .../{how-to-guides => }/custom-domain.mdx | 10 +- .../customize-organization.mdx | 10 +- .../{how-to-guides => }/grade-exercise.mdx | 4 +- apps/docs/content/docs/home.mdx | 2 +- .../docs/how-to-guides/certificates.mdx | 64 --- .../docs/content/docs/how-to-guides/meta.json | 17 - .../{how-to-guides => }/invite-students.mdx | 8 +- .../invite-team-member.mdx | 12 +- apps/docs/content/docs/live-class.mdx | 112 +++++ apps/docs/content/docs/meta.json | 33 +- .../{how-to-guides => }/org-landing-page.mdx | 16 +- apps/docs/content/docs/organization.mdx | 22 +- apps/docs/content/docs/programs.mdx | 4 +- apps/docs/content/docs/quickstart/signup.mdx | 2 +- .../roles-and-permissions.mdx | 10 +- apps/docs/content/docs/student-dashboard.mdx | 8 +- .../{how-to-guides => }/take-attendance.mdx | 4 +- .../use-math-in-editor.mdx | 0 apps/docs/content/docs/welcome-email.mdx | 61 +++ .../public/certificates-design-editor.webp | Bin 0 -> 33274 bytes apps/docs/public/certificates-rules.webp | Bin 0 -> 37630 bytes .../docs/public/certificates-signatories.webp | Bin 0 -> 38922 bytes .../public/certificates-student-download.webp | Bin 0 -> 23422 bytes apps/docs/public/live-class-change-time.webp | Bin 0 -> 27510 bytes apps/docs/public/live-class-lms-card.webp | Bin 0 -> 36048 bytes .../public/live-class-session-settings.webp | Bin 0 -> 44036 bytes apps/docs/public/live-class-student-card.webp | Bin 0 -> 37182 bytes apps/docs/public/notify-students-menu.webp | Bin 0 -> 48972 bytes apps/docs/public/progression-cant-skip.webp | Bin 0 -> 49778 bytes .../public/progression-completion-rule.webp | Bin 0 -> 49922 bytes apps/docs/public/progression-locked.webp | Bin 0 -> 24094 bytes apps/docs/public/progression-mode.webp | Bin 0 -> 34940 bytes .../progression-student-course-complete.webp | Bin 0 -> 60296 bytes apps/docs/public/welcome-email-editor.webp | Bin 0 -> 24400 bytes apps/docs/public/welcome-email-preview.webp | Bin 0 -> 54840 bytes apps/docs/vite.config.ts | 7 +- apps/jobs/package.json | 2 + apps/jobs/src/index.ts | 3 +- apps/jobs/src/processors/emails/send.ts | 3 +- .../src/processors/notifications/index.ts | 3 + .../notifications/notify-course-exercise.ts | 56 +++ .../notifications/notify-session-update.ts | 104 +++++ .../notifications/session-reminder-scan.ts | 102 +++++ apps/jobs/src/workers/notifications.ts | 102 +++++ apps/website/README.md | 2 +- apps/website/src/app.html | 12 +- apps/website/src/routes/+layout.ts | 20 +- .../static/classroomio-opengraph-image.jpg | Bin 0 -> 532443 bytes .../static/classroomio-opengraph-image.webp | Bin 0 -> 241298 bytes packages/ai-assistant/src/prompt/teacher.ts | 9 +- .../core/src/services/agent/chat-context.ts | 4 +- .../core/src/services/agent/chat-tools.ts | 30 +- packages/core/src/services/course/course.ts | 4 +- packages/db/src/queries/course/course.ts | 43 +- packages/db/src/queries/course/index.ts | 1 + packages/db/src/queries/course/invite.ts | 6 +- packages/db/src/queries/course/session.ts | 161 +++++++ packages/db/src/queries/newsfeed/newsfeed.ts | 9 +- packages/db/src/queries/program/goal.ts | 10 +- packages/db/src/schema.ts | 4 + packages/email/src/core/base.ts | 3 +- packages/email/src/core/branding.ts | 86 ++++ packages/email/src/core/types.ts | 2 + packages/email/src/emails/index.ts | 13 + packages/email/src/emails/invite-teacher.ts | 6 +- packages/email/src/emails/newsfeed.ts | 11 +- .../email/src/emails/program-goal-reminder.ts | 8 +- packages/email/src/emails/quiz-assigned.ts | 30 ++ packages/email/src/emails/session.ts | 61 +++ .../src/emails/student-course-completion.ts | 6 +- .../email/src/emails/student-course-invite.ts | 6 +- .../src/emails/student-course-welcome.ts | 19 +- .../email/src/emails/student-org-invite.ts | 6 +- .../src/emails/student-program-welcome.ts | 8 +- .../email/src/emails/student-prove-payment.ts | 6 +- .../email/src/emails/submission-graded.ts | 54 +++ .../email/src/emails/submission-received.ts | 30 ++ .../src/emails/teacher-course-welcome.ts | 6 +- .../src/emails/teacher-student-buy-request.ts | 6 +- .../src/emails/teacher-student-joined.ts | 6 +- packages/email/src/ics.ts | 91 ++++ packages/email/src/index.ts | 3 + packages/email/src/send.ts | 3 +- packages/email/src/templates/default.ts | 43 +- packages/email/src/utils/constants.ts | 5 + .../email/src/utils/services/nodemailer.ts | 5 +- .../email/src/utils/services/zeptomail.ts | 15 +- packages/jobs/src/enqueue/index.ts | 1 + packages/jobs/src/enqueue/notifications.ts | 51 +++ packages/jobs/src/payloads/emails.ts | 4 +- packages/jobs/src/payloads/index.ts | 1 + packages/jobs/src/payloads/notifications.ts | 49 ++ packages/jobs/src/queues/index.ts | 1 + packages/jobs/src/queues/job-state.ts | 56 +++ packages/jobs/src/queues/names.ts | 5 + .../live-session-card.stories.svelte | 87 ++++ packages/ui/README.md | 4 + packages/ui/src/base/button/button.svelte | 1 + .../ui/src/custom/live-session-card/index.ts | 2 + .../live-session-card.svelte | 293 ++++++++++++ packages/ui/src/custom/moving-icons/index.ts | 1 + .../ui/src/custom/moving-icons/radio.svelte | 91 ++++ .../simple-logo-nav/simple-logo-nav.svelte | 4 +- packages/ui/src/output.css | 2 +- .../utils/src/validation/course/course.ts | 2 + packages/utils/src/validation/mail/mail.ts | 4 +- pnpm-lock.yaml | 77 ++++ pnpm-workspace.yaml | 1 + prd/embed-link-platforms.md | 341 ++++++++++++++ prd/super-admin/README.md | 430 ++++++++++++++++++ skills/add-docs-image/SKILL.md | 99 ++++ 193 files changed, 5477 insertions(+), 805 deletions(-) delete mode 100644 .slim.yaml create mode 100644 apps/api/src/services/course/notify-exercise.ts create mode 100644 apps/api/src/services/course/notify-session.ts create mode 100644 apps/api/src/services/course/session-invite.ts create mode 100644 apps/dashboard/src/lib/features/course/components/lesson/live-session-card.svelte create mode 100644 apps/dashboard/src/lib/features/lms/components/upcoming-sessions-card.svelte create mode 100644 apps/dashboard/src/lib/features/settings/components/org-settings-inline-tabs.svelte create mode 100644 apps/docs/content/docs/certificates.mdx rename apps/docs/content/docs/{how-to-guides => }/course-enrollment.mdx (94%) rename apps/docs/content/docs/{how-to-guides => }/course-landingpage.mdx (73%) create mode 100644 apps/docs/content/docs/course-progression.mdx rename apps/docs/content/docs/{how-to-guides => }/course-types.mdx (86%) rename apps/docs/content/docs/{how-to-guides => }/create-exercise.mdx (72%) rename apps/docs/content/docs/{how-to-guides => }/create-first-course.mdx (100%) rename apps/docs/content/docs/{how-to-guides => }/custom-domain.mdx (83%) rename apps/docs/content/docs/{how-to-guides => }/customize-organization.mdx (88%) rename apps/docs/content/docs/{how-to-guides => }/grade-exercise.mdx (92%) delete mode 100644 apps/docs/content/docs/how-to-guides/certificates.mdx delete mode 100644 apps/docs/content/docs/how-to-guides/meta.json rename apps/docs/content/docs/{how-to-guides => }/invite-students.mdx (92%) rename apps/docs/content/docs/{how-to-guides => }/invite-team-member.mdx (90%) create mode 100644 apps/docs/content/docs/live-class.mdx rename apps/docs/content/docs/{how-to-guides => }/org-landing-page.mdx (78%) rename apps/docs/content/docs/{how-to-guides => }/roles-and-permissions.mdx (84%) rename apps/docs/content/docs/{how-to-guides => }/take-attendance.mdx (86%) rename apps/docs/content/docs/{how-to-guides => }/use-math-in-editor.mdx (100%) create mode 100644 apps/docs/content/docs/welcome-email.mdx create mode 100644 apps/docs/public/certificates-design-editor.webp create mode 100644 apps/docs/public/certificates-rules.webp create mode 100644 apps/docs/public/certificates-signatories.webp create mode 100644 apps/docs/public/certificates-student-download.webp create mode 100644 apps/docs/public/live-class-change-time.webp create mode 100644 apps/docs/public/live-class-lms-card.webp create mode 100644 apps/docs/public/live-class-session-settings.webp create mode 100644 apps/docs/public/live-class-student-card.webp create mode 100644 apps/docs/public/notify-students-menu.webp create mode 100644 apps/docs/public/progression-cant-skip.webp create mode 100644 apps/docs/public/progression-completion-rule.webp create mode 100644 apps/docs/public/progression-locked.webp create mode 100644 apps/docs/public/progression-mode.webp create mode 100644 apps/docs/public/progression-student-course-complete.webp create mode 100644 apps/docs/public/welcome-email-editor.webp create mode 100644 apps/docs/public/welcome-email-preview.webp create mode 100644 apps/jobs/src/processors/notifications/index.ts create mode 100644 apps/jobs/src/processors/notifications/notify-course-exercise.ts create mode 100644 apps/jobs/src/processors/notifications/notify-session-update.ts create mode 100644 apps/jobs/src/processors/notifications/session-reminder-scan.ts create mode 100644 apps/jobs/src/workers/notifications.ts create mode 100644 apps/website/static/classroomio-opengraph-image.jpg create mode 100644 apps/website/static/classroomio-opengraph-image.webp create mode 100644 packages/db/src/queries/course/session.ts create mode 100644 packages/email/src/core/branding.ts create mode 100644 packages/email/src/emails/quiz-assigned.ts create mode 100644 packages/email/src/emails/session.ts create mode 100644 packages/email/src/emails/submission-graded.ts create mode 100644 packages/email/src/emails/submission-received.ts create mode 100644 packages/email/src/ics.ts create mode 100644 packages/jobs/src/enqueue/notifications.ts create mode 100644 packages/jobs/src/payloads/notifications.ts create mode 100644 packages/jobs/src/queues/job-state.ts create mode 100644 packages/storybook/src/molecules/live-session-card/live-session-card.stories.svelte create mode 100644 packages/ui/src/custom/live-session-card/index.ts create mode 100644 packages/ui/src/custom/live-session-card/live-session-card.svelte create mode 100644 packages/ui/src/custom/moving-icons/radio.svelte create mode 100644 prd/embed-link-platforms.md create mode 100644 prd/super-admin/README.md create mode 100644 skills/add-docs-image/SKILL.md diff --git a/.gitignore b/.gitignore index 33844035..892c0eec 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,11 @@ company/ # Claude Code local artifacts .claude/skills -.claude/scheduled_tasks.lock \ No newline at end of file +.claude/scheduled_tasks.lock + +# Local db-agent playground (not committed) +apps/db-agent + +# Generated htpasswd files (hashes are safe to store in secrets/CI, plaintext never committed) +.htpasswd +*.htpasswd \ No newline at end of file diff --git a/.slim.yaml b/.slim.yaml deleted file mode 100644 index b3f9cda2..00000000 --- a/.slim.yaml +++ /dev/null @@ -1,6 +0,0 @@ -services: - - domain: cio-fe - port: 5173 - - domain: cio-be - port: 3002 -log_mode: minimal diff --git a/PRD-TRACKER.md b/PRD-TRACKER.md index 54d50b03..b0c3a2cb 100644 --- a/PRD-TRACKER.md +++ b/PRD-TRACKER.md @@ -6,6 +6,8 @@ Use this file to keep a single prioritized view of all PRDs. | Rank | List # | PRD | Status | | --- | --- | --- | --- | +| - | - | `prd/super-admin` | draft | +| - | - | `prd/embed-link-platforms` | draft | | 1 | - | `prd/notification-system` | todo | | 2 | 14 | `prd/course-templates` | todo | | 3 | 5 | `prd/course-import` | todo | diff --git a/README.md b/README.md index 8509e3c9..9ee8966c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ - ClassroomIO is a no-code tool that allows you build and scale your online bootcamp with ease. + ClassroomIO is a no-code tool that allows you build and scale your online bootcamp with ease.

ClassroomIO.com

The Open Source Learning Management System for Companies diff --git a/apps/api/src/routes/course/course.ts b/apps/api/src/routes/course/course.ts index 548ca958..efdd7c90 100644 --- a/apps/api/src/routes/course/course.ts +++ b/apps/api/src/routes/course/course.ts @@ -35,6 +35,7 @@ import { courseAiTutorRouter } from '@api/routes/course/ai-tutor'; import { authMiddleware } from '@api/middlewares/auth'; import { authOrAutomationKeyMiddleware } from '@api/middlewares/auth-or-automation-key'; import { cloneCourse } from '@api/services/course/clone'; +import { sanitizeHtml } from '@cio/core/utils/sanitize-html'; import { complianceRouter } from '@api/routes/course/compliance'; import { contentRouter } from '@api/routes/course/content'; import { courseMemberMiddleware } from '@api/middlewares/course-member'; @@ -329,6 +330,13 @@ export const courseRouter = new Hono() const validatedData = c.req.valid('json'); const { tagIds, ...courseData } = validatedData; + if (courseData.metadata?.welcomeEmailMessage) { + courseData.metadata = { + ...courseData.metadata, + welcomeEmailMessage: sanitizeHtml(courseData.metadata.welcomeEmailMessage) + }; + } + const result = await updateCourse(courseId, courseData); if (tagIds !== undefined) { diff --git a/apps/api/src/routes/course/exercise.ts b/apps/api/src/routes/course/exercise.ts index 4533a1e8..11dd10a9 100644 --- a/apps/api/src/routes/course/exercise.ts +++ b/apps/api/src/routes/course/exercise.ts @@ -29,8 +29,14 @@ import { initVideoRecordingUpload } from '@api/services/exercise/video-recording'; +import { + getNotifyCourseExerciseStatusService, + notifyCourseExerciseService +} from '@api/services/course/notify-exercise'; + import { Hono } from '@api/utils/hono'; import { authMiddleware } from '@api/middlewares/auth'; +import { courseTeamMemberMiddleware } from '@api/middlewares/course-team-member'; import { authOrAutomationKeyMiddleware } from '@api/middlewares/auth-or-automation-key'; import { courseMemberMiddleware } from '@api/middlewares/course-member'; import { courseMemberOrAutomationKeyMiddleware } from '@api/middlewares/course-member-or-automation-key'; @@ -82,6 +88,28 @@ export const exerciseRouter = new Hono() return handleError(c, error, 'Failed to fetch exercise submissions overview'); } }) + .post('/:exerciseId/notify', authMiddleware, courseTeamMemberMiddleware, async (c) => { + try { + const courseId = c.req.param('courseId')!; + const exerciseId = c.req.param('exerciseId')!; + + const result = await notifyCourseExerciseService(courseId, exerciseId); + return c.json({ success: true, data: result }, 202); + } catch (error) { + return handleError(c, error, 'Failed to notify students'); + } + }) + .get('/:exerciseId/notify/:jobId', authMiddleware, courseTeamMemberMiddleware, async (c) => { + try { + const jobId = c.req.param('jobId')!; + const pollCount = Number.parseInt(c.req.query('pollCount') ?? '0', 10) || 0; + + const envelope = await getNotifyCourseExerciseStatusService(jobId, pollCount); + return c.json({ success: true, data: envelope }, 200); + } catch (error) { + return handleError(c, error, 'Failed to fetch notification status'); + } + }) .get( '/:exerciseId', authOrAutomationKeyMiddleware, diff --git a/apps/api/src/routes/course/lesson.ts b/apps/api/src/routes/course/lesson.ts index b2278924..fc33ed03 100644 --- a/apps/api/src/routes/course/lesson.ts +++ b/apps/api/src/routes/course/lesson.ts @@ -38,6 +38,8 @@ import { Hono } from '@api/utils/hono'; import { ZLessonDownloadContent } from '@cio/utils/validation/course'; import { authMiddleware } from '@api/middlewares/auth'; import { courseMemberMiddleware } from '@api/middlewares/course-member'; +import { courseTeamMemberMiddleware } from '@api/middlewares/course-team-member'; +import { notifyCourseSessionUpdateService } from '@api/services/course/notify-session'; import { generateLessonPdf } from '@api/utils/lesson'; import { getGroupMemberIdByCourseAndProfile } from '@cio/db/queries/group'; import { handleError } from '@api/utils/errors'; @@ -121,6 +123,23 @@ export const lessonRouter = new Hono() } } ) + .post( + '/:lessonId/notify-session-update', + authMiddleware, + courseTeamMemberMiddleware, + zValidator('param', ZLessonGetParam), + async (c) => { + try { + const courseId = c.req.param('courseId')!; + const { lessonId } = c.req.valid('param'); + + const result = await notifyCourseSessionUpdateService(courseId, lessonId); + return c.json({ success: true, data: result }, 202); + } catch (error) { + return handleError(c, error, 'Failed to notify session update'); + } + } + ) .delete('/:lessonId', authMiddleware, courseMemberMiddleware, zValidator('param', ZLessonGetParam), async (c) => { try { const { lessonId } = c.req.valid('param'); diff --git a/apps/api/src/routes/internal/compliance.ts b/apps/api/src/routes/internal/compliance.ts index 86774517..59d42a41 100644 --- a/apps/api/src/routes/internal/compliance.ts +++ b/apps/api/src/routes/internal/compliance.ts @@ -3,9 +3,19 @@ import { runProgramGoalEvaluationSweep, runProgramGoalReminderScan } from '@api/ import { Hono } from '@api/utils/hono'; import { apiKeyMiddleware } from '@api/middlewares/api-key'; +import { enqueueSessionReminderScan } from '@cio/jobs'; import { handleError } from '@api/utils/errors'; export const internalComplianceRouter = new Hono() + .post('/send-session-reminders', apiKeyMiddleware, async (c) => { + try { + const jobId = await enqueueSessionReminderScan(); + + return c.json({ success: true, data: { jobId: jobId ?? null } }, 200); + } catch (error) { + return handleError(c, error, 'Failed to enqueue session reminder scan'); + } + }) .post('/check-expiry', apiKeyMiddleware, async (c) => { try { const data = await runComplianceExpiryCheck(); diff --git a/apps/api/src/services/course/invite.ts b/apps/api/src/services/course/invite.ts index 400ed6e3..b25a1b35 100644 --- a/apps/api/src/services/course/invite.ts +++ b/apps/api/src/services/course/invite.ts @@ -29,11 +29,12 @@ import crypto from 'node:crypto'; import { getDashboardBaseUrl } from '@cio/core/config/dashboard-url'; import { getCourseTeachers } from '@cio/db/queries/course/people'; import { getProfileById } from '@cio/db/queries/auth'; -import { buildEmailFromName } from '@cio/email'; +import { buildEmailFromName, buildEmailBranding, type EmailBranding } from '@cio/email'; import { enqueueTransactionalEmail } from '@api/services/jobs'; import { getProfileByEmail, markUserAndProfileEmailVerified } from '@cio/db/queries/auth'; import { generateSlug } from '@cio/utils/functions'; import { ensureComplianceEnrollmentRecordsForProfiles } from './compliance'; +import { getWelcomeSessionIcs } from './session-invite'; import { db } from '@cio/db/drizzle'; import { trackServerEvent, SERVER_EVENTS } from '@cio/analytics'; @@ -358,20 +359,26 @@ async function sendStudentJoinEmails(input: { courseName: string; orgName: string; org: OrgUrlInfo; + branding: EmailBranding; studentId: string; studentEmail: string; + welcomeEmailMessage?: string | null; }) { try { const loginUrl = getDashboardBaseUrl(input.org); + const ics = await getWelcomeSessionIcs(input.courseId); await enqueueTransactionalEmail('studentCourseWelcome', { to: input.studentEmail, fields: { orgName: input.orgName, courseName: input.courseName, - loginUrl + loginUrl, + customMessage: input.welcomeEmailMessage ?? undefined, + branding: input.branding }, from: buildEmailFromName(`${input.orgName} (via ClassroomIO.com)`), - idempotencyKey: `course-welcome:${input.courseId}:${input.studentId}` + idempotencyKey: `course-welcome:${input.courseId}:${input.studentId}`, + ics }); } catch (error) { console.error('Failed to enqueue student welcome email:', error); @@ -395,7 +402,8 @@ async function sendStudentJoinEmails(input: { fields: { courseName: input.courseName, studentName, - studentEmail: input.studentEmail + studentEmail: input.studentEmail, + branding: input.branding }, from: buildEmailFromName('ClassroomIO'), idempotencyKey: `teacher-student-joined:${input.courseId}:${input.studentId}` @@ -414,6 +422,7 @@ async function createEmailInviteAndSend(input: { courseName: string; courseSlug: string; org: OrgUrlInfo; + branding: EmailBranding; metadata?: Record; shouldSend: boolean; }) { @@ -450,7 +459,8 @@ async function createEmailInviteAndSend(input: { orgName: input.orgName, courseName: input.courseName, inviteLink: createdInvite.inviteLink, - expiresAt: getExpiryLabel(createdInvite.expiresAt) + expiresAt: getExpiryLabel(createdInvite.expiresAt), + branding: input.branding }, from: buildEmailFromName(`${input.orgName} (via ClassroomIO.com)`), idempotencyKey: `course-invite-email:${createdInvite.id}` @@ -549,6 +559,11 @@ export async function createStudentInvite(courseId: string, createdByProfileId: const orgName = courseOrgData.orgName || 'ClassroomIO'; const courseName = courseOrgData.courseTitle || course[0].title || 'Course'; + const orgBranding = buildEmailBranding({ + name: courseOrgData.orgName, + avatarUrl: courseOrgData.orgAvatarUrl, + theme: courseOrgData.orgTheme + }); const inviteResults = await Promise.all( recipients.valid.map((recipientEmail) => @@ -561,6 +576,7 @@ export async function createStudentInvite(courseId: string, createdByProfileId: courseName, courseSlug, org: orgUrlInfo, + branding: orgBranding, metadata: data.metadata, shouldSend: data.sendEmail }) @@ -630,7 +646,8 @@ export async function enrollInCourse( throw new AppError('This course is not available for enrollment', ErrorCodes.VALIDATION_ERROR, 400); } - const courseMetadata = (courseWithRelations.metadata as { allowNewStudent?: boolean } | null) ?? null; + const courseMetadata = + (courseWithRelations.metadata as { allowNewStudent?: boolean; welcomeEmailMessage?: string | null } | null) ?? null; const isInternalEnrollmentOnly = org.settings?.internalEnrollmentOnly ?? false; const orgMemberId = await getOrganizationMemberIdByOrgAndProfile(org.id, user.id); @@ -677,8 +694,10 @@ export async function enrollInCourse( courseName: title, orgName: org.name, org: { siteName: org.siteName, customDomain: org.customDomain, isCustomDomainVerified: org.isCustomDomainVerified }, + branding: buildEmailBranding({ name: org.name, avatarUrl: org.avatarUrl, theme: org.theme }), studentId: user.id, - studentEmail: normalizedEmail + studentEmail: normalizedEmail, + welcomeEmailMessage: courseMetadata?.welcomeEmailMessage }); trackServerEvent({ @@ -944,7 +963,9 @@ export async function acceptStudentInvite(token: string, user: TAuthUser, contex orgName: organization.name, orgSiteName: organization.siteName, orgCustomDomain: organization.customDomain, - orgIsCustomDomainVerified: organization.isCustomDomainVerified + orgIsCustomDomainVerified: organization.isCustomDomainVerified, + orgAvatarUrl: organization.avatarUrl, + orgTheme: organization.theme }; } @@ -1025,7 +1046,11 @@ export async function acceptStudentInvite(token: string, user: TAuthUser, contex orgName: organization.name, orgSiteName: organization.siteName, orgCustomDomain: organization.customDomain, - orgIsCustomDomainVerified: organization.isCustomDomainVerified + orgIsCustomDomainVerified: organization.isCustomDomainVerified, + orgAvatarUrl: organization.avatarUrl, + orgTheme: organization.theme, + welcomeEmailMessage: + (course.metadata as { welcomeEmailMessage?: string | null } | null)?.welcomeEmailMessage ?? null }; }); @@ -1041,8 +1066,14 @@ export async function acceptStudentInvite(token: string, user: TAuthUser, contex customDomain: result.orgCustomDomain, isCustomDomainVerified: result.orgIsCustomDomainVerified }, + branding: buildEmailBranding({ + name: result.orgName, + avatarUrl: result.orgAvatarUrl, + theme: result.orgTheme + }), studentId: user.id, - studentEmail: normalizedEmail + studentEmail: normalizedEmail, + welcomeEmailMessage: result.welcomeEmailMessage }); trackServerEvent({ diff --git a/apps/api/src/services/course/notify-exercise.ts b/apps/api/src/services/course/notify-exercise.ts new file mode 100644 index 00000000..e52b223d --- /dev/null +++ b/apps/api/src/services/course/notify-exercise.ts @@ -0,0 +1,90 @@ +import { AppError, ErrorCodes } from '@api/utils/errors'; +import { getCourseById, getCourseWithOrgData } from '@cio/db/queries/course'; +import { getExerciseById } from '@cio/db/queries/exercise'; +import { getDashboardBaseUrl } from '@cio/core/config/dashboard-url'; +import { buildEmailFromName, buildEmailBranding } from '@cio/email'; +import { QUEUE_NAMES, enqueueNotifyCourseExercise, getQueueJobEnvelope, type JobEnvelope } from '@cio/jobs'; + +const NOTIFY_DOMAIN = 'notify-course-exercise'; + +/** + * Enqueue a background job that emails every course member a "quiz assigned" + * nudge with a deep link to take the exercise. Returns the job id the + * dashboard polls for completion. + */ +export async function notifyCourseExerciseService(courseId: string, exerciseId: string): Promise<{ jobId: string }> { + const [courseRows, orgData, exercise] = await Promise.all([ + getCourseById(courseId), + getCourseWithOrgData(courseId), + getExerciseById(exerciseId) + ]); + + const course = courseRows?.[0]; + + if (!course) { + throw new AppError('Course not found', ErrorCodes.NOT_FOUND, 404); + } + + if (!orgData) { + throw new AppError('Course organization not found', ErrorCodes.NOT_FOUND, 404); + } + + if (!exercise || exercise.courseId !== courseId) { + throw new AppError('Exercise not found for this course', ErrorCodes.NOT_FOUND, 404); + } + + const baseUrl = getDashboardBaseUrl({ + siteName: orgData.orgSiteName, + customDomain: orgData.orgCustomDomain, + isCustomDomainVerified: orgData.orgIsCustomDomainVerified + }); + + // PUBLIC courses are taken on the anonymous slug-based org-site route; + // every other type uses the authenticated id-based LMS route. + let quizUrl: string; + if (course.type === 'PUBLIC') { + if (!course.slug || !exercise.slug) { + throw new AppError('Public course/exercise is missing a slug to link to', ErrorCodes.VALIDATION_ERROR, 400); + } + + quizUrl = `${baseUrl}/course/${course.slug}/lesson/${exercise.slug}`; + } else { + quizUrl = `${baseUrl}/courses/${courseId}/exercises/${exerciseId}`; + } + + const orgName = orgData.orgName || 'ClassroomIO'; + + const jobId = await enqueueNotifyCourseExercise({ + courseId, + exerciseTitle: exercise.title, + courseName: course.title, + orgName, + fromName: buildEmailFromName(`${orgName} (via ClassroomIO.com)`), + quizUrl, + branding: buildEmailBranding({ + name: orgData.orgName, + avatarUrl: orgData.orgAvatarUrl, + theme: orgData.orgTheme + }) + }); + + if (!jobId) { + throw new AppError('Failed to enqueue notification job', ErrorCodes.INTERNAL_ERROR, 500); + } + + return { jobId }; +} + +/** + * Read the status of a notify job (BullMQ-backed envelope). Throws 404 if the + * job is gone (retention swept it). + */ +export async function getNotifyCourseExerciseStatusService(jobId: string, pollCount = 0): Promise { + const envelope = await getQueueJobEnvelope(QUEUE_NAMES.notifications, jobId, NOTIFY_DOMAIN, pollCount); + + if (!envelope) { + throw new AppError('Notification job not found', ErrorCodes.NOT_FOUND, 404); + } + + return envelope; +} diff --git a/apps/api/src/services/course/notify-session.ts b/apps/api/src/services/course/notify-session.ts new file mode 100644 index 00000000..abe0ce36 --- /dev/null +++ b/apps/api/src/services/course/notify-session.ts @@ -0,0 +1,16 @@ +import { AppError, ErrorCodes } from '@api/utils/errors'; +import { enqueueNotifyCourseSessionUpdate } from '@cio/jobs'; + +/** + * Enqueue a background job that emails every course member an updated calendar + * invite after a teacher changes a live session. Returns the job id. + */ +export async function notifyCourseSessionUpdateService(courseId: string, lessonId: string): Promise<{ jobId: string }> { + const jobId = await enqueueNotifyCourseSessionUpdate({ courseId, lessonId }); + + if (!jobId) { + throw new AppError('Failed to enqueue session update notification', ErrorCodes.INTERNAL_ERROR, 500); + } + + return { jobId }; +} diff --git a/apps/api/src/services/course/payment-request.ts b/apps/api/src/services/course/payment-request.ts index cad8120b..828a642d 100644 --- a/apps/api/src/services/course/payment-request.ts +++ b/apps/api/src/services/course/payment-request.ts @@ -2,7 +2,7 @@ import { AppError, ErrorCodes } from '@api/utils/errors'; import { getCourseTeachers } from '@cio/db/queries/course/people'; import { getCourseWithOrgData } from '@cio/db/queries/course'; -import { buildEmailFromName } from '@cio/email'; +import { buildEmailFromName, buildEmailBranding } from '@cio/email'; import { enqueueTransactionalEmail } from '@api/services/jobs'; import { trackServerEvent, SERVER_EVENTS } from '@cio/analytics'; @@ -27,6 +27,11 @@ export async function createPaymentRequest(data: PaymentRequestData) { const courseName = course.courseTitle || ''; const orgName = course.orgName || 'ClassroomIO'; + const branding = buildEmailBranding({ + name: course.orgName, + avatarUrl: course.orgAvatarUrl, + theme: course.orgTheme + }); const groupId = course.groupId; if (!groupId) { @@ -48,7 +53,8 @@ export async function createPaymentRequest(data: PaymentRequestData) { fields: { courseName, studentEmail: data.studentEmail, - studentFullname: data.studentFullname + studentFullname: data.studentFullname, + branding }, from: buildEmailFromName('ClassroomIO'), idempotencyKey: `payment-request:teacher:${data.courseId}:${data.studentEmail}` @@ -64,7 +70,8 @@ export async function createPaymentRequest(data: PaymentRequestData) { courseName, teacherEmail, studentFullname: data.studentFullname, - orgName + orgName, + branding }, from: buildEmailFromName(`${orgName} - ClassroomIO`), replyTo: teacherEmail, diff --git a/apps/api/src/services/course/people.ts b/apps/api/src/services/course/people.ts index 98b81cab..8c725788 100644 --- a/apps/api/src/services/course/people.ts +++ b/apps/api/src/services/course/people.ts @@ -14,9 +14,10 @@ import type { TGroupmember } from '@cio/db/types'; import { getDashboardBaseUrl } from '@cio/core/config/dashboard-url'; import { getCourseWithOrgData } from '@cio/db/queries/course'; import { getProfileById } from '@cio/db/queries/auth'; -import { buildEmailFromName } from '@cio/email'; +import { buildEmailFromName, buildEmailBranding } from '@cio/email'; import { enqueueTransactionalEmail } from '@api/services/jobs'; import { ensureComplianceEnrollmentRecordsForProfiles } from './compliance'; +import { getWelcomeSessionIcs } from './session-invite'; /** * Gets all course members (people) for a course @@ -68,6 +69,11 @@ export async function addMember( if (courseOrgData) { const courseName = courseOrgData.courseTitle || ''; const orgName = courseOrgData.orgName || 'ClassroomIO'; + const branding = buildEmailBranding({ + name: courseOrgData.orgName, + avatarUrl: courseOrgData.orgAvatarUrl, + theme: courseOrgData.orgTheme + }); const loginUrl = getDashboardBaseUrl({ siteName: courseOrgData.orgSiteName, customDomain: courseOrgData.orgCustomDomain, @@ -97,10 +103,13 @@ export async function addMember( fields: { orgName, courseName, - loginUrl + loginUrl, + customMessage: courseOrgData.welcomeEmailMessage ?? undefined, + branding }, from: buildEmailFromName(`${orgName} (via ClassroomIO.com)`), - idempotencyKey: `course-people-student-welcome:${courseId}:${studentEmail}` + idempotencyKey: `course-people-student-welcome:${courseId}:${studentEmail}`, + ics: await getWelcomeSessionIcs(courseId) }); } catch (emailError) { console.error('Failed to enqueue student welcome email:', emailError); @@ -119,7 +128,8 @@ export async function addMember( fields: { courseName, studentName, - studentEmail + studentEmail, + branding }, from: buildEmailFromName('ClassroomIO'), idempotencyKey: `course-people-teacher-joined:${courseId}:${studentEmail}` @@ -182,6 +192,11 @@ export async function addMembers(courseId: string, members: TAddCourseMembers) { const courseName = courseOrgData.courseTitle || ''; const orgName = courseOrgData.orgName || 'ClassroomIO'; const orgSiteName = courseOrgData.orgSiteName || ''; + const branding = buildEmailBranding({ + name: courseOrgData.orgName, + avatarUrl: courseOrgData.orgAvatarUrl, + theme: courseOrgData.orgTheme + }); // Add all members const addedMembers = await Promise.all(members.map((member) => addCourseMember(courseId, member))); @@ -217,7 +232,8 @@ export async function addMembers(courseId: string, members: TAddCourseMembers) { name, orgName, courseName, - inviteLink + inviteLink, + branding }, from: buildEmailFromName(`${orgName} (via ClassroomIO.com)`), idempotencyKey: `teacher-course-welcome:${courseId}:${email}` diff --git a/apps/api/src/services/course/session-invite.ts b/apps/api/src/services/course/session-invite.ts new file mode 100644 index 00000000..2a752b65 --- /dev/null +++ b/apps/api/src/services/course/session-invite.ts @@ -0,0 +1,37 @@ +import { getCourseById, getUpcomingSessionsForCourseIds } from '@cio/db/queries/course'; +import { buildSessionIcs } from '@cio/email'; + +/** + * Build the calendar invite (.ics) for a course's next upcoming live session, + * for attaching to the welcome email on enrollment. Returns undefined when the + * course is not a LIVE_CLASS or has no upcoming session. The invite reuses the + * same UID as the session reminders, so calendars treat them as one event. + */ +export async function getWelcomeSessionIcs(courseId: string): Promise { + try { + const courseRows = await getCourseById(courseId); + const course = courseRows?.[0]; + if (!course || course.type !== 'LIVE_CLASS') { + return undefined; + } + + const upcoming = (await getUpcomingSessionsForCourseIds([courseId])).get(courseId); + if (!upcoming) { + return undefined; + } + + return buildSessionIcs({ + uid: `session-${upcoming.lessonId}@classroomio`, + sequence: 0, + method: 'PUBLISH', + start: upcoming.lessonAt, + title: upcoming.lessonTitle, + description: `Join your live session: ${upcoming.callUrl}`, + url: upcoming.callUrl, + alarmsBeforeMinutes: [1440, 60] + }); + } catch (error) { + console.error('getWelcomeSessionIcs error:', error); + return undefined; + } +} diff --git a/apps/api/src/services/jobs/email-jobs.ts b/apps/api/src/services/jobs/email-jobs.ts index 1a138ecc..c1345c59 100644 --- a/apps/api/src/services/jobs/email-jobs.ts +++ b/apps/api/src/services/jobs/email-jobs.ts @@ -20,6 +20,8 @@ export interface EnqueueTemplateEmailInput extends CommonOp fields: z.infer>; from?: string; replyTo?: string; + /** Optional iCalendar (.ics) body attached as a text/calendar part. */ + ics?: string; } export interface EnqueueRawEmailInput extends CommonOptions { @@ -81,7 +83,8 @@ export async function enqueueTransactionalEmail( to: recipient, fields: validatedFields, from: input.from, - replyTo: input.replyTo + replyTo: input.replyTo, + ics: input.ics }, { idempotencyKey: recipientKey(input.idempotencyKey, recipient, recipients.length) } ); diff --git a/apps/api/src/services/newsfeed/newsfeed.ts b/apps/api/src/services/newsfeed/newsfeed.ts index 9a17fb7c..61bc7618 100644 --- a/apps/api/src/services/newsfeed/newsfeed.ts +++ b/apps/api/src/services/newsfeed/newsfeed.ts @@ -19,7 +19,7 @@ import { } from '@cio/db/queries/newsfeed'; import { env } from '@cio/core/config/env'; -import { buildEmailFromName } from '@cio/email'; +import { buildEmailFromName, buildEmailBranding } from '@cio/email'; import { enqueueTransactionalEmail } from '@api/services/jobs'; /** @@ -359,6 +359,11 @@ async function sendNewsfeedPostEmail(feedId: string, authorId: string) { const orgName = feedData.organization?.name || 'ClassroomIO'; const orgSiteName = feedData.organization?.siteName || 'app'; + const branding = buildEmailBranding({ + name: feedData.organization?.name, + avatarUrl: feedData.organization?.avatarUrl, + theme: feedData.organization?.theme + }); const postLink = `https://${orgSiteName}.${TENANT_ROOT_DOMAIN}/courses/${feedData.courseId}?feedId=${feedData.feedId}`; const recipients = feedData.courseMembers @@ -374,7 +379,8 @@ async function sendNewsfeedPostEmail(feedId: string, authorId: string) { teacherName: feedData.author?.fullname || 'A teacher', content: feedData.content || '', postLink, - orgName + orgName, + branding }, from: buildEmailFromName(`${orgName} - ClassroomIO`), replyTo: feedData.author?.email || 'noreply@classroomio.com', @@ -403,6 +409,11 @@ async function sendNewsfeedCommentEmail(feedId: string, commentContent: string) const orgName = feedData.organization?.name || 'ClassroomIO'; const orgSiteName = feedData.organization?.siteName || 'app'; + const branding = buildEmailBranding({ + name: feedData.organization?.name, + avatarUrl: feedData.organization?.avatarUrl, + theme: feedData.organization?.theme + }); const postLink = `https://${orgSiteName}.${TENANT_ROOT_DOMAIN}/courses/${feedData.courseId}?feedId=${feedData.feedId}`; await enqueueTransactionalEmail('newsfeedComment', { @@ -411,7 +422,8 @@ async function sendNewsfeedCommentEmail(feedId: string, commentContent: string) courseTitle: feedData.courseTitle, comment: commentContent, postLink, - orgName + orgName, + branding }, from: buildEmailFromName(`${orgName} - ClassroomIO`), replyTo: 'noreply@classroomio.com' diff --git a/apps/api/src/services/organization/audience.ts b/apps/api/src/services/organization/audience.ts index 4c1cdf31..4d079f77 100644 --- a/apps/api/src/services/organization/audience.ts +++ b/apps/api/src/services/organization/audience.ts @@ -5,7 +5,7 @@ import type { TImportAudienceMembers } from '@cio/utils/validation/organization'; import { addGroupMembers, enrollUsersInCourseGroups, getExistingGroupMembers } from '@cio/db/queries/group'; -import { buildEmailFromName } from '@cio/email'; +import { buildEmailFromName, buildEmailBranding } from '@cio/email'; import { enqueueTransactionalEmail } from '@api/services/jobs'; import { addProgramMember, getExistingProgramMembers, getProgramsByOrg } from '@cio/db/queries/program'; import { @@ -30,6 +30,7 @@ import crypto from 'node:crypto'; import { getDashboardBaseUrl } from '@cio/core/config/dashboard-url'; import { getProfilesByEmails } from '@cio/db/queries/auth'; import { ensureComplianceEnrollmentRecordsForProfiles } from '../course/compliance'; +import { getWelcomeSessionIcs } from '../course/session-invite'; const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const ORG_INVITE_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000; @@ -62,8 +63,11 @@ function generateToken(): string { return crypto.randomBytes(32).toString('base64url'); } -function buildInviteLink(token: string): string { - return `${getDashboardBaseUrl()}/invite/${encodeURIComponent(token)}`; +function buildInviteLink( + token: string, + org?: { siteName?: string | null; customDomain?: string | null; isCustomDomainVerified?: boolean | null } +): string { + return `${getDashboardBaseUrl(org)}/invite/${encodeURIComponent(token)}`; } function getExpiryLabel(expiresAtIso: string): string { @@ -170,6 +174,7 @@ async function enrollAudienceStudentProfilesInCourses( const validGroupIds = courseGroups.map((cg) => cg.groupId).filter(Boolean) as string[]; const courseTitleByGroupId = new Map(courseGroups.map((cg) => [cg.groupId, cg.courseTitle])); + const welcomeMessageByGroupId = new Map(courseGroups.map((cg) => [cg.groupId, cg.welcomeEmailMessage])); const validProfiles = uniqueProfileIds.filter((id) => validProfileIds.has(id)); const pairs = validProfiles.flatMap((profileId) => validGroupIds.map((groupId) => ({ groupId, profileId }))); @@ -198,6 +203,10 @@ async function enrollAudienceStudentProfilesInCourses( const loginUrl = getDashboardBaseUrl(organization); if (shouldSendEmail && toInsert.length > 0) { + const icsByGroupId = new Map( + await Promise.all(courseGroups.map(async (cg) => [cg.groupId, await getWelcomeSessionIcs(cg.courseId)] as const)) + ); + const emailPromises = toInsert .filter((p) => profileEmailMap.get(p.profileId)) .map(async (p) => { @@ -208,10 +217,13 @@ async function enrollAudienceStudentProfilesInCourses( fields: { orgName: organization.name, courseName: courseTitleByGroupId.get(p.groupId) || 'Course', - loginUrl + loginUrl, + customMessage: welcomeMessageByGroupId.get(p.groupId) ?? undefined, + branding: buildEmailBranding(organization) }, from: buildEmailFromName(`${organization.name} (via ClassroomIO.com)`), - idempotencyKey: `audience-course-welcome:${p.groupId}:${p.profileId}` + idempotencyKey: `audience-course-welcome:${p.groupId}:${p.profileId}`, + ics: icsByGroupId.get(p.groupId) }); emailsSent++; } catch (emailError) { @@ -290,7 +302,8 @@ async function enrollAudienceStudentProfilesInPrograms( fields: { orgName: organization.name, programName: programNameById.get(pair.programId) || 'Program', - loginUrl + loginUrl, + branding: buildEmailBranding(organization) }, from: buildEmailFromName(`${organization.name} (via ClassroomIO.com)`), idempotencyKey: `audience-program-welcome:${pair.programId}:${pair.profileId}` @@ -387,7 +400,7 @@ async function createStudentOrgInvitesAndSendEmails(input: { const invite = inviteByEmail.get(email)!; const token = tokenByEmail.get(email)!; try { - const inviteLink = buildInviteLink(token); + const inviteLink = buildInviteLink(token, organization); await enqueueTransactionalEmail('studentOrgInvite', { to: email, fields: { @@ -395,7 +408,8 @@ async function createStudentOrgInvitesAndSendEmails(input: { orgName: organization.name, inviteLink, expiresAt: getExpiryLabel(expiresAt), - courseNames: accessNamesLabel + courseNames: accessNamesLabel, + branding: buildEmailBranding(organization) }, from: buildEmailFromName(`${organization.name} (via ClassroomIO.com)`), idempotencyKey: `student-org-invite:${invite.id}` @@ -677,7 +691,7 @@ export async function resendAudienceInvite(orgId: string, data: TAudienceInviteB let emailSent = false; try { - const inviteLink = buildInviteLink(token); + const inviteLink = buildInviteLink(token, organization); await enqueueTransactionalEmail('studentOrgInvite', { to: emailToUse, fields: { @@ -685,7 +699,8 @@ export async function resendAudienceInvite(orgId: string, data: TAudienceInviteB orgName: organization.name, inviteLink, expiresAt: getExpiryLabel(expiresAt), - courseNames: accessNamesLabel + courseNames: accessNamesLabel, + branding: buildEmailBranding(organization) }, from: buildEmailFromName(`${organization.name} (via ClassroomIO.com)`), idempotencyKey: `student-org-invite:${invite.id}` diff --git a/apps/api/src/services/organization/invite.ts b/apps/api/src/services/organization/invite.ts index 4c2553a0..41646284 100644 --- a/apps/api/src/services/organization/invite.ts +++ b/apps/api/src/services/organization/invite.ts @@ -32,6 +32,7 @@ import { getDashboardBaseUrl } from '@cio/core/config/dashboard-url'; import { parseCourseIdsFromInviteMetadata, parseProgramIdsFromInviteMetadata } from '@api/utils/org'; import { markUserAndProfileEmailVerified } from '@cio/db/queries/auth/profile'; import { enqueueTransactionalEmail } from '@api/services/jobs'; +import { buildEmailBranding } from '@cio/email'; import { ensureComplianceEnrollmentRecordsForProfiles } from '../course/compliance'; type OrganizationInviteStatus = 'ACTIVE' | 'EXPIRED' | 'REVOKED' | 'ACCEPTED'; @@ -60,8 +61,11 @@ function normalizeEmails(emails: string[]): string[] { return [...new Set(emails.map((email) => email.toLowerCase().trim()).filter(Boolean))]; } -function buildInviteLink(token: string): string { - return `${getDashboardBaseUrl()}/invite/${encodeURIComponent(token)}`; +function buildInviteLink( + token: string, + org?: { siteName?: string | null; customDomain?: string | null; isCustomDomainVerified?: boolean | null } +): string { + return `${getDashboardBaseUrl(org)}/invite/${encodeURIComponent(token)}`; } function getRoleLabel(roleId: number): string { @@ -245,7 +249,7 @@ export async function inviteTeamMembers(orgId: string, emails: string[], roleId: } }); - const inviteLink = buildInviteLink(token); + const inviteLink = buildInviteLink(token, organization); try { await enqueueTransactionalEmail('inviteTeacher', { @@ -256,7 +260,8 @@ export async function inviteTeamMembers(orgId: string, emails: string[], roleId: orgSiteName: organization.siteName, roleName, expiresAt: getExpiryLabel(expiresAt), - inviteLink + inviteLink, + branding: buildEmailBranding(organization) }, idempotencyKey: `org-invite-teacher:${invite.id}` }); diff --git a/apps/api/src/services/program/goal.ts b/apps/api/src/services/program/goal.ts index 2ace890e..12a5326e 100644 --- a/apps/api/src/services/program/goal.ts +++ b/apps/api/src/services/program/goal.ts @@ -1,6 +1,7 @@ import { AppError, ErrorCodes } from '@api/utils/errors'; import { enqueueTransactionalEmail } from '@api/services/jobs'; import { getDashboardBaseUrl } from '@cio/core/config/dashboard-url'; +import { buildEmailBranding } from '@cio/email'; import { countAssignmentsByStatus, createProgramGoal, @@ -425,7 +426,12 @@ export async function runProgramGoalReminderScan(): Promise<{ daysUntilDue, completedCount: row.assignment.completedCount ?? 0, requiredCount: row.assignment.requiredCount ?? 0, - loginUrl: `${loginUrl}/lms/programs/${row.programId}` + loginUrl: `${loginUrl}/lms/programs/${row.programId}`, + branding: buildEmailBranding({ + name: row.organizationName, + avatarUrl: row.organizationAvatarUrl, + theme: row.organizationTheme + }) }, idempotencyKey: `program-goal-reminder:${row.assignment.id}:${daysUntilDue}:${dayKey}` }); diff --git a/apps/api/src/services/submission/submission.ts b/apps/api/src/services/submission/submission.ts index d44cd8ee..ef2aa6ad 100644 --- a/apps/api/src/services/submission/submission.ts +++ b/apps/api/src/services/submission/submission.ts @@ -12,8 +12,8 @@ import type { TSubmissionGradesUpdate, TSubmissionUpdate } from '@cio/utils/validation/submission'; -import { buildEmailFromName } from '@cio/email'; -import { enqueueRawEmail } from '@api/services/jobs'; +import { buildEmailBranding, buildEmailFromName } from '@cio/email'; +import { enqueueTransactionalEmail } from '@api/services/jobs'; import { createSubmission, deleteSubmission, @@ -34,7 +34,7 @@ import { getQuestionTypeByTypename, requiresManualGrading } from '@cio/question-types'; -import { getCourseById, getOrganizationByCourseId } from '@cio/db/queries/course'; +import { getCourseById, getCourseWithOrgData } from '@cio/db/queries/course'; import { getCourseTeachers, getProfileByGroupMemberId } from '@cio/db/queries/course/people'; import { getExerciseById, getExerciseWithRelationsOptimized } from '@cio/db/queries/exercise'; import { getGroupMemberIdByCourseAndProfile, isCourseTeamMemberOrOrgAdmin } from '@cio/db/queries/group'; @@ -578,7 +578,8 @@ export async function createSubmissionService( .map((question) => question.questionType?.typename ?? '') .filter((typename) => typename.length > 0) ); - const gradingState: SubmissionGradingState = 'queued'; + const gradingState: SubmissionGradingState = + overallStatus === 'manual_required' || overallStatus === 'hybrid' ? 'awaiting_manual' : 'queued'; const submissionData: TNewSubmission = { courseId, @@ -869,7 +870,6 @@ export async function updateSubmissionGradesBatch( const currentGradingState = resolveSubmissionGradingState(submission); const targetGradingState: SubmissionGradingState = 'completed'; const targetStatusId = projectLegacyStatusId(targetGradingState); - if (!isAllowedGradingTransition(currentGradingState, targetGradingState)) { throw new AppError('Invalid submission workflow transition', ErrorCodes.VALIDATION_ERROR, 400); } @@ -965,13 +965,17 @@ async function sendSubmissionUpdateEmail(submissionId: string, newStatusId: numb return; } - // Get organization name - const orgResult = await getOrganizationByCourseId(fullSubmission.courseId || ''); + // Get organization name and URL info + const orgResult = await getCourseWithOrgData(fullSubmission.courseId || ''); const orgName = orgResult?.orgName || 'ClassroomIO'; const statusText = LEGACY_BOARD_STATUS_LABELS[newStatusId] || 'Updated'; - const baseUrl = getDashboardBaseUrl(); + const baseUrl = getDashboardBaseUrl({ + siteName: orgResult?.orgSiteName, + customDomain: orgResult?.orgCustomDomain, + isCustomDomainVerified: orgResult?.orgIsCustomDomainVerified + }); const exerciseLink = `${baseUrl}/courses/${fullSubmission.courseId}/exercises/${fullSubmission.exercise.id}`; // Calculate total and max points @@ -979,37 +983,33 @@ async function sendSubmissionUpdateEmail(submissionId: string, newStatusId: numb const totalMark = answers.reduce((sum: number, a: any) => sum + (a.point || 0), 0); const maxMark = (fullSubmission.exercise.questions || []).reduce((sum: number, q: any) => sum + (q.points || 0), 0); - let content = ` -

Hello ${fullSubmission.groupmember.profile.fullname || 'Student'},

-

The status of your submitted exercise on ${fullSubmission.exercise.title} has been updated to ${statusText}

- `; + const isGraded = newStatusId === 3; + const score = isGraded ? `${totalMark}/${maxMark}` : undefined; - if (newStatusId === 3) { - content += ` -

Your score was ${totalMark}/${maxMark}

-
View your Result - `; - } else { - content += `Open Exercise`; + try { + await enqueueTransactionalEmail('submissionGraded', { + to: fullSubmission.groupmember.profile.email, + fields: { + orgName, + studentName: fullSubmission.groupmember.profile.fullname || 'Student', + exerciseTitle: fullSubmission.exercise.title, + courseName: course.title, + statusText, + exerciseLink, + score, + lessonTitle: fullSubmission.lesson?.title, + branding: buildEmailBranding({ + name: orgResult?.orgName, + avatarUrl: orgResult?.orgAvatarUrl, + theme: orgResult?.orgTheme + }) + }, + from: buildEmailFromName(`${orgName} (via ClassroomIO.com)`), + idempotencyKey: `submission-update:${submissionId}:${newStatusId}` + }); + } catch (error) { + console.error('Failed to enqueue submission graded email:', error); } - - if (fullSubmission.lesson?.title) { - content += ` -

This exercise is for ${fullSubmission.lesson.title} in a course you are taking titled ${course.title}

- `; - } else { - content += ` -

This exercise is in a course you are taking titled ${course.title}

- `; - } - - await enqueueRawEmail({ - from: buildEmailFromName(`${orgName} (via ClassroomIO.com)`), - to: fullSubmission.groupmember.profile.email, - subject: 'Submission Update', - content, - idempotencyKey: `submission-update:${submissionId}:${newStatusId}` - }); } /** @@ -1042,32 +1042,43 @@ async function sendExerciseSubmissionUpdateEmail(courseId: string, exerciseId: s return; } - // Get organization name - const orgResult = await getOrganizationByCourseId(courseId); + // Get organization name and URL info + const orgResult = await getCourseWithOrgData(courseId); const orgName = orgResult?.orgName || 'ClassroomIO'; - const baseUrl = getDashboardBaseUrl(); + const baseUrl = getDashboardBaseUrl({ + siteName: orgResult?.orgSiteName, + customDomain: orgResult?.orgCustomDomain, + isCustomDomainVerified: orgResult?.orgIsCustomDomainVerified + }); const exerciseLink = `${baseUrl}/courses/${courseId}/exercises/${exerciseId}`; const submissionLink = `${baseUrl}/courses/${courseId}/submissions`; - const content = ` -

Hello,

-

A student ${student.fullname || student.username} just submitted an exercise ${exercise.title}

-

You can get started grading by clicking "Open Submissions"

- - `; + const studentName = student.fullname || student.username || 'A student'; const tutorEmails = tutorsResult.map((tutor) => tutor.email).filter((email): email is string => Boolean(email)); if (tutorEmails.length === 0) return; - await enqueueRawEmail({ - from: buildEmailFromName(`${orgName} (via ClassroomIO.com)`), - to: tutorEmails, - subject: `[Submitted]: ${exercise.title}`, - content, - idempotencyKey: `exercise-submitted:${courseId}:${exerciseId}:${submittedBy}` - }); + try { + await enqueueTransactionalEmail('submissionReceived', { + to: tutorEmails, + fields: { + orgName, + studentName, + exerciseTitle: exercise.title, + exerciseLink, + submissionLink, + branding: buildEmailBranding({ + name: orgResult?.orgName, + avatarUrl: orgResult?.orgAvatarUrl, + theme: orgResult?.orgTheme + }) + }, + from: buildEmailFromName(`${orgName} (via ClassroomIO.com)`), + idempotencyKey: `exercise-submitted:${courseId}:${exerciseId}:${submittedBy}` + }); + } catch (error) { + console.error('Failed to enqueue submission received email:', error); + } } diff --git a/apps/api/src/utils/course-completion.ts b/apps/api/src/utils/course-completion.ts index 7dcca63a..eccd579b 100644 --- a/apps/api/src/utils/course-completion.ts +++ b/apps/api/src/utils/course-completion.ts @@ -5,7 +5,7 @@ import { } from '@cio/db/queries/course/course'; import { setMemberCertificateEarned, setMemberCertificationEmailSent } from '@cio/db/queries/course/people'; import { getProfileById } from '@cio/db/queries/auth'; -import { buildEmailFromName } from '@cio/email'; +import { buildEmailFromName, buildEmailBranding } from '@cio/email'; import { enqueueTransactionalEmail } from '@api/services/jobs'; export function calcCourseProgressPercent(params: { @@ -81,7 +81,12 @@ export function scheduleCertificationCompletionWork(params: { courseName: courseRow.title, studentName: profile?.fullname || studentEmail, certificateUrl, - customMessage: courseRow.certificate?.emailMessage ?? null + customMessage: courseRow.certificate?.emailMessage ?? null, + branding: buildEmailBranding({ + name: courseRow.orgName, + avatarUrl: courseRow.orgAvatarUrl, + theme: courseRow.orgTheme + }) }, from: buildEmailFromName(`${courseRow.orgName} (via ClassroomIO.com)`), idempotencyKey: `course-completion:${groupMemberId}` diff --git a/apps/dashboard/README.md b/apps/dashboard/README.md index 8545863b..f3a1b0d8 100644 --- a/apps/dashboard/README.md +++ b/apps/dashboard/README.md @@ -1,5 +1,5 @@ - A flexible, user-friendly platform for creating, managing, and delivering courses for companies and training organisations + A flexible, user-friendly platform for creating, managing, and delivering trainings for companies and training organisations

ClassroomIO

The Open Source Teaching Platform for Bootcamps diff --git a/apps/dashboard/src/lib/features/course/api/exercise.svelte.ts b/apps/dashboard/src/lib/features/course/api/exercise.svelte.ts index ee01054c..a0723aa1 100644 --- a/apps/dashboard/src/lib/features/course/api/exercise.svelte.ts +++ b/apps/dashboard/src/lib/features/course/api/exercise.svelte.ts @@ -28,6 +28,8 @@ import { import { mapZodErrorsToTranslations } from '$lib/utils/validation'; import { snackbar } from '$features/ui/snackbar/store'; +import { toast } from '@cio/ui/base/sonner'; +import { t } from '$lib/utils/functions/translations'; /** * API class for exercise operations @@ -60,6 +62,74 @@ export class ExerciseApi extends BaseApiWithErrors { }); } + /** + * Notifies all course members that a quiz has been assigned. Runs as a + * background job; shows a sonner spinner that polls until the job is done. + */ + async notifyStudents(courseId: string, exerciseId: string) { + const toastId = toast.loading(t.get('course.navItem.lessons.exercises.all_exercises.notify.sending'), { + position: 'bottom-right' + }); + + try { + const res = await classroomio.course[':courseId'].exercise[':exerciseId'].notify.$post({ + param: { courseId, exerciseId } + }); + const body = await res.json(); + + if (!body.success) { + throw new Error('Failed to start notification'); + } + + const jobId = body.data.jobId; + const maxPolls = 60; + + for (let pollCount = 0; pollCount < maxPolls; pollCount++) { + const statusRes = await classroomio.course[':courseId'].exercise[':exerciseId'].notify[':jobId'].$get({ + param: { courseId, exerciseId, jobId }, + query: { pollCount: String(pollCount) } + }); + const statusBody = await statusRes.json(); + + if (!statusBody.success) { + throw new Error('Failed to read notification status'); + } + + const { job, nextPollMs } = statusBody.data; + + if (job.status === 'completed') { + const notified = (job.result as { notified?: number } | null)?.notified ?? 0; + toast.success(t.get('course.navItem.lessons.exercises.all_exercises.notify.sent', { count: notified }), { + id: toastId, + position: 'bottom-right' + }); + return; + } + + if (job.status === 'failed' || job.status === 'canceled') { + toast.error(t.get('course.navItem.lessons.exercises.all_exercises.notify.failed'), { + id: toastId, + position: 'bottom-right' + }); + return; + } + + await new Promise((resolve) => setTimeout(resolve, nextPollMs || 2000)); + } + + toast.error(t.get('course.navItem.lessons.exercises.all_exercises.notify.failed'), { + id: toastId, + position: 'bottom-right' + }); + } catch (error) { + console.error('notifyStudents error:', error); + toast.error(t.get('course.navItem.lessons.exercises.all_exercises.notify.failed'), { + id: toastId, + position: 'bottom-right' + }); + } + } + /** * Creates a new exercise */ diff --git a/apps/dashboard/src/lib/features/course/components/ceritficate/certificate-settings.svelte b/apps/dashboard/src/lib/features/course/components/ceritficate/certificate-settings.svelte index 6ed92be7..0b3742e7 100644 --- a/apps/dashboard/src/lib/features/course/components/ceritficate/certificate-settings.svelte +++ b/apps/dashboard/src/lib/features/course/components/ceritficate/certificate-settings.svelte @@ -140,6 +140,7 @@ {/each} {$t('course.certification.final_exercise_helper')} + {$t('course.certification.final_exercise_multiple_attempts_note')} {#if courseApi.course?.certificate?.requiredExerciseId} diff --git a/apps/dashboard/src/lib/features/course/components/ceritficate/course-completion-modal.svelte b/apps/dashboard/src/lib/features/course/components/ceritficate/course-completion-modal.svelte index 14f4e7bd..71e86948 100644 --- a/apps/dashboard/src/lib/features/course/components/ceritficate/course-completion-modal.svelte +++ b/apps/dashboard/src/lib/features/course/components/ceritficate/course-completion-modal.svelte @@ -4,21 +4,34 @@ import { resolve } from '$app/paths'; import * as Dialog from '@cio/ui/base/dialog'; import { Button } from '@cio/ui/base/button'; + import { Spinner } from '@cio/ui/base/spinner'; import { Confetti } from '$features/ui'; import { setConfetti } from '$features/ui/confetti/store'; + import { ContentType } from '@cio/utils/constants/content'; import { courseCompletionModal, closeCourseCompletionModal } from '$features/course/store/course-completion-modal'; + import { getContentRoute } from '$features/course/utils/content'; + import { formatBlockerMessage } from '$features/course/utils/certificate-utils'; import { t } from '$lib/utils/functions/translations'; let open = $state(false); let activeCourseId = $state(''); + let activeStep = $state<'checking' | 'eligible' | 'not-eligible'>('checking'); + let activeEvaluation = $state | null>(null); + let activeExerciseId = $state(undefined); onMount(() => { return courseCompletionModal.subscribe((v) => { if (v?.open && v.courseId) { activeCourseId = v.courseId; + activeStep = v.step; + activeEvaluation = v.evaluation as Record | null; + activeExerciseId = v.exerciseId; open = true; - setConfetti(true); - setTimeout(() => setConfetti(false), 5500); + + if (v.step === 'eligible' && !v.evaluation?.certificateEarnedAt) { + setConfetti(true); + setTimeout(() => setConfetti(false), 5500); + } } else { open = false; } @@ -37,6 +50,24 @@ onOpenChange(false); goto(resolve(`/courses/${activeCourseId}/certificates`, {})); } + + function goToExercise() { + if (!activeCourseId || !activeExerciseId) return; + onOpenChange(false); + const path = getContentRoute(activeCourseId, { id: activeExerciseId, type: ContentType.Exercise }); + if (path) { + goto(resolve(path, {})); + } + } + + function formatSingleBlocker() { + if (!activeEvaluation) return ''; + const blockers = (activeEvaluation as Record).blockers as + | Array> + | undefined; + if (!blockers || blockers.length === 0) return ''; + return formatBlockerMessage(blockers[0] as Parameters[0]); + }

@@ -45,13 +76,33 @@ - - {$t('course.completion.modal.title')} - {$t('course.completion.modal.subtitle')} - - - - - + {#if activeStep === 'checking'} +
+ +

{$t('course.completion.modal.checking')}

+
+ {:else if activeStep === 'eligible'} + + {$t('course.completion.modal.title')} + {$t('course.completion.modal.subtitle')} + + + + + + {:else if activeStep === 'not-eligible'} + + {$t('course.completion.modal.not_eligible_title')} + +
+

{formatSingleBlocker()}

+
+ + + {#if activeExerciseId} + + {/if} + + {/if}
diff --git a/apps/dashboard/src/lib/features/course/components/ceritficate/student-certificate/unlocked-certificate.svelte b/apps/dashboard/src/lib/features/course/components/ceritficate/student-certificate/unlocked-certificate.svelte index d8eb5c20..7ce4c7d8 100644 --- a/apps/dashboard/src/lib/features/course/components/ceritficate/student-certificate/unlocked-certificate.svelte +++ b/apps/dashboard/src/lib/features/course/components/ceritficate/student-certificate/unlocked-certificate.svelte @@ -11,7 +11,7 @@ import { snackbar } from '$features/ui/snackbar/store'; import { classroomio } from '$lib/utils/services/api'; import type { CertificationEvaluationData } from '$features/course/utils/types'; - import { normalizeCertificateIssuedAt } from '$features/course/utils/certificate-utils'; + import { normalizeCertificateIssuedAt, formatBlockerMessage } from '$features/course/utils/certificate-utils'; import { openCourseCompletionModal } from '$features/course/store/course-completion-modal'; let isLoading = $state(false); @@ -21,41 +21,6 @@ let courseId = $derived(courseApi.course?.id ?? ''); - function formatBlockerMessage(blocker: CertificationEvaluationData['blockers'][number]): string { - const p = blocker.params ?? {}; - switch (blocker.code) { - case 'CERT_PROGRESS': - return t.get('course.certification.blocker_progress', { - current: Number(p.current ?? 0), - required: Number(p.required ?? 0) - }); - case 'CERT_DEADLINE_PASSED': - return t.get('course.certification.blocker_deadline'); - case 'CERT_NO_CONTENT': - return t.get('course.certification.blocker_no_content'); - case 'CERT_FINAL_EXERCISE_NOT_SUBMITTED': - return t.get('course.certification.blocker_final_not_submitted', { - exerciseTitle: String(p.exerciseTitle ?? '') - }); - case 'CERT_FINAL_EXERCISE_PENDING_GRADE': - return t.get('course.certification.blocker_final_pending', { - exerciseTitle: String(p.exerciseTitle ?? '') - }); - case 'CERT_FINAL_EXERCISE_SCORE': - return t.get('course.certification.blocker_final_score', { - exerciseTitle: String(p.exerciseTitle ?? ''), - bestPercent: Number(p.bestPercent ?? 0), - requiredPercent: Number(p.requiredPercent ?? 0) - }); - case 'CERT_FINAL_EXERCISE_MISCONFIGURED': - return t.get('course.certification.blocker_final_misconfigured', { - exerciseTitle: String(p.exerciseTitle ?? '') - }); - default: - return blocker.code; - } - } - function buildBody() { return { studentName: $profile.fullname || 'Recipient', diff --git a/apps/dashboard/src/lib/features/course/components/course-header.svelte b/apps/dashboard/src/lib/features/course/components/course-header.svelte index 09561423..652af5da 100644 --- a/apps/dashboard/src/lib/features/course/components/course-header.svelte +++ b/apps/dashboard/src/lib/features/course/components/course-header.svelte @@ -3,6 +3,7 @@ import * as Sidebar from '@cio/ui/base/sidebar'; import EyeIcon from '@lucide/svelte/icons/eye'; import { Button } from '@cio/ui/base/button'; + import { Waves } from '@cio/ui/custom/animation'; import { page } from '$app/state'; import { currentOrg, currentOrgDomain } from '$lib/utils/store/org'; import { isStudentExperience } from '$lib/utils/store/app'; @@ -58,9 +59,22 @@ - {#if !$isStudentExperience} diff --git a/apps/dashboard/src/lib/features/course/components/exercise/edit-mode.svelte b/apps/dashboard/src/lib/features/course/components/exercise/edit-mode.svelte index 37850ccc..4811116a 100644 --- a/apps/dashboard/src/lib/features/course/components/exercise/edit-mode.svelte +++ b/apps/dashboard/src/lib/features/course/components/exercise/edit-mode.svelte @@ -53,7 +53,7 @@ shouldDeleteExercise?: boolean; exerciseId: string; goBack?: () => void; - /** Self-paced + all auto-gradable question types: enforce points > 0 */ + /** All auto-gradable question types (any course): enforce points > 0 for scoring */ requiresPositivePointsForAutoGrade?: boolean; selfPacedCourse?: boolean; /** Public course restricts picker to auto-gradable question types only. */ diff --git a/apps/dashboard/src/lib/features/course/components/exercise/view-mode.svelte b/apps/dashboard/src/lib/features/course/components/exercise/view-mode.svelte index 06d5c396..cfe4762b 100644 --- a/apps/dashboard/src/lib/features/course/components/exercise/view-mode.svelte +++ b/apps/dashboard/src/lib/features/course/components/exercise/view-mode.svelte @@ -40,7 +40,11 @@ import { ContentType } from '@cio/utils/constants/content'; import { getOrderedNavigableContent } from '$features/course/utils/content'; import { isOrgStudent } from '$lib/utils/store/app'; - import { openCourseCompletionModal } from '$features/course/store/course-completion-modal'; + import { + openCourseCompletionModal, + updateCourseCompletionModal, + closeCourseCompletionModal + } from '$features/course/store/course-completion-modal'; import { isSelfPacedLikeCourse } from '$features/course/utils/compliance-utils'; import { toExerciseQuestionModel } from './question-type-utils'; import { getExerciseQuestionLabels } from './question-labels'; @@ -152,7 +156,19 @@ $isOrgStudent && allContentItems.length > 0 && allContentItems.every((item) => item.isComplete); if (allComplete && courseApi.course?.id) { + const requiredExerciseId = courseApi.course?.certificate?.requiredExerciseId ?? undefined; openCourseCompletionModal(courseApi.course.id); + + const certRes = await courseApi.getCertificationEvaluation(courseApi.course.id); + if (certRes?.data) { + if (certRes.data.isNewCompletion) { + updateCourseCompletionModal(courseApi.course.id, 'eligible', certRes.data, requiredExerciseId); + } else { + updateCourseCompletionModal(courseApi.course.id, 'not-eligible', certRes.data, requiredExerciseId); + } + } else { + closeCourseCompletionModal(); + } } } diff --git a/apps/dashboard/src/lib/features/course/components/lesson/content-list.svelte b/apps/dashboard/src/lib/features/course/components/lesson/content-list.svelte index f1291646..b982f4b0 100644 --- a/apps/dashboard/src/lib/features/course/components/lesson/content-list.svelte +++ b/apps/dashboard/src/lib/features/course/components/lesson/content-list.svelte @@ -286,7 +286,7 @@ ? $t('course.navItem.lessons.add_lesson.lock') : $t('course.navItem.lessons.add_lesson.unlock')} {@const canRenderJoinButton = - item.type === ContentType.Lesson && isLiveCourse && Boolean(item.callUrl) && !itemLocked} + item.type === ContentType.Lesson && isLiveCourse && Boolean(item.callUrl) && !itemLocked && !isEditingItem} {@const canRenderContinueButton = isStudentView && !itemLocked} {@const isLockPending = Boolean(lockPendingItemKeys[getItemLockKey(item)])} {@const actionDisabled = Boolean($contentEditingStore && !isEditingItem)} diff --git a/apps/dashboard/src/lib/features/course/components/lesson/content-navigation-actions.svelte b/apps/dashboard/src/lib/features/course/components/lesson/content-navigation-actions.svelte index ff5f0d6d..c6f451b9 100644 --- a/apps/dashboard/src/lib/features/course/components/lesson/content-navigation-actions.svelte +++ b/apps/dashboard/src/lib/features/course/components/lesson/content-navigation-actions.svelte @@ -14,7 +14,11 @@ import { ContentType } from '@cio/utils/constants/content'; import { snackbar } from '$features/ui/snackbar/store'; import type { CourseContentItem } from '$features/course/utils/types'; - import { openCourseCompletionModal } from '$features/course/store/course-completion-modal'; + import { + openCourseCompletionModal, + updateCourseCompletionModal, + closeCourseCompletionModal + } from '$features/course/store/course-completion-modal'; import { updateLessonCompletionInCourseContent } from '$features/course/utils/content-completion'; interface Props { @@ -135,7 +139,19 @@ navigableContentItems.every((item) => item.isComplete); if (allComplete) { + const requiredExerciseId = courseApi.course?.certificate?.requiredExerciseId ?? undefined; openCourseCompletionModal(courseId); + + const certRes = await courseApi.getCertificationEvaluation(courseId); + if (certRes?.data) { + if (certRes.data.isNewCompletion) { + updateCourseCompletionModal(courseId, 'eligible', certRes.data, requiredExerciseId); + } else { + updateCourseCompletionModal(courseId, 'not-eligible', certRes.data, requiredExerciseId); + } + } else { + closeCourseCompletionModal(); + } } } else { snackbar.error('snackbar.lessons.error.try_later'); diff --git a/apps/dashboard/src/lib/features/course/components/lesson/content-row.svelte b/apps/dashboard/src/lib/features/course/components/lesson/content-row.svelte index cac5c89e..d968c773 100644 --- a/apps/dashboard/src/lib/features/course/components/lesson/content-row.svelte +++ b/apps/dashboard/src/lib/features/course/components/lesson/content-row.svelte @@ -2,10 +2,13 @@ import { resolve } from '$app/paths'; import LockIcon from '@lucide/svelte/icons/lock'; import { InputField } from '@cio/ui/custom/input-field'; + import { RadioIcon } from '@cio/ui/custom/moving-icons'; import { CircleCheckIcon } from '$features/ui/icons'; import type { Snippet } from 'svelte'; import CourseContentIcon from '$features/course/components/course-content-icon.svelte'; import type { CourseContentItem } from '$features/course/utils/types'; + import { ContentType } from '@cio/utils/constants/content'; + import { t } from '$lib/utils/functions/translations'; import { cn } from '@cio/ui/tools'; interface Props { @@ -62,6 +65,16 @@ {/if} + {#if item.type === ContentType.Lesson && item.callUrl} + + + + {/if} +
- import { lessonApi } from '$features/course/api'; + import { lessonApi, courseApi } from '$features/course/api'; import { InputField } from '@cio/ui/custom/input-field'; import { Checkbox } from '@cio/ui/base/checkbox'; + import { Button } from '@cio/ui/base/button'; + import * as Dialog from '@cio/ui/base/dialog'; import * as Field from '@cio/ui/base/field'; import * as Select from '@cio/ui/base/select'; + import * as Tooltip from '@cio/ui/base/tooltip'; + import InfoIcon from '@lucide/svelte/icons/info'; + import { toast } from '@cio/ui/base/sonner'; + import { classroomio } from '$lib/utils/services/api'; import { t } from '$lib/utils/functions/translations'; + import { getBrowserTimezone, instantToZonedWallClock, zonedWallClockToInstant } from '$lib/utils/functions/date'; import { getVideoTitle, isHlsUploadVideo, type LessonVideo } from './video/video-card-utils'; type LessonCompletionPolicy = 'manual' | 'video_watch' | 'none'; + // ── Live session (Zoom link + scheduled time + timezone) ────────────────── + const isLiveClass = $derived(courseApi.course?.type === 'LIVE_CLASS'); + const timezoneOptions = (() => { + try { + return (Intl as unknown as { supportedValuesOf?: (k: string) => string[] }).supportedValuesOf?.('timeZone') ?? []; + } catch { + return []; + } + })(); + + let sessionCallUrl = $state(''); + let sessionWallClock = $state(''); + let sessionTimezone = $state(getBrowserTimezone()); + let sessionInitializedFor = $state(null); + let isSavingSession = $state(false); + let confirmOpen = $state(false); + + $effect(() => { + const lesson = lessonApi.lesson; + if (!lesson || sessionInitializedFor === lesson.id) return; + + const tz = courseApi.course?.metadata?.sessionTimezone || getBrowserTimezone(); + sessionTimezone = tz; + sessionCallUrl = lesson.callUrl ?? ''; + sessionWallClock = instantToZonedWallClock(lesson.lessonAt, tz); + sessionInitializedFor = lesson.id; + }); + + const hadPriorSession = $derived(Boolean(lessonApi.lesson?.lessonAt && lessonApi.lesson?.callUrl)); + + function computeNewInstant(): string { + return sessionWallClock ? zonedWallClockToInstant(sessionWallClock, sessionTimezone) : ''; + } + + function sessionChanged(): boolean { + const currentTz = courseApi.course?.metadata?.sessionTimezone || getBrowserTimezone(); + + return ( + sessionCallUrl !== (lessonApi.lesson?.callUrl ?? '') || + computeNewInstant() !== (lessonApi.lesson?.lessonAt ?? '') || + sessionTimezone !== currentTz + ); + } + + async function persistSession() { + const courseId = courseApi.course?.id; + const lessonId = lessonApi.lesson?.id; + if (!courseId || !lessonId) return; + + isSavingSession = true; + try { + await lessonApi.update(courseId, lessonId, { + callUrl: sessionCallUrl || undefined, + lessonAt: computeNewInstant() || undefined + }); + + const currentTz = courseApi.course?.metadata?.sessionTimezone || ''; + if (sessionTimezone && sessionTimezone !== currentTz) { + await courseApi.update(courseId, { + metadata: { ...(courseApi.course?.metadata ?? {}), sessionTimezone } + }); + } + + sessionInitializedFor = null; // re-sync baselines from refreshed lesson/course + } finally { + isSavingSession = false; + } + } + + async function notifySessionUpdate() { + const courseId = courseApi.course?.id; + const lessonId = lessonApi.lesson?.id; + if (!courseId || !lessonId) return; + + try { + await classroomio.course[':courseId'].lesson[':lessonId']['notify-session-update'].$post({ + param: { courseId, lessonId } + }); + toast.success(t.get('course.navItem.lessons.session.notified')); + } catch { + toast.error(t.get('course.navItem.lessons.session.notify_failed')); + } + } + + async function handleSaveSession() { + if (!sessionChanged()) return; + + if (hadPriorSession) { + confirmOpen = true; + return; + } + + await persistSession(); + toast.success(t.get('course.navItem.lessons.session.saved')); + } + + async function confirmSaveAndNotify() { + confirmOpen = false; + await persistSession(); + await notifySessionUpdate(); + } + const completionPolicy = $derived(lessonApi.lesson?.completionPolicy ?? 'manual'); const videoWatchThreshold = $derived(lessonApi.lesson?.videoWatchThreshold ?? 95); const videos = $derived(lessonApi.lesson?.videos ?? []); @@ -63,6 +172,59 @@
+ {#if isLiveClass} + + {$t('course.navItem.lessons.session.heading')} + {$t('course.navItem.lessons.session.intro')} + + + (sessionCallUrl = (e.currentTarget as HTMLInputElement).value)} + /> + + +
+ + {$t('course.navItem.lessons.session.datetime_label')} + (sessionWallClock = (e.currentTarget as HTMLInputElement).value)} + /> + + + + {$t('course.navItem.lessons.session.timezone_label')} + + {$t('course.navItem.lessons.session.timezone_helper')} + +
+ +
+ +
+
+ + + {/if} + {$t('course.navItem.lessons.settings.progression.heading')} {$t('course.navItem.lessons.settings.progression.intro')} @@ -72,9 +234,36 @@ - - {$t('course.navItem.lessons.completion_policy.label')} - +
+ + {$t('course.navItem.lessons.completion_policy.label')} + + + + + + + +
    +
  • + {$t('course.navItem.lessons.completion_policy.manual_label')}: + {$t('course.navItem.lessons.completion_policy.manual_description')} +
  • +
  • + {$t('course.navItem.lessons.completion_policy.video_watch_label')}: + {$t('course.navItem.lessons.completion_policy.video_watch_description')} +
  • +
  • + {$t('course.navItem.lessons.completion_policy.none_label')}: + {$t('course.navItem.lessons.completion_policy.none_description')} +
  • +
+
+
+
+
{policyTriggerLabel(completionPolicy)} @@ -108,30 +297,6 @@
-
-

{$t('course.navItem.lessons.settings.progression.option_guide_heading')}

-
    -
  • - - {$t('course.navItem.lessons.completion_policy.manual_label')}: - - {$t('course.navItem.lessons.completion_policy.manual_description')} -
  • -
  • - - {$t('course.navItem.lessons.completion_policy.video_watch_label')}: - - {$t('course.navItem.lessons.completion_policy.video_watch_description')} -
  • -
  • - - {$t('course.navItem.lessons.completion_policy.none_label')}: - - {$t('course.navItem.lessons.completion_policy.none_description')} -
  • -
-
- {#if completionPolicy === 'video_watch'}
+ + + + + {$t('course.navItem.lessons.session.confirm_title')} + {$t('course.navItem.lessons.session.confirm_body')} + + + + + + + diff --git a/apps/dashboard/src/lib/features/course/components/lesson/live-session-card.svelte b/apps/dashboard/src/lib/features/course/components/lesson/live-session-card.svelte new file mode 100644 index 00000000..499b34a0 --- /dev/null +++ b/apps/dashboard/src/lib/features/course/components/lesson/live-session-card.svelte @@ -0,0 +1,35 @@ + + + diff --git a/apps/dashboard/src/lib/features/course/components/sidebar/course-content-tree.svelte b/apps/dashboard/src/lib/features/course/components/sidebar/course-content-tree.svelte index a91a3f87..27ff5dfd 100644 --- a/apps/dashboard/src/lib/features/course/components/sidebar/course-content-tree.svelte +++ b/apps/dashboard/src/lib/features/course/components/sidebar/course-content-tree.svelte @@ -12,6 +12,7 @@ import { CircleCheckIcon } from '$features/ui/icons'; import { t } from '$lib/utils/functions/translations'; import { IconButton } from '@cio/ui/custom/icon-button'; + import { RadioIcon } from '@cio/ui/custom/moving-icons'; import CourseContentIcon from '$features/course/components/course-content-icon.svelte'; interface Props { @@ -29,6 +30,16 @@ const canOpenContentModal = $derived(Boolean(onOpenContentModal) && !isStudent); +{#snippet liveSessionDot()} + + + +{/snippet} + {#if contentData.grouped} {#each contentData.sections as section (section.id)} @@ -74,7 +85,7 @@ {#snippet child({ props })} {@const isContentLocked = (contentItem.isUnlocked ?? true) === false} - {@const isLockedForStudent = isStudent && isContentLocked} + {@const isLockedForStudent = isStudent && (isContentLocked || contentItem.accessible === false)}
{/if} - {#if isContentLocked} + {#if contentItem.type === ContentType.Lesson && contentItem.callUrl} + {@render liveSessionDot()} + {:else if isContentLocked || isLockedForStudent} {#snippet child({ props })} {@const isContentLocked = (contentItem.isUnlocked ?? true) === false} - {@const isLockedForStudent = isStudent && isContentLocked} + {@const isLockedForStudent = isStudent && (isContentLocked || contentItem.accessible === false)} {/if} - {#if isContentLocked} + {#if contentItem.type === ContentType.Lesson && contentItem.callUrl} + {@render liveSessionDot()} + {:else if isContentLocked || isLockedForStudent} 0 && typeIds.every((id) => isAutoGradableQuestionType(getQuestionTypeKeyFromId(id))); } - /** When true, every question must have points > 0 before save */ - const requiresPositivePointsForAutoGrade = $derived( - isSelfPacedCourse && isExerciseFullyAutoGradable(activeQuestionTypeIds) - ); + const isFullyAutoGradable = $derived(isExerciseFullyAutoGradable(activeQuestionTypeIds)); + + /** When true, every question must have points > 0 before save (for meaningful auto-grading) */ + const requiresPositivePointsForAutoGrade = $derived(isFullyAutoGradable); + const teacherAutoGradeBadge = $derived.by(() => { - if ($isOrgStudent || !isSelfPacedCourse || activeQuestionTypeIds.length === 0) return null; - return isExerciseFullyAutoGradable(activeQuestionTypeIds) ? ('auto' as const) : ('manual' as const); + if ($isOrgStudent || isPublicCourse || activeQuestionTypeIds.length === 0) return null; + return isFullyAutoGradable ? ('auto' as const) : ('manual' as const); }); async function scrollToExerciseElement(elementId: string) { @@ -498,6 +499,16 @@ {$t('course.navItem.lessons.exercises.all_exercises.reorder')} {/if} + { + if (courseApi.course?.id && exerciseId) { + exerciseApi.notifyStudents(courseApi.course.id, exerciseId); + } + }} + > + {$t('course.navItem.lessons.exercises.all_exercises.notify.action')} + {#snippet child()} -
+
+ {#if isLiveSessionLesson && mode === MODES.view && !($isOrgStudent && !isLessonUnlocked)} +
+ +
+ {/if} + {#if $isOrgStudent && !isLessonUnlocked} ; const updatedCourse = { @@ -224,7 +226,8 @@ allowNewStudents: !!course.metadata?.allowNewStudent, isContentGroupingEnabled: course.metadata?.isContentGroupingEnabled ?? true, progressionMode: course.metadata?.progressionMode ?? 'free', - callout: normalizeCallout(course.callout) + callout: normalizeCallout(course.callout), + welcomeEmailMessage: course.metadata?.welcomeEmailMessage ?? '' }); }); } @@ -350,7 +353,7 @@
- + + + {/each} + + +{/if} diff --git a/apps/dashboard/src/lib/features/lms/pages/dashboard.svelte b/apps/dashboard/src/lib/features/lms/pages/dashboard.svelte index af06e710..ff0a3aae 100644 --- a/apps/dashboard/src/lib/features/lms/pages/dashboard.svelte +++ b/apps/dashboard/src/lib/features/lms/pages/dashboard.svelte @@ -19,12 +19,14 @@ import { coursesApi } from '$features/course/api'; import * as ResourceListRow from '@cio/ui/custom/resource-list-row'; import { CourseListRow } from '$features/course/components'; + import UpcomingSessionsCard from '$features/lms/components/upcoming-sessions-card.svelte'; import CoursePublicBadge from '$features/course/components/course-public-badge.svelte'; import CoursePreviewModal from '$features/lms/components/course-preview-modal.svelte'; import type { RecommendedCourses } from '$features/course/types'; import { IconButton } from '@cio/ui/custom/icon-button'; import ExternalLinkIcon from '@lucide/svelte/icons/external-link'; import CopyIcon from '@lucide/svelte/icons/copy'; + import VideoIcon from '@lucide/svelte/icons/video'; import { copyPublicCoursePageUrl, openCoursePreview } from '$features/course/utils/course-preview'; import { getStudentCourseComplianceDate, @@ -59,6 +61,27 @@ let inProgressCourses = $derived(coursesApi.enrolledCourses.filter((course) => !isStudentCourseComplete(course))); let highlightedCourses = $derived.by(() => getHighlightedCourses(inProgressCourses)); let currentCourse = $derived(highlightedCourses[0] ?? coursesApi.enrolledCourses[0] ?? null); + let shouldShowCertificateHero = $derived.by(() => { + if (!currentCourse || coursesApi.enrolledCourses.length !== 1) { + return false; + } + + return isStudentCourseComplete(currentCourse) && currentCourse.certificateEarnedAt != null; + }); + + let upcomingSessions = $derived( + coursesApi.enrolledCourses + .filter((course) => course.type === 'LIVE_CLASS' && course.upcomingSession) + .map((course) => ({ + lessonId: course.upcomingSession!.lessonId, + courseTitle: course.title, + lessonTitle: course.upcomingSession!.lessonTitle, + callUrl: course.upcomingSession!.callUrl, + lessonAt: course.upcomingSession!.lessonAt, + timezone: course.upcomingSession!.sessionTimezone + })) + .sort((a, b) => new Date(a.lessonAt).getTime() - new Date(b.lessonAt).getTime()) + ); $effect(() => { if (!$profile.id || !$currentOrg.id) return; @@ -127,6 +150,12 @@ goto(`/courses/${id}/lessons?next=true`); } + function gotoCourseCertificates(id: string | undefined) { + if (!id) return; + + goto(`/courses/${id}/certificates`); + } + function showPublishedPublicCourseLinks(course: EnrolledCourse | null) { if (!course || course.type !== 'PUBLIC') { return false; @@ -167,16 +196,28 @@
+ {#if upcomingSessions.length} + + {/if} +

- {$t('dashboard.pick_up_where_you_left_off')} + {#if shouldShowCertificateHero} + {$t('dashboard.get_your_certificate')} + {:else} + {$t('dashboard.pick_up_where_you_left_off')} + {/if}

{#if currentCourse} - {$t('dashboard.course_awaits_you', { title: currentCourse.title })} + {#if shouldShowCertificateHero} + {currentCourse.title} + {:else} + {$t('dashboard.course_awaits_you', { title: currentCourse.title })} + {/if} {:else} {$t('dashboard.learning_awaits_you')} {/if} @@ -205,10 +246,19 @@ + + {/if} diff --git a/apps/dashboard/src/lib/features/settings/components/index.ts b/apps/dashboard/src/lib/features/settings/components/index.ts index 7530a366..b92eee91 100644 --- a/apps/dashboard/src/lib/features/settings/components/index.ts +++ b/apps/dashboard/src/lib/features/settings/components/index.ts @@ -2,3 +2,4 @@ export { default as LanguagePicker } from './language-picker.svelte'; export { default as AuthGeneral } from './auth-general.svelte'; export { default as AuthSso } from './auth-sso.svelte'; export { default as AuthTokenAuth } from './auth-token-auth.svelte'; +export { default as OrgSettingsInlineTabs } from './org-settings-inline-tabs.svelte'; diff --git a/apps/dashboard/src/lib/features/settings/components/org-settings-inline-tabs.svelte b/apps/dashboard/src/lib/features/settings/components/org-settings-inline-tabs.svelte new file mode 100644 index 00000000..a6d03d4c --- /dev/null +++ b/apps/dashboard/src/lib/features/settings/components/org-settings-inline-tabs.svelte @@ -0,0 +1,52 @@ + + +{#if currentTab} +
+ handleTabChange(event)}> + + {#each orgSettingsTabs as tab} + + {$t(tab.label)} + + {/each} + + +
+{/if} diff --git a/apps/dashboard/src/lib/features/settings/pages/org.svelte b/apps/dashboard/src/lib/features/settings/pages/org.svelte index 0a4202e0..61d414bd 100644 --- a/apps/dashboard/src/lib/features/settings/pages/org.svelte +++ b/apps/dashboard/src/lib/features/settings/pages/org.svelte @@ -1,17 +1,14 @@ @@ -171,51 +165,6 @@

- - - - - {$t('settings.organization.organization_profile.customize_lms.heading')} - {$t('settings.organization.organization_profile.customize_lms.sub_heading')} - {$t('settings.organization.organization_profile.customize_lms.body')} - - - - - - - - - {$t('settings.organization.organization_profile.custom_domain.heading')} - {$t('settings.organization.organization_profile.custom_domain.sub_heading')} - {$t('settings.organization.organization_profile.custom_domain.body')} - - - - - - - - - {$t('settings.organization.organization_profile.team.heading')} - {$t('settings.organization.organization_profile.team.sub_heading')} - {$t('settings.organization.organization_profile.team.body')} - - - - diff --git a/packages/ui/src/custom/simple-logo-nav/simple-logo-nav.svelte b/packages/ui/src/custom/simple-logo-nav/simple-logo-nav.svelte index fdb1e08d..8c520bcc 100644 --- a/packages/ui/src/custom/simple-logo-nav/simple-logo-nav.svelte +++ b/packages/ui/src/custom/simple-logo-nav/simple-logo-nav.svelte @@ -11,7 +11,5 @@ ClassroomIO -

- The Most Customizable Platform for Customer, Partner, and Employee Education -

+

One Platform for Customer, Partner, and Employee Training

diff --git a/packages/ui/src/output.css b/packages/ui/src/output.css index f566f36e..a9b942a0 100644 --- a/packages/ui/src/output.css +++ b/packages/ui/src/output.css @@ -1,2 +1,2 @@ /*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:"";--tw-outline-style:solid;--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0;--border-angle:0deg}}}@layer theme{:root,:host{--ui-font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--ui-font-serif:ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;--ui-font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--ui-color-red-50:oklch(97.1% .013 17.38);--ui-color-red-500:oklch(63.7% .237 25.331);--ui-color-red-600:oklch(57.7% .245 27.325);--ui-color-red-700:oklch(50.5% .213 27.518);--ui-color-red-950:oklch(25.8% .092 26.042);--ui-color-orange-500:oklch(70.5% .213 47.604);--ui-color-amber-50:oklch(98.7% .022 95.277);--ui-color-amber-200:oklch(92.4% .12 95.746);--ui-color-amber-300:oklch(87.9% .169 91.605);--ui-color-amber-400:oklch(82.8% .189 84.429);--ui-color-amber-500:oklch(76.9% .188 70.08);--ui-color-amber-600:oklch(66.6% .179 58.318);--ui-color-amber-900:oklch(41.4% .112 45.904);--ui-color-amber-950:oklch(27.9% .077 45.635);--ui-color-yellow-500:oklch(79.5% .184 86.047);--ui-color-green-500:oklch(72.3% .219 149.579);--ui-color-green-600:oklch(62.7% .194 149.214);--ui-color-emerald-50:oklch(97.9% .021 166.113);--ui-color-emerald-300:oklch(84.5% .143 164.978);--ui-color-emerald-400:oklch(76.5% .177 163.223);--ui-color-emerald-500:oklch(69.6% .17 162.48);--ui-color-emerald-600:oklch(59.6% .145 163.225);--ui-color-emerald-700:oklch(50.8% .118 165.612);--ui-color-emerald-950:oklch(26.2% .051 172.552);--ui-color-sky-50:oklch(97.7% .013 236.62);--ui-color-sky-200:oklch(90.1% .058 230.902);--ui-color-sky-900:oklch(39.1% .09 240.876);--ui-color-sky-950:oklch(29.3% .066 243.157);--ui-color-blue-600:oklch(54.6% .245 262.881);--ui-color-violet-500:oklch(60.6% .25 292.717);--ui-color-pink-500:oklch(65.6% .241 354.308);--ui-color-rose-500:oklch(64.5% .246 16.439);--ui-color-slate-500:oklch(55.4% .046 257.417);--ui-color-slate-800:oklch(27.9% .041 260.031);--ui-color-slate-950:oklch(12.9% .042 264.695);--ui-color-gray-200:oklch(92.8% .006 264.531);--ui-color-gray-700:oklch(37.3% .034 259.733);--ui-color-zinc-100:oklch(96.7% .001 286.375);--ui-color-zinc-300:oklch(87.1% .006 286.286);--ui-color-zinc-400:oklch(70.5% .015 286.067);--ui-color-zinc-700:oklch(37% .013 285.805);--ui-color-zinc-800:oklch(27.4% .006 286.033);--ui-color-neutral-100:oklch(97% 0 0);--ui-color-neutral-400:oklch(70.8% 0 0);--ui-color-neutral-600:oklch(43.9% 0 0);--ui-color-neutral-800:oklch(26.9% 0 0);--ui-color-neutral-900:oklch(20.5% 0 0);--ui-color-black:#000;--ui-color-white:#fff;--ui-spacing:.25rem;--ui-container-xs:20rem;--ui-container-sm:24rem;--ui-container-md:28rem;--ui-container-lg:32rem;--ui-container-xl:36rem;--ui-container-2xl:42rem;--ui-container-3xl:48rem;--ui-container-4xl:56rem;--ui-container-5xl:64rem;--ui-container-7xl:80rem;--ui-text-xs:.75rem;--ui-text-xs--line-height:calc(1 / .75);--ui-text-sm:.875rem;--ui-text-sm--line-height:calc(1.25 / .875);--ui-text-base:1rem;--ui-text-base--line-height:calc(1.5 / 1);--ui-text-lg:1.125rem;--ui-text-lg--line-height:calc(1.75 / 1.125);--ui-text-xl:1.25rem;--ui-text-xl--line-height:calc(1.75 / 1.25);--ui-text-2xl:1.5rem;--ui-text-2xl--line-height:calc(2 / 1.5);--ui-text-3xl:1.875rem;--ui-text-3xl--line-height:calc(2.25 / 1.875);--ui-text-4xl:2.25rem;--ui-text-4xl--line-height:calc(2.5 / 2.25);--ui-text-5xl:3rem;--ui-text-5xl--line-height:1;--ui-text-6xl:3.75rem;--ui-text-6xl--line-height:1;--ui-text-7xl:4.5rem;--ui-text-7xl--line-height:1;--ui-font-weight-light:300;--ui-font-weight-normal:400;--ui-font-weight-medium:500;--ui-font-weight-semibold:600;--ui-font-weight-bold:700;--ui-font-weight-extrabold:800;--ui-font-weight-black:900;--ui-tracking-tighter:-.05em;--ui-tracking-tight:-.025em;--ui-tracking-wide:.025em;--ui-tracking-wider:.05em;--ui-tracking-widest:.1em;--ui-leading-tight:1.25;--ui-leading-snug:1.375;--ui-leading-normal:1.5;--ui-leading-relaxed:1.625;--ui-radius-xs:.125rem;--ui-radius-2xl:1rem;--ui-radius-3xl:1.5rem;--ui-drop-shadow-sm:0 1px 2px #00000026;--ui-ease-out:cubic-bezier(0, 0, .2, 1);--ui-ease-in-out:cubic-bezier(.4, 0, .2, 1);--ui-animate-spin:spin 1s linear infinite;--ui-animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--ui-blur-sm:8px;--ui-blur-md:12px;--ui-blur-xl:24px;--ui-blur-2xl:40px;--ui-blur-3xl:64px;--ui-aspect-video:16 / 9;--ui-default-transition-duration:.15s;--ui-default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--ui-default-mono-font-family:var(--ui-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(--font-cio,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--ui-default-font-feature-settings,normal);font-variation-settings:var(--ui-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(--ui-default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--ui-default-mono-font-feature-settings,normal);font-variation-settings:var(--ui-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}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){*{outline-color:color-mix(in oklab, var(--ring) 50%, transparent)}}body{background-color:var(--background);font-family:var(--font-sans);color:var(--foreground)}button,input,select,optgroup,textarea{font-family:var(--font-sans)}::file-selector-button{font-family:var(--font-sans)}.toaster{--normal-bg:var(--color-popover);--normal-text:var(--color-popover-foreground);--normal-border:var(--color-border)}}@layer components{.cio-marketing-border-beam{pointer-events:none;border-radius:inherit;border:calc(var(--border-width) * 1px) solid transparent;-webkit-mask-composite:source-in;-webkit-mask-source-type:auto,auto;position:absolute;inset:0;-webkit-mask-image:linear-gradient(#0000,#0000),linear-gradient(#fff,#fff);mask-image:linear-gradient(#0000,#0000),linear-gradient(#fff,#fff);-webkit-mask-position:0 0,0 0;mask-position:0 0,0 0;-webkit-mask-size:auto,auto;mask-size:auto,auto;-webkit-mask-repeat:repeat,repeat;mask-repeat:repeat,repeat;-webkit-mask-clip:padding-box,border-box;mask-clip:padding-box,border-box;-webkit-mask-origin:border-box,border-box;mask-origin:border-box,border-box;-webkit-mask-composite:source-in;mask-composite:intersect;-webkit-mask-source-type:auto,auto;mask-mode:match-source,match-source}.cio-marketing-border-beam:after{content:"";aspect-ratio:1;width:calc(var(--size) * 1px);animation-delay:var(--delay);background:linear-gradient(to left, var(--color-from), var(--color-to), transparent);offset-anchor:calc(var(--anchor) * 1%) 50%;offset-path:rect(0 auto auto 0 round calc(var(--size) * 1px));animation:border-beam calc(var(--duration) * 1s) infinite linear;position:absolute}}@layer utilities{.ui\:\@container\/field-group{container:field-group/inline-size}.ui\:\@container{container-type:inline-size}.ui\:\@container-\[size\]{container-type:size}.ui\:pointer-events-none{pointer-events:none}.ui\:sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.ui\:absolute{position:absolute}.ui\:fixed{position:fixed}.ui\:relative{position:relative}.ui\:sticky{position:sticky}.ui\:-inset-full{inset:-100%}.ui\:-inset-px{inset:-1px}.ui\:inset-\(--cut\){inset:var(--cut)}.ui\:inset-0{inset:calc(var(--ui-spacing) * 0)}.ui\:inset-x-0{inset-inline:calc(var(--ui-spacing) * 0)}.ui\:inset-x-\[-10\%\]{inset-inline:-10%}.ui\:inset-y-0{inset-block:calc(var(--ui-spacing) * 0)}.ui\:start-0{inset-inline-start:calc(var(--ui-spacing) * 0)}.ui\:end-4{inset-inline-end:calc(var(--ui-spacing) * 4)}.ui\:-top-2{top:calc(var(--ui-spacing) * -2)}.ui\:-top-3{top:calc(var(--ui-spacing) * -3)}.ui\:-top-16{top:calc(var(--ui-spacing) * -16)}.ui\:-top-20{top:calc(var(--ui-spacing) * -20)}.ui\:-top-32{top:calc(var(--ui-spacing) * -32)}.ui\:top-0{top:calc(var(--ui-spacing) * 0)}.ui\:top-1\.5{top:calc(var(--ui-spacing) * 1.5)}.ui\:top-1\/2{top:50%}.ui\:top-2{top:calc(var(--ui-spacing) * 2)}.ui\:top-3{top:calc(var(--ui-spacing) * 3)}.ui\:top-3\.5{top:calc(var(--ui-spacing) * 3.5)}.ui\:top-4{top:calc(var(--ui-spacing) * 4)}.ui\:top-11{top:calc(var(--ui-spacing) * 11)}.ui\:top-12{top:calc(var(--ui-spacing) * 12)}.ui\:top-\[-12px\]{top:-12px}.ui\:top-\[6px\]{top:6px}.ui\:top-\[50\%\]{top:50%}.ui\:top-\[60\%\]{top:60%}.ui\:top-full{top:100%}.ui\:top-px{top:1px}.ui\:-right-4{right:calc(var(--ui-spacing) * -4)}.ui\:right-0{right:calc(var(--ui-spacing) * 0)}.ui\:right-1{right:calc(var(--ui-spacing) * 1)}.ui\:right-2{right:calc(var(--ui-spacing) * 2)}.ui\:right-3{right:calc(var(--ui-spacing) * 3)}.ui\:right-3\.5{right:calc(var(--ui-spacing) * 3.5)}.ui\:right-4{right:calc(var(--ui-spacing) * 4)}.ui\:right-9{right:calc(var(--ui-spacing) * 9)}.ui\:right-\[-10\%\]{right:-10%}.ui\:right-\[-12px\]{right:-12px}.ui\:-bottom-px{bottom:-1px}.ui\:bottom-0{bottom:calc(var(--ui-spacing) * 0)}.ui\:bottom-2{bottom:calc(var(--ui-spacing) * 2)}.ui\:bottom-3{bottom:calc(var(--ui-spacing) * 3)}.ui\:bottom-3\.5{bottom:calc(var(--ui-spacing) * 3.5)}.ui\:bottom-4{bottom:calc(var(--ui-spacing) * 4)}.ui\:bottom-\[-50\%\]{bottom:-50%}.ui\:bottom-\[-220px\]{bottom:-220px}.ui\:bottom-full{bottom:100%}.ui\:-left-24{left:calc(var(--ui-spacing) * -24)}.ui\:left-0{left:calc(var(--ui-spacing) * 0)}.ui\:left-1\/2{left:50%}.ui\:left-2{left:calc(var(--ui-spacing) * 2)}.ui\:left-3{left:calc(var(--ui-spacing) * 3)}.ui\:left-3\.5{left:calc(var(--ui-spacing) * 3.5)}.ui\:left-\[50\%\]{left:50%}.ui\:left-\[calc\(50\%-3rem\)\]{left:calc(50% - 3rem)}.ui\:left-auto{left:auto}.ui\:left-full{left:100%}.ui\:isolate{isolation:isolate}.ui\:-z-10{z-index:calc(10 * -1)}.ui\:-z-20{z-index:calc(20 * -1)}.ui\:-z-30{z-index:calc(30 * -1)}.ui\:z-0{z-index:0}.ui\:z-1{z-index:1}.ui\:z-10{z-index:10}.ui\:z-20{z-index:20}.ui\:z-30{z-index:30}.ui\:z-40{z-index:40}.ui\:z-50{z-index:50}.ui\:z-100{z-index:100}.ui\:z-200{z-index:200}.ui\:z-999{z-index:999}.ui\:z-\[1\]{z-index:1}.ui\:z-\[110\]{z-index:110}.ui\:order-first{order:-9999}.ui\:order-last{order:9999}.ui\:col-start-2{grid-column-start:2}.ui\:row-span-2{grid-row:span 2/span 2}.ui\:row-start-1{grid-row-start:1}.ui\:m-0{margin:calc(var(--ui-spacing) * 0)}.ui\:m-0\!{margin:calc(var(--ui-spacing) * 0)!important}.ui\:-mx-1{margin-inline:calc(var(--ui-spacing) * -1)}.ui\:-mx-6{margin-inline:calc(var(--ui-spacing) * -6)}.ui\:-mx-\[2\.5px\]{margin-inline:-2.5px}.ui\:-mx-\[2px\]{margin-inline:-2px}.ui\:mx-0\.5{margin-inline:calc(var(--ui-spacing) * .5)}.ui\:mx-2{margin-inline:calc(var(--ui-spacing) * 2)}.ui\:mx-4{margin-inline:calc(var(--ui-spacing) * 4)}.ui\:mx-5{margin-inline:calc(var(--ui-spacing) * 5)}.ui\:mx-auto{margin-inline:auto}.ui\:my-0{margin-block:calc(var(--ui-spacing) * 0)}.ui\:my-0\.5{margin-block:calc(var(--ui-spacing) * .5)}.ui\:my-1{margin-block:calc(var(--ui-spacing) * 1)}.ui\:my-2{margin-block:calc(var(--ui-spacing) * 2)}.ui\:my-3{margin-block:calc(var(--ui-spacing) * 3)}.ui\:my-4{margin-block:calc(var(--ui-spacing) * 4)}.ui\:my-10{margin-block:calc(var(--ui-spacing) * 10)}.ui\:ms-1{margin-inline-start:calc(var(--ui-spacing) * 1)}.ui\:ms-4{margin-inline-start:calc(var(--ui-spacing) * 4)}.ui\:-mt-1{margin-top:calc(var(--ui-spacing) * -1)}.ui\:mt-0\.5{margin-top:calc(var(--ui-spacing) * .5)}.ui\:mt-1{margin-top:calc(var(--ui-spacing) * 1)}.ui\:mt-1\.5{margin-top:calc(var(--ui-spacing) * 1.5)}.ui\:mt-2{margin-top:calc(var(--ui-spacing) * 2)}.ui\:mt-3{margin-top:calc(var(--ui-spacing) * 3)}.ui\:mt-4{margin-top:calc(var(--ui-spacing) * 4)}.ui\:mt-6{margin-top:calc(var(--ui-spacing) * 6)}.ui\:mt-7{margin-top:calc(var(--ui-spacing) * 7)}.ui\:mt-8{margin-top:calc(var(--ui-spacing) * 8)}.ui\:mt-9{margin-top:calc(var(--ui-spacing) * 9)}.ui\:mt-10{margin-top:calc(var(--ui-spacing) * 10)}.ui\:mt-12{margin-top:calc(var(--ui-spacing) * 12)}.ui\:mt-14{margin-top:calc(var(--ui-spacing) * 14)}.ui\:mt-16{margin-top:calc(var(--ui-spacing) * 16)}.ui\:mt-auto{margin-top:auto}.ui\:mr-1{margin-right:calc(var(--ui-spacing) * 1)}.ui\:mr-2{margin-right:calc(var(--ui-spacing) * 2)}.ui\:-mb-6{margin-bottom:calc(var(--ui-spacing) * -6)}.ui\:mb-1{margin-bottom:calc(var(--ui-spacing) * 1)}.ui\:mb-1\.5{margin-bottom:calc(var(--ui-spacing) * 1.5)}.ui\:mb-2{margin-bottom:calc(var(--ui-spacing) * 2)}.ui\:mb-2\.5{margin-bottom:calc(var(--ui-spacing) * 2.5)}.ui\:mb-3{margin-bottom:calc(var(--ui-spacing) * 3)}.ui\:mb-4{margin-bottom:calc(var(--ui-spacing) * 4)}.ui\:mb-5{margin-bottom:calc(var(--ui-spacing) * 5)}.ui\:mb-6{margin-bottom:calc(var(--ui-spacing) * 6)}.ui\:mb-7{margin-bottom:calc(var(--ui-spacing) * 7)}.ui\:mb-8{margin-bottom:calc(var(--ui-spacing) * 8)}.ui\:mb-9{margin-bottom:calc(var(--ui-spacing) * 9)}.ui\:mb-10{margin-bottom:calc(var(--ui-spacing) * 10)}.ui\:mb-12{margin-bottom:calc(var(--ui-spacing) * 12)}.ui\:mb-14{margin-bottom:calc(var(--ui-spacing) * 14)}.ui\:mb-16{margin-bottom:calc(var(--ui-spacing) * 16)}.ui\:ml-1{margin-left:calc(var(--ui-spacing) * 1)}.ui\:ml-2{margin-left:calc(var(--ui-spacing) * 2)}.ui\:ml-2\.5{margin-left:calc(var(--ui-spacing) * 2.5)}.ui\:ml-auto{margin-left:auto}.ui\:box-border{box-sizing:border-box}.ui\:line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.ui\:line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.ui\:line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.ui\:block{display:block}.ui\:flex{display:flex}.ui\:grid{display:grid}.ui\:hidden{display:none}.ui\:inline-block{display:inline-block}.ui\:inline-flex{display:inline-flex}.ui\:field-sizing-content{field-sizing:content}.ui\:aspect-\[1\],.ui\:aspect-square{aspect-ratio:1}.ui\:aspect-video{aspect-ratio:var(--ui-aspect-video)}.ui\:\!size-6{width:calc(var(--ui-spacing) * 6)!important;height:calc(var(--ui-spacing) * 6)!important}.ui\:size-1{width:calc(var(--ui-spacing) * 1);height:calc(var(--ui-spacing) * 1)}.ui\:size-1\.5{width:calc(var(--ui-spacing) * 1.5);height:calc(var(--ui-spacing) * 1.5)}.ui\:size-2{width:calc(var(--ui-spacing) * 2);height:calc(var(--ui-spacing) * 2)}.ui\:size-2\.5{width:calc(var(--ui-spacing) * 2.5);height:calc(var(--ui-spacing) * 2.5)}.ui\:size-3{width:calc(var(--ui-spacing) * 3);height:calc(var(--ui-spacing) * 3)}.ui\:size-3\.5{width:calc(var(--ui-spacing) * 3.5);height:calc(var(--ui-spacing) * 3.5)}.ui\:size-4{width:calc(var(--ui-spacing) * 4);height:calc(var(--ui-spacing) * 4)}.ui\:size-5{width:calc(var(--ui-spacing) * 5);height:calc(var(--ui-spacing) * 5)}.ui\:size-6{width:calc(var(--ui-spacing) * 6);height:calc(var(--ui-spacing) * 6)}.ui\:size-7{width:calc(var(--ui-spacing) * 7);height:calc(var(--ui-spacing) * 7)}.ui\:size-8{width:calc(var(--ui-spacing) * 8);height:calc(var(--ui-spacing) * 8)}.ui\:size-9{width:calc(var(--ui-spacing) * 9);height:calc(var(--ui-spacing) * 9)}.ui\:size-10{width:calc(var(--ui-spacing) * 10);height:calc(var(--ui-spacing) * 10)}.ui\:size-11{width:calc(var(--ui-spacing) * 11);height:calc(var(--ui-spacing) * 11)}.ui\:size-12{width:calc(var(--ui-spacing) * 12);height:calc(var(--ui-spacing) * 12)}.ui\:size-14{width:calc(var(--ui-spacing) * 14);height:calc(var(--ui-spacing) * 14)}.ui\:size-14\!{width:calc(var(--ui-spacing) * 14)!important;height:calc(var(--ui-spacing) * 14)!important}.ui\:size-16{width:calc(var(--ui-spacing) * 16);height:calc(var(--ui-spacing) * 16)}.ui\:size-20{width:calc(var(--ui-spacing) * 20);height:calc(var(--ui-spacing) * 20)}.ui\:size-24{width:calc(var(--ui-spacing) * 24);height:calc(var(--ui-spacing) * 24)}.ui\:size-28{width:calc(var(--ui-spacing) * 28);height:calc(var(--ui-spacing) * 28)}.ui\:size-32{width:calc(var(--ui-spacing) * 32);height:calc(var(--ui-spacing) * 32)}.ui\:size-\[2\.4px\]{width:2.4px;height:2.4px}.ui\:size-\[11px\]{width:11px;height:11px}.ui\:size-\[22px\]{width:22px;height:22px}.ui\:size-\[640px\]{width:640px;height:640px}.ui\:size-\[800px\]{width:800px;height:800px}.ui\:size-fit{width:fit-content;height:fit-content}.ui\:size-full{width:100%;height:100%}.ui\:h-\(--bits-navigation-menu-viewport-height\){height:var(--bits-navigation-menu-viewport-height)}.ui\:h-\(--bits-select-anchor-height\){height:var(--bits-select-anchor-height)}.ui\:h-0{height:calc(var(--ui-spacing) * 0)}.ui\:h-0\.5{height:calc(var(--ui-spacing) * .5)}.ui\:h-0\.5\!{height:calc(var(--ui-spacing) * .5)!important}.ui\:h-1{height:calc(var(--ui-spacing) * 1)}.ui\:h-1\.5{height:calc(var(--ui-spacing) * 1.5)}.ui\:h-2{height:calc(var(--ui-spacing) * 2)}.ui\:h-2\.5{height:calc(var(--ui-spacing) * 2.5)}.ui\:h-3{height:calc(var(--ui-spacing) * 3)}.ui\:h-4{height:calc(var(--ui-spacing) * 4)}.ui\:h-5{height:calc(var(--ui-spacing) * 5)}.ui\:h-6{height:calc(var(--ui-spacing) * 6)}.ui\:h-7{height:calc(var(--ui-spacing) * 7)}.ui\:h-8{height:calc(var(--ui-spacing) * 8)}.ui\:h-9{height:calc(var(--ui-spacing) * 9)}.ui\:h-10{height:calc(var(--ui-spacing) * 10)}.ui\:h-12{height:calc(var(--ui-spacing) * 12)}.ui\:h-14{height:calc(var(--ui-spacing) * 14)}.ui\:h-16{height:calc(var(--ui-spacing) * 16)}.ui\:h-20{height:calc(var(--ui-spacing) * 20)}.ui\:h-24{height:calc(var(--ui-spacing) * 24)}.ui\:h-28{height:calc(var(--ui-spacing) * 28)}.ui\:h-40{height:calc(var(--ui-spacing) * 40)}.ui\:h-48{height:calc(var(--ui-spacing) * 48)}.ui\:h-50\!{height:calc(var(--ui-spacing) * 50)!important}.ui\:h-96{height:calc(var(--ui-spacing) * 96)}.ui\:h-128{height:calc(var(--ui-spacing) * 128)}.ui\:h-\[1\.2rem\]{height:1.2rem}.ui\:h-\[1\.15rem\]{height:1.15rem}.ui\:h-\[6px\]{height:6px}.ui\:h-\[10px\]{height:10px}.ui\:h-\[14px\]{height:14px}.ui\:h-\[22px\]{height:22px}.ui\:h-\[70px\]{height:70px}.ui\:h-\[72px\]{height:72px}.ui\:h-\[100cqh\]{height:100cqh}.ui\:h-\[168px\]{height:168px}.ui\:h-\[180px\]{height:180px}.ui\:h-\[200px\]{height:200px}.ui\:h-\[280px\]{height:280px}.ui\:h-\[380px\]{height:380px}.ui\:h-\[420px\]{height:420px}.ui\:h-\[440px\]{height:440px}.ui\:h-\[460px\]{height:460px}.ui\:h-\[500px\]{height:500px}.ui\:h-\[520px\]{height:520px}.ui\:h-\[680px\]{height:680px}.ui\:h-\[calc\(100\%-1px\)\]{height:calc(100% - 1px)}.ui\:h-\[calc\(100\%-3px\)\]{height:calc(100% - 3px)}.ui\:h-\[calc\(100dvh-3rem\)\]{height:calc(100dvh - 3rem)}.ui\:h-auto{height:auto}.ui\:h-fit{height:fit-content}.ui\:h-fit\!{height:fit-content!important}.ui\:h-full{height:100%}.ui\:h-px{height:1px}.ui\:h-screen{height:100vh}.ui\:max-h-\(--bits-dropdown-menu-content-available-height\){max-height:var(--bits-dropdown-menu-content-available-height)}.ui\:max-h-\(--bits-select-content-available-height\){max-height:var(--bits-select-content-available-height)}.ui\:max-h-32{max-height:calc(var(--ui-spacing) * 32)}.ui\:max-h-52{max-height:calc(var(--ui-spacing) * 52)}.ui\:max-h-60{max-height:calc(var(--ui-spacing) * 60)}.ui\:max-h-64{max-height:calc(var(--ui-spacing) * 64)}.ui\:max-h-72{max-height:calc(var(--ui-spacing) * 72)}.ui\:max-h-80{max-height:calc(var(--ui-spacing) * 80)}.ui\:max-h-90{max-height:calc(var(--ui-spacing) * 90)}.ui\:max-h-96{max-height:calc(var(--ui-spacing) * 96)}.ui\:max-h-\[85vh\]{max-height:85vh}.ui\:max-h-\[300px\]{max-height:300px}.ui\:max-h-svh{max-height:100svh}.ui\:min-h-0{min-height:calc(var(--ui-spacing) * 0)}.ui\:min-h-4{min-height:calc(var(--ui-spacing) * 4)}.ui\:min-h-8{min-height:calc(var(--ui-spacing) * 8)}.ui\:min-h-14{min-height:calc(var(--ui-spacing) * 14)}.ui\:min-h-16{min-height:calc(var(--ui-spacing) * 16)}.ui\:min-h-40{min-height:calc(var(--ui-spacing) * 40)}.ui\:min-h-96{min-height:calc(var(--ui-spacing) * 96)}.ui\:min-h-\[32rem\]{min-height:32rem}.ui\:min-h-\[44px\]{min-height:44px}.ui\:min-h-\[63px\]{min-height:63px}.ui\:min-h-\[240px\]{min-height:240px}.ui\:min-h-\[320px\]{min-height:320px}.ui\:min-h-\[calc\(100dvh-3rem\)\]{min-height:calc(100dvh - 3rem)}.ui\:min-h-\[calc\(100vh-48px\)\]{min-height:calc(100vh - 48px)}.ui\:min-h-dvh{min-height:100dvh}.ui\:min-h-screen{min-height:100vh}.ui\:w-\(--sidebar-width\){width:var(--sidebar-width)}.ui\:w-0{width:calc(var(--ui-spacing) * 0)}.ui\:w-1{width:calc(var(--ui-spacing) * 1)}.ui\:w-1\.5{width:calc(var(--ui-spacing) * 1.5)}.ui\:w-1\/4{width:25%}.ui\:w-2{width:calc(var(--ui-spacing) * 2)}.ui\:w-2\.5{width:calc(var(--ui-spacing) * 2.5)}.ui\:w-2\/4{width:50%}.ui\:w-3\/4{width:75%}.ui\:w-4{width:calc(var(--ui-spacing) * 4)}.ui\:w-5{width:calc(var(--ui-spacing) * 5)}.ui\:w-6{width:calc(var(--ui-spacing) * 6)}.ui\:w-7{width:calc(var(--ui-spacing) * 7)}.ui\:w-8{width:calc(var(--ui-spacing) * 8)}.ui\:w-10{width:calc(var(--ui-spacing) * 10)}.ui\:w-14{width:calc(var(--ui-spacing) * 14)}.ui\:w-16{width:calc(var(--ui-spacing) * 16)}.ui\:w-20{width:calc(var(--ui-spacing) * 20)}.ui\:w-24{width:calc(var(--ui-spacing) * 24)}.ui\:w-28{width:calc(var(--ui-spacing) * 28)}.ui\:w-40{width:calc(var(--ui-spacing) * 40)}.ui\:w-48{width:calc(var(--ui-spacing) * 48)}.ui\:w-52{width:calc(var(--ui-spacing) * 52)}.ui\:w-64{width:calc(var(--ui-spacing) * 64)}.ui\:w-72{width:calc(var(--ui-spacing) * 72)}.ui\:w-88{width:calc(var(--ui-spacing) * 88)}.ui\:w-96{width:calc(var(--ui-spacing) * 96)}.ui\:w-\[1\.2rem\]{width:1.2rem}.ui\:w-\[10px\]{width:10px}.ui\:w-\[25px\]{width:25px}.ui\:w-\[50px\]{width:50px}.ui\:w-\[80\%\]{width:80%}.ui\:w-\[84\%\]{width:84%}.ui\:w-\[100px\]{width:100px}.ui\:w-\[260px\]{width:260px}.ui\:w-\[420px\]{width:420px}.ui\:w-\[520px\]{width:520px}.ui\:w-auto{width:auto}.ui\:w-fit{width:fit-content}.ui\:w-fit\!{width:fit-content!important}.ui\:w-full{width:100%}.ui\:w-full\!{width:100%!important}.ui\:w-max{width:max-content}.ui\:w-px{width:1px}.ui\:w-screen{width:100vw}.ui\:max-w-\(--skeleton-width\){max-width:var(--skeleton-width)}.ui\:max-w-2xl{max-width:var(--ui-container-2xl)}.ui\:max-w-3xl{max-width:var(--ui-container-3xl)}.ui\:max-w-4xl{max-width:var(--ui-container-4xl)}.ui\:max-w-5xl{max-width:var(--ui-container-5xl)}.ui\:max-w-6{max-width:calc(var(--ui-spacing) * 6)}.ui\:max-w-7xl{max-width:var(--ui-container-7xl)}.ui\:max-w-40{max-width:calc(var(--ui-spacing) * 40)}.ui\:max-w-80{max-width:calc(var(--ui-spacing) * 80)}.ui\:max-w-\[16rem\]{max-width:16rem}.ui\:max-w-\[18ch\]{max-width:18ch}.ui\:max-w-\[20ch\]{max-width:20ch}.ui\:max-w-\[55vw\]{max-width:55vw}.ui\:max-w-\[60\%\]{max-width:60%}.ui\:max-w-\[200px\]{max-width:200px}.ui\:max-w-\[240px\]{max-width:240px}.ui\:max-w-\[260px\]{max-width:260px}.ui\:max-w-\[280px\]{max-width:280px}.ui\:max-w-\[300px\]{max-width:300px}.ui\:max-w-\[320px\]{max-width:320px}.ui\:max-w-\[480px\]{max-width:480px}.ui\:max-w-\[520px\]{max-width:520px}.ui\:max-w-\[600px\]{max-width:600px}.ui\:max-w-\[640px\]{max-width:640px}.ui\:max-w-\[700px\]{max-width:700px}.ui\:max-w-\[820px\]{max-width:820px}.ui\:max-w-\[880px\]{max-width:880px}.ui\:max-w-\[1080px\]{max-width:1080px}.ui\:max-w-\[1100px\]{max-width:1100px}.ui\:max-w-\[1120px\]{max-width:1120px}.ui\:max-w-\[1180px\]{max-width:1180px}.ui\:max-w-\[1200px\]{max-width:1200px}.ui\:max-w-\[1240px\]{max-width:1240px}.ui\:max-w-\[1280px\]{max-width:1280px}.ui\:max-w-\[1320px\]{max-width:1320px}.ui\:max-w-\[calc\(100\%-2rem\)\]{max-width:calc(100% - 2rem)}.ui\:max-w-full{max-width:100%}.ui\:max-w-max{max-width:max-content}.ui\:max-w-md{max-width:var(--ui-container-md)}.ui\:max-w-none{max-width:none}.ui\:max-w-sm{max-width:var(--ui-container-sm)}.ui\:max-w-xl{max-width:var(--ui-container-xl)}.ui\:max-w-xs{max-width:var(--ui-container-xs)}.ui\:min-w-\(--bits-select-anchor-width\){min-width:var(--bits-select-anchor-width)}.ui\:min-w-0{min-width:calc(var(--ui-spacing) * 0)}.ui\:min-w-5{min-width:calc(var(--ui-spacing) * 5)}.ui\:min-w-7{min-width:calc(var(--ui-spacing) * 7)}.ui\:min-w-8{min-width:calc(var(--ui-spacing) * 8)}.ui\:min-w-9{min-width:calc(var(--ui-spacing) * 9)}.ui\:min-w-10{min-width:calc(var(--ui-spacing) * 10)}.ui\:min-w-18{min-width:calc(var(--ui-spacing) * 18)}.ui\:min-w-32{min-width:calc(var(--ui-spacing) * 32)}.ui\:min-w-48{min-width:calc(var(--ui-spacing) * 48)}.ui\:min-w-\[3ch\]{min-width:3ch}.ui\:min-w-\[5rem\]{min-width:5rem}.ui\:min-w-\[9rem\]{min-width:9rem}.ui\:min-w-\[min\(24rem\,calc\(100vw-5rem\)\)\]{min-width:min(24rem,100vw - 5rem)}.ui\:min-w-full{min-width:100%}.ui\:flex-1{flex:1}.ui\:flex-shrink-0{flex-shrink:0}.ui\:shrink{flex-shrink:1}.ui\:shrink-0{flex-shrink:0}.ui\:basis-full{flex-basis:100%}.ui\:origin-\(--bits-dropdown-menu-content-transform-origin\){transform-origin:var(--bits-dropdown-menu-content-transform-origin)}.ui\:origin-\(--bits-menubar-content-transform-origin\){transform-origin:var(--bits-menubar-content-transform-origin)}.ui\:origin-\(--bits-popover-content-transform-origin\){transform-origin:var(--bits-popover-content-transform-origin)}.ui\:origin-\(--bits-select-content-transform-origin\){transform-origin:var(--bits-select-content-transform-origin)}.ui\:origin-\(--bits-tooltip-content-transform-origin\){transform-origin:var(--bits-tooltip-content-transform-origin)}.ui\:origin-center{transform-origin:50%}.ui\:-translate-x-0{--tw-translate-x:calc(var(--ui-spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:-translate-x-full{--tw-translate-x:-100%;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:-translate-x-px{--tw-translate-x:-1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-x-3{--tw-translate-x:calc(var(--ui-spacing) * 3);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-x-4{--tw-translate-x:calc(var(--ui-spacing) * 4);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-x-\[-50\%\]{--tw-translate-x:-50%;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-x-px{--tw-translate-x:1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:-translate-y-full{--tw-translate-y:-100%;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-y-0\.5{--tw-translate-y:calc(var(--ui-spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-y-3{--tw-translate-y:calc(var(--ui-spacing) * 3);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-y-4{--tw-translate-y:calc(var(--ui-spacing) * 4);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-y-\[-50\%\]{--tw-translate-y:-50%;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:\[translate\:0_0\]{translate:0}.ui\:scale-0{--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x) var(--tw-scale-y)}.ui\:scale-100{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}.ui\:-rotate-90{rotate:-90deg}.ui\:rotate-0{rotate:none}.ui\:rotate-5{rotate:5deg}.ui\:rotate-45{rotate:45deg}.ui\:rotate-90{rotate:90deg}.ui\:\[transform\:scaleX\(-1\)\]{transform:scaleX(-1)}.ui\:transform-gpu{transform:translateZ(0) var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.ui\:animate-in{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:animate-magicslide{animation:magicslide var(--speed) ease-in-out infinite alternate}.ui\:animate-meteor{animation:5s linear infinite meteor}.ui\:animate-pulse{animation:var(--ui-animate-pulse)}.ui\:animate-shine{animation:2s linear infinite shine}.ui\:animate-spin{animation:var(--ui-animate-spin)}.ui\:animate-spin-around{animation:spin-around calc(var(--speed) * 2) infinite linear}.ui\:cursor-auto{cursor:auto}.ui\:cursor-col-resize{cursor:col-resize}.ui\:cursor-default{cursor:default}.ui\:cursor-default\!{cursor:default!important}.ui\:cursor-grab{cursor:grab}.ui\:cursor-not-allowed{cursor:not-allowed}.ui\:cursor-pointer{cursor:pointer}.ui\:cursor-text{cursor:text}.ui\:resize-none{resize:none}.ui\:scroll-my-1{scroll-margin-block:calc(var(--ui-spacing) * 1)}.ui\:scroll-py-1{scroll-padding-block:calc(var(--ui-spacing) * 1)}.ui\:list-disc{list-style-type:disc}.ui\:list-none{list-style-type:none}.ui\:auto-rows-min{grid-auto-rows:min-content}.ui\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ui\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ui\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.ui\:grid-cols-\[0_1fr\]{grid-template-columns:0 1fr}.ui\:grid-cols-\[1fr_auto_1fr\]{grid-template-columns:1fr auto 1fr}.ui\:grid-cols-\[6px_6px\]{grid-template-columns:6px 6px}.ui\:grid-rows-\[auto_auto\]{grid-template-rows:auto auto}.ui\:flex-col{flex-direction:column}.ui\:flex-col-reverse{flex-direction:column-reverse}.ui\:flex-row{flex-direction:row}.ui\:flex-nowrap\!{flex-wrap:nowrap!important}.ui\:flex-wrap{flex-wrap:wrap}.ui\:place-content-between{place-content:space-between}.ui\:place-content-center{place-content:center}.ui\:place-items-center{place-items:center}.ui\:items-baseline{align-items:baseline}.ui\:items-center{align-items:center}.ui\:items-end{align-items:flex-end}.ui\:items-start{align-items:flex-start}.ui\:items-stretch{align-items:stretch}.ui\:justify-around{justify-content:space-around}.ui\:justify-between{justify-content:space-between}.ui\:justify-center{justify-content:center}.ui\:justify-end{justify-content:flex-end}.ui\:justify-start{justify-content:flex-start}.ui\:justify-start\!{justify-content:flex-start!important}.ui\:justify-items-center{justify-items:center}.ui\:justify-items-start{justify-items:start}.ui\:gap-0{gap:calc(var(--ui-spacing) * 0)}.ui\:gap-0\.5{gap:calc(var(--ui-spacing) * .5)}.ui\:gap-1{gap:calc(var(--ui-spacing) * 1)}.ui\:gap-1\.5{gap:calc(var(--ui-spacing) * 1.5)}.ui\:gap-2{gap:calc(var(--ui-spacing) * 2)}.ui\:gap-2\.5{gap:calc(var(--ui-spacing) * 2.5)}.ui\:gap-3{gap:calc(var(--ui-spacing) * 3)}.ui\:gap-4{gap:calc(var(--ui-spacing) * 4)}.ui\:gap-5{gap:calc(var(--ui-spacing) * 5)}.ui\:gap-6{gap:calc(var(--ui-spacing) * 6)}.ui\:gap-7{gap:calc(var(--ui-spacing) * 7)}.ui\:gap-8{gap:calc(var(--ui-spacing) * 8)}.ui\:gap-10{gap:calc(var(--ui-spacing) * 10)}.ui\:gap-12{gap:calc(var(--ui-spacing) * 12)}.ui\:gap-16{gap:calc(var(--ui-spacing) * 16)}.ui\:gap-20{gap:calc(var(--ui-spacing) * 20)}.ui\:gap-\[1px\]{gap:1px}.ui\:gap-\[14px\]{gap:14px}.ui\:gap-px{gap:1px}:where(.ui\:space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.ui\:space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.ui\:space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.ui\:space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.ui\:space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.ui\:space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.ui\:gap-x-3{column-gap:calc(var(--ui-spacing) * 3)}.ui\:gap-x-4{column-gap:calc(var(--ui-spacing) * 4)}.ui\:gap-x-5{column-gap:calc(var(--ui-spacing) * 5)}.ui\:gap-x-6{column-gap:calc(var(--ui-spacing) * 6)}.ui\:gap-x-8{column-gap:calc(var(--ui-spacing) * 8)}:where(.ui\:space-x-1>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--ui-spacing) * 1) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--ui-spacing) * 1) * calc(1 - var(--tw-space-x-reverse)))}:where(.ui\:space-x-8>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--ui-spacing) * 8) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--ui-spacing) * 8) * calc(1 - var(--tw-space-x-reverse)))}.ui\:gap-y-0\.5{row-gap:calc(var(--ui-spacing) * .5)}.ui\:gap-y-1{row-gap:calc(var(--ui-spacing) * 1)}.ui\:gap-y-2{row-gap:calc(var(--ui-spacing) * 2)}.ui\:gap-y-10{row-gap:calc(var(--ui-spacing) * 10)}.ui\:gap-y-12{row-gap:calc(var(--ui-spacing) * 12)}.ui\:place-self-end{place-self:end}.ui\:self-center{align-self:center}.ui\:self-start{align-self:flex-start}.ui\:self-stretch{align-self:stretch}.ui\:justify-self-center{justify-self:center}.ui\:justify-self-end{justify-self:flex-end}.ui\:truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ui\:overflow-auto{overflow:auto}.ui\:overflow-hidden{overflow:hidden}.ui\:overflow-visible{overflow:visible}.ui\:overflow-x-auto{overflow-x:auto}.ui\:overflow-x-hidden{overflow-x:hidden}.ui\:overflow-y-auto{overflow-y:auto}.ui\:overflow-y-hidden{overflow-y:hidden}.ui\:scroll-smooth{scroll-behavior:smooth}.ui\:\[border-radius\:9999px\]{border-radius:9999px}.ui\:\[border-radius\:var\(--landing-radius-card\)\]{border-radius:var(--landing-radius-card)}.ui\:\[border-radius\:var\(--landing-radius-pill\)\]{border-radius:var(--landing-radius-pill)}.ui\:rounded{border-radius:.25rem}.ui\:rounded-\(--radius\){border-radius:var(--radius)}.ui\:rounded-2xl{border-radius:var(--ui-radius-2xl)}.ui\:rounded-3xl{border-radius:var(--ui-radius-3xl)}.ui\:rounded-\[2px\]{border-radius:2px}.ui\:rounded-\[3px\]{border-radius:3px}.ui\:rounded-\[4px\]{border-radius:4px}.ui\:rounded-\[10px\]{border-radius:10px}.ui\:rounded-\[14px\]{border-radius:14px}.ui\:rounded-\[20px\]{border-radius:20px}.ui\:rounded-\[calc\(var\(--radius\)-5px\)\]{border-radius:calc(var(--radius) - 5px)}.ui\:rounded-full{border-radius:3.40282e38px}.ui\:rounded-lg{border-radius:var(--radius)}.ui\:rounded-md{border-radius:calc(var(--radius) - 2px)}.ui\:rounded-md\!{border-radius:calc(var(--radius) - 2px)!important}.ui\:rounded-none{border-radius:0}.ui\:rounded-sm{border-radius:calc(var(--radius) - 4px)}.ui\:rounded-xl{border-radius:calc(var(--radius) + 4px)}.ui\:rounded-xs{border-radius:var(--ui-radius-xs)}.ui\:rounded-t-md{border-top-left-radius:calc(var(--radius) - 2px);border-top-right-radius:calc(var(--radius) - 2px)}.ui\:rounded-t-xl{border-top-left-radius:calc(var(--radius) + 4px);border-top-right-radius:calc(var(--radius) + 4px)}.ui\:border{border-style:var(--tw-border-style);border-width:1px}.ui\:border-0{border-style:var(--tw-border-style);border-width:0}.ui\:border-0\!{border-style:var(--tw-border-style)!important;border-width:0!important}.ui\:border-2{border-style:var(--tw-border-style);border-width:2px}.ui\:border-\[1\.5px\]{border-style:var(--tw-border-style);border-width:1.5px}.ui\:border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.ui\:border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}.ui\:border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.ui\:border-y-\[10px\]{border-block-style:var(--tw-border-style);border-block-width:10px}.ui\:border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.ui\:border-t-2{border-top-style:var(--tw-border-style);border-top-width:2px}.ui\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.ui\:border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.ui\:border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.ui\:border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.ui\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.ui\:border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.ui\:border-l-\[16px\]{border-left-style:var(--tw-border-style);border-left-width:16px}.ui\:border-dashed{--tw-border-style:dashed;border-style:dashed}.ui\:border-none{--tw-border-style:none;border-style:none}.ui\:border-solid{--tw-border-style:solid;border-style:solid}.ui\:border-\(--color-border\){border-color:var(--color-border)}.ui\:border-\[\#1c1f28\]{border-color:#1c1f28}.ui\:border-\[\#262a35\]{border-color:#262a35}.ui\:border-\[\#d9d8d0\]{border-color:#d9d8d0}.ui\:border-\[var\(--landing-accent\)\]{border-color:var(--landing-accent)}.ui\:border-\[var\(--landing-accent-fg\)\],.ui\:border-\[var\(--landing-accent-fg\)\]\/15{border-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-accent-fg\)\]\/15{border-color:color-mix(in oklab, var(--landing-accent-fg) 15%, transparent)}}.ui\:border-\[var\(--landing-accent-fg\)\]\/20{border-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-accent-fg\)\]\/20{border-color:color-mix(in oklab, var(--landing-accent-fg) 20%, transparent)}}.ui\:border-\[var\(--landing-bg\)\]\/15{border-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-bg\)\]\/15{border-color:color-mix(in oklab, var(--landing-bg) 15%, transparent)}}.ui\:border-\[var\(--landing-bg\)\]\/40{border-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-bg\)\]\/40{border-color:color-mix(in oklab, var(--landing-bg) 40%, transparent)}}.ui\:border-\[var\(--landing-border\)\],.ui\:border-\[var\(--landing-border\)\]\/40{border-color:var(--landing-border)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-border\)\]\/40{border-color:color-mix(in oklab, var(--landing-border) 40%, transparent)}}.ui\:border-\[var\(--landing-border\)\]\/50{border-color:var(--landing-border)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-border\)\]\/50{border-color:color-mix(in oklab, var(--landing-border) 50%, transparent)}}.ui\:border-\[var\(--landing-border\)\]\/60{border-color:var(--landing-border)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-border\)\]\/60{border-color:color-mix(in oklab, var(--landing-border) 60%, transparent)}}.ui\:border-\[var\(--landing-border-soft\)\]{border-color:var(--landing-border-soft)}.ui\:border-\[var\(--landing-button-secondary-border\)\]{border-color:var(--landing-button-secondary-border)}.ui\:border-\[var\(--landing-fg\)\]{border-color:var(--landing-fg)}.ui\:border-amber-200{border-color:var(--ui-color-amber-200)}.ui\:border-amber-400{border-color:var(--ui-color-amber-400)}.ui\:border-black{border-color:var(--ui-color-black)}.ui\:border-border,.ui\:border-border\/50{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.ui\:border-border\/50{border-color:color-mix(in oklab, var(--border) 50%, transparent)}}.ui\:border-emerald-300{border-color:var(--ui-color-emerald-300)}.ui\:border-emerald-400{border-color:var(--ui-color-emerald-400)}.ui\:border-emerald-500{border-color:var(--ui-color-emerald-500)}.ui\:border-input{border-color:var(--input)}.ui\:border-muted{border-color:var(--muted)}.ui\:border-muted-foreground,.ui\:border-muted-foreground\/40{border-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:border-muted-foreground\/40{border-color:color-mix(in oklab, var(--muted-foreground) 40%, transparent)}}.ui\:border-neutral-400{border-color:var(--ui-color-neutral-400)}.ui\:border-neutral-800{border-color:var(--ui-color-neutral-800)}.ui\:border-primary,.ui\:border-primary\/30{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:border-primary\/30{border-color:color-mix(in oklab, var(--primary) 30%, transparent)}}.ui\:border-primary\/40{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:border-primary\/40{border-color:color-mix(in oklab, var(--primary) 40%, transparent)}}.ui\:border-primary\/50{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:border-primary\/50{border-color:color-mix(in oklab, var(--primary) 50%, transparent)}}.ui\:border-red-500{border-color:var(--ui-color-red-500)}.ui\:border-sidebar-border{border-color:var(--sidebar-border)}.ui\:border-sky-200{border-color:var(--ui-color-sky-200)}.ui\:border-transparent{border-color:#0000}.ui\:border-white,.ui\:border-white\/10{border-color:var(--ui-color-white)}@supports (color:color-mix(in lab, red, red)){.ui\:border-white\/10{border-color:color-mix(in oklab, var(--ui-color-white) 10%, transparent)}}.ui\:border-zinc-300{border-color:var(--ui-color-zinc-300)}.ui\:border-zinc-400{border-color:var(--ui-color-zinc-400)}.ui\:border-y-transparent{border-block-color:#0000}.ui\:border-l-current{border-left-color:currentColor}.ui\:border-l-foreground{border-left-color:var(--foreground)}.ui\:border-l-transparent{border-left-color:#0000}.ui\:bg-\(--color-bg\){background-color:var(--color-bg)}.ui\:bg-\[\#0f1218\]{background-color:#0f1218}.ui\:bg-\[\#1a1a1a\]{background-color:#1a1a1a}.ui\:bg-\[\#06070a\]{background-color:#06070a}.ui\:bg-\[\#e2e1d9\]{background-color:#e2e1d9}.ui\:bg-\[\#ebeae3\]{background-color:#ebeae3}.ui\:bg-\[\#ecebe5\]{background-color:#ecebe5}.ui\:bg-\[\#f4f3ed\]{background-color:#f4f3ed}.ui\:bg-\[\#f4f5f7\]{background-color:#f4f5f7}.ui\:bg-\[\#fafaf5\]{background-color:#fafaf5}.ui\:bg-\[var\(--landing-accent\)\],.ui\:bg-\[var\(--landing-accent\)\]\/5{background-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent\)\]\/5{background-color:color-mix(in oklab, var(--landing-accent) 5%, transparent)}}.ui\:bg-\[var\(--landing-accent\)\]\/10{background-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent\)\]\/10{background-color:color-mix(in oklab, var(--landing-accent) 10%, transparent)}}.ui\:bg-\[var\(--landing-accent\)\]\/60{background-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent\)\]\/60{background-color:color-mix(in oklab, var(--landing-accent) 60%, transparent)}}.ui\:bg-\[var\(--landing-accent\)\]\/70{background-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent\)\]\/70{background-color:color-mix(in oklab, var(--landing-accent) 70%, transparent)}}.ui\:bg-\[var\(--landing-accent-fg\)\],.ui\:bg-\[var\(--landing-accent-fg\)\]\/10{background-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent-fg\)\]\/10{background-color:color-mix(in oklab, var(--landing-accent-fg) 10%, transparent)}}.ui\:bg-\[var\(--landing-accent-fg\)\]\/15{background-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent-fg\)\]\/15{background-color:color-mix(in oklab, var(--landing-accent-fg) 15%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\],.ui\:bg-\[var\(--landing-bg\)\]\/5{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/5{background-color:color-mix(in oklab, var(--landing-bg) 5%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\]\/30{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/30{background-color:color-mix(in oklab, var(--landing-bg) 30%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\]\/75{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/75{background-color:color-mix(in oklab, var(--landing-bg) 75%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\]\/85{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/85{background-color:color-mix(in oklab, var(--landing-bg) 85%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\]\/90{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/90{background-color:color-mix(in oklab, var(--landing-bg) 90%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\]\/95{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/95{background-color:color-mix(in oklab, var(--landing-bg) 95%, transparent)}}.ui\:bg-\[var\(--landing-bg-section\)\]{background-color:var(--landing-bg-section)}.ui\:bg-\[var\(--landing-border\)\]{background-color:var(--landing-border)}.ui\:bg-\[var\(--landing-button-primary-bg\)\]{background-color:var(--landing-button-primary-bg)}.ui\:bg-\[var\(--landing-button-secondary-bg\)\]{background-color:var(--landing-button-secondary-bg)}.ui\:bg-\[var\(--landing-card\)\],.ui\:bg-\[var\(--landing-card\)\]\/70{background-color:var(--landing-card)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-card\)\]\/70{background-color:color-mix(in oklab, var(--landing-card) 70%, transparent)}}.ui\:bg-\[var\(--landing-card-soft\)\],.ui\:bg-\[var\(--landing-card-soft\)\]\/30{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-card-soft\)\]\/30{background-color:color-mix(in oklab, var(--landing-card-soft) 30%, transparent)}}.ui\:bg-\[var\(--landing-card-soft\)\]\/40{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-card-soft\)\]\/40{background-color:color-mix(in oklab, var(--landing-card-soft) 40%, transparent)}}.ui\:bg-\[var\(--landing-card-soft\)\]\/50{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-card-soft\)\]\/50{background-color:color-mix(in oklab, var(--landing-card-soft) 50%, transparent)}}.ui\:bg-\[var\(--landing-card-soft\)\]\/60{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-card-soft\)\]\/60{background-color:color-mix(in oklab, var(--landing-card-soft) 60%, transparent)}}.ui\:bg-\[var\(--landing-fg\)\]{background-color:var(--landing-fg)}.ui\:bg-accent{background-color:var(--accent)}.ui\:bg-amber-50,.ui\:bg-amber-50\/30{background-color:var(--ui-color-amber-50)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-amber-50\/30{background-color:color-mix(in oklab, var(--ui-color-amber-50) 30%, transparent)}}.ui\:bg-amber-500{background-color:var(--ui-color-amber-500)}.ui\:bg-amber-500\!{background-color:var(--ui-color-amber-500)!important}.ui\:bg-amber-600{background-color:var(--ui-color-amber-600)}.ui\:bg-background,.ui\:bg-background\/50{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-background\/50{background-color:color-mix(in oklab, var(--background) 50%, transparent)}}.ui\:bg-background\/90{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-background\/90{background-color:color-mix(in oklab, var(--background) 90%, transparent)}}.ui\:bg-background\/95{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-background\/95{background-color:color-mix(in oklab, var(--background) 95%, transparent)}}.ui\:bg-black,.ui\:bg-black\/10{background-color:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-black\/10{background-color:color-mix(in oklab, var(--ui-color-black) 10%, transparent)}}.ui\:bg-black\/40{background-color:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-black\/40{background-color:color-mix(in oklab, var(--ui-color-black) 40%, transparent)}}.ui\:bg-black\/50{background-color:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-black\/50{background-color:color-mix(in oklab, var(--ui-color-black) 50%, transparent)}}.ui\:bg-blue-600{background-color:var(--ui-color-blue-600)}.ui\:bg-blue-600\!{background-color:var(--ui-color-blue-600)!important}.ui\:bg-border{background-color:var(--border)}.ui\:bg-card,.ui\:bg-card\/95{background-color:var(--card)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-card\/95{background-color:color-mix(in oklab, var(--card) 95%, transparent)}}.ui\:bg-current{background-color:currentColor}.ui\:bg-destructive{background-color:var(--destructive)}.ui\:bg-emerald-50\/20{background-color:var(--ui-color-emerald-50)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-emerald-50\/20{background-color:color-mix(in oklab, var(--ui-color-emerald-50) 20%, transparent)}}.ui\:bg-emerald-50\/30{background-color:var(--ui-color-emerald-50)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-emerald-50\/30{background-color:color-mix(in oklab, var(--ui-color-emerald-50) 30%, transparent)}}.ui\:bg-emerald-50\/40{background-color:var(--ui-color-emerald-50)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-emerald-50\/40{background-color:color-mix(in oklab, var(--ui-color-emerald-50) 40%, transparent)}}.ui\:bg-emerald-500{background-color:var(--ui-color-emerald-500)}.ui\:bg-emerald-500\!{background-color:var(--ui-color-emerald-500)!important}.ui\:bg-emerald-600{background-color:var(--ui-color-emerald-600)}.ui\:bg-gray-200{background-color:var(--ui-color-gray-200)}.ui\:bg-green-500{background-color:var(--ui-color-green-500)}.ui\:bg-inherit{background-color:inherit}.ui\:bg-input{background-color:var(--input)}.ui\:bg-muted{background-color:var(--muted)}.ui\:bg-muted-foreground\/30{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-muted-foreground\/30{background-color:color-mix(in oklab, var(--muted-foreground) 30%, transparent)}}.ui\:bg-muted\/30{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-muted\/30{background-color:color-mix(in oklab, var(--muted) 30%, transparent)}}.ui\:bg-muted\/50{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-muted\/50{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}.ui\:bg-muted\/95{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-muted\/95{background-color:color-mix(in oklab, var(--muted) 95%, transparent)}}.ui\:bg-neutral-100{background-color:var(--ui-color-neutral-100)}.ui\:bg-neutral-900\/50{background-color:var(--ui-color-neutral-900)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-neutral-900\/50{background-color:color-mix(in oklab, var(--ui-color-neutral-900) 50%, transparent)}}.ui\:bg-popover{background-color:var(--popover)}.ui\:bg-primary{background-color:var(--primary)}.ui\:bg-primary-foreground{background-color:var(--primary-foreground)}.ui\:bg-primary\/10{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-primary\/10{background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.ui\:bg-primary\/20{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-primary\/20{background-color:color-mix(in oklab, var(--primary) 20%, transparent)}}.ui\:bg-red-50\/40{background-color:var(--ui-color-red-50)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-red-50\/40{background-color:color-mix(in oklab, var(--ui-color-red-50) 40%, transparent)}}.ui\:bg-red-500{background-color:var(--ui-color-red-500)}.ui\:bg-rose-500{background-color:var(--ui-color-rose-500)}.ui\:bg-rose-500\!{background-color:var(--ui-color-rose-500)!important}.ui\:bg-secondary,.ui\:bg-secondary\/50{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-secondary\/50{background-color:color-mix(in oklab, var(--secondary) 50%, transparent)}}.ui\:bg-sidebar{background-color:var(--sidebar)}.ui\:bg-sidebar-border{background-color:var(--sidebar-border)}.ui\:bg-sky-50{background-color:var(--ui-color-sky-50)}.ui\:bg-slate-500{background-color:var(--ui-color-slate-500)}.ui\:bg-slate-500\!{background-color:var(--ui-color-slate-500)!important}.ui\:bg-transparent{background-color:#0000}.ui\:bg-violet-500{background-color:var(--ui-color-violet-500)}.ui\:bg-violet-500\!{background-color:var(--ui-color-violet-500)!important}.ui\:bg-white,.ui\:bg-white\/5{background-color:var(--ui-color-white)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-white\/5{background-color:color-mix(in oklab, var(--ui-color-white) 5%, transparent)}}.ui\:bg-yellow-500{background-color:var(--ui-color-yellow-500)}.ui\:bg-zinc-100{background-color:var(--ui-color-zinc-100)}.ui\:bg-zinc-400{background-color:var(--ui-color-zinc-400)}.ui\:bg-linear-to-r{--tw-gradient-position:to right}@supports (background-image:linear-gradient(in lab, red, red)){.ui\:bg-linear-to-r{--tw-gradient-position:to right in oklab}}.ui\:bg-linear-to-r{background-image:linear-gradient(var(--tw-gradient-stops))}.ui\:bg-linear-to-t{--tw-gradient-position:to top}@supports (background-image:linear-gradient(in lab, red, red)){.ui\:bg-linear-to-t{--tw-gradient-position:to top in oklab}}.ui\:bg-linear-to-t{background-image:linear-gradient(var(--tw-gradient-stops))}.ui\:bg-\[linear-gradient\(110deg\,\#000103\,45\%\,\#1e2631\,55\%\,\#000103\)\]{background-image:linear-gradient(110deg,#000103,45%,#1e2631,55%,#000103)}.ui\:from-background{--tw-gradient-from:var(--background);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:from-pink-500{--tw-gradient-from:var(--ui-color-pink-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:from-slate-500{--tw-gradient-from:var(--ui-color-slate-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:from-transparent{--tw-gradient-from:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:via-black\/80{--tw-gradient-via:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:via-black\/80{--tw-gradient-via:color-mix(in oklab, var(--ui-color-black) 80%, transparent)}}.ui\:via-black\/80{--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.ui\:via-blue-600\/30{--tw-gradient-via:var(--ui-color-blue-600)}@supports (color:color-mix(in lab, red, red)){.ui\:via-blue-600\/30{--tw-gradient-via:color-mix(in oklab, var(--ui-color-blue-600) 30%, transparent)}}.ui\:via-blue-600\/30{--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.ui\:via-50\%{--tw-gradient-via-position:50%}.ui\:to-orange-500{--tw-gradient-to:var(--ui-color-orange-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:to-transparent{--tw-gradient-to:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:bg-\[length\:200\%_100\%\]{background-size:200% 100%}.ui\:bg-cover{background-size:cover}.ui\:bg-size-\[var\(--shimmer-width\)_100\%\]{background-size:var(--shimmer-width) 100%}.ui\:bg-clip-padding{background-clip:padding-box}.ui\:bg-clip-text{-webkit-background-clip:text;background-clip:text}.ui\:bg-center{background-position:50%}.ui\:bg-position-\[0_0\]{background-position:0 0}.ui\:bg-no-repeat{background-repeat:no-repeat}.ui\:fill-amber-400{fill:var(--ui-color-amber-400)}.ui\:fill-current{fill:currentColor}.ui\:fill-none{fill:none}.ui\:fill-primary{fill:var(--primary)}.ui\:object-contain{object-fit:contain}.ui\:object-cover{object-fit:cover}.ui\:p-0{padding:calc(var(--ui-spacing) * 0)}.ui\:p-0\!{padding:calc(var(--ui-spacing) * 0)!important}.ui\:p-0\.5{padding:calc(var(--ui-spacing) * .5)}.ui\:p-1{padding:calc(var(--ui-spacing) * 1)}.ui\:p-1\!{padding:calc(var(--ui-spacing) * 1)!important}.ui\:p-1\.5{padding:calc(var(--ui-spacing) * 1.5)}.ui\:p-2{padding:calc(var(--ui-spacing) * 2)}.ui\:p-3{padding:calc(var(--ui-spacing) * 3)}.ui\:p-3\!{padding:calc(var(--ui-spacing) * 3)!important}.ui\:p-4{padding:calc(var(--ui-spacing) * 4)}.ui\:p-5{padding:calc(var(--ui-spacing) * 5)}.ui\:p-6{padding:calc(var(--ui-spacing) * 6)}.ui\:p-7{padding:calc(var(--ui-spacing) * 7)}.ui\:p-8{padding:calc(var(--ui-spacing) * 8)}.ui\:p-10{padding:calc(var(--ui-spacing) * 10)}.ui\:p-\[3px\]{padding:3px}.ui\:px-1{padding-inline:calc(var(--ui-spacing) * 1)}.ui\:px-1\.5{padding-inline:calc(var(--ui-spacing) * 1.5)}.ui\:px-2{padding-inline:calc(var(--ui-spacing) * 2)}.ui\:px-2\.5{padding-inline:calc(var(--ui-spacing) * 2.5)}.ui\:px-3{padding-inline:calc(var(--ui-spacing) * 3)}.ui\:px-3\.5{padding-inline:calc(var(--ui-spacing) * 3.5)}.ui\:px-4{padding-inline:calc(var(--ui-spacing) * 4)}.ui\:px-5{padding-inline:calc(var(--ui-spacing) * 5)}.ui\:px-6{padding-inline:calc(var(--ui-spacing) * 6)}.ui\:px-7{padding-inline:calc(var(--ui-spacing) * 7)}.ui\:px-8{padding-inline:calc(var(--ui-spacing) * 8)}.ui\:py-0{padding-block:calc(var(--ui-spacing) * 0)}.ui\:py-0\.5{padding-block:calc(var(--ui-spacing) * .5)}.ui\:py-1{padding-block:calc(var(--ui-spacing) * 1)}.ui\:py-1\.5{padding-block:calc(var(--ui-spacing) * 1.5)}.ui\:py-2{padding-block:calc(var(--ui-spacing) * 2)}.ui\:py-2\.5{padding-block:calc(var(--ui-spacing) * 2.5)}.ui\:py-3{padding-block:calc(var(--ui-spacing) * 3)}.ui\:py-3\.5{padding-block:calc(var(--ui-spacing) * 3.5)}.ui\:py-4{padding-block:calc(var(--ui-spacing) * 4)}.ui\:py-5{padding-block:calc(var(--ui-spacing) * 5)}.ui\:py-6{padding-block:calc(var(--ui-spacing) * 6)}.ui\:py-8{padding-block:calc(var(--ui-spacing) * 8)}.ui\:py-10{padding-block:calc(var(--ui-spacing) * 10)}.ui\:py-12{padding-block:calc(var(--ui-spacing) * 12)}.ui\:py-14{padding-block:calc(var(--ui-spacing) * 14)}.ui\:py-16{padding-block:calc(var(--ui-spacing) * 16)}.ui\:py-20{padding-block:calc(var(--ui-spacing) * 20)}.ui\:py-24{padding-block:calc(var(--ui-spacing) * 24)}.ui\:py-32{padding-block:calc(var(--ui-spacing) * 32)}.ui\:ps-3{padding-inline-start:calc(var(--ui-spacing) * 3)}.ui\:pe-3{padding-inline-end:calc(var(--ui-spacing) * 3)}.ui\:pt-0{padding-top:calc(var(--ui-spacing) * 0)}.ui\:pt-1{padding-top:calc(var(--ui-spacing) * 1)}.ui\:pt-1\.5{padding-top:calc(var(--ui-spacing) * 1.5)}.ui\:pt-2{padding-top:calc(var(--ui-spacing) * 2)}.ui\:pt-3{padding-top:calc(var(--ui-spacing) * 3)}.ui\:pt-3\!{padding-top:calc(var(--ui-spacing) * 3)!important}.ui\:pt-3\.5{padding-top:calc(var(--ui-spacing) * 3.5)}.ui\:pt-4{padding-top:calc(var(--ui-spacing) * 4)}.ui\:pt-5{padding-top:calc(var(--ui-spacing) * 5)}.ui\:pt-6{padding-top:calc(var(--ui-spacing) * 6)}.ui\:pt-8{padding-top:calc(var(--ui-spacing) * 8)}.ui\:pt-10{padding-top:calc(var(--ui-spacing) * 10)}.ui\:pt-12{padding-top:calc(var(--ui-spacing) * 12)}.ui\:pt-16{padding-top:calc(var(--ui-spacing) * 16)}.ui\:pt-20{padding-top:calc(var(--ui-spacing) * 20)}.ui\:pr-1{padding-right:calc(var(--ui-spacing) * 1)}.ui\:pr-2{padding-right:calc(var(--ui-spacing) * 2)}.ui\:pr-4{padding-right:calc(var(--ui-spacing) * 4)}.ui\:pr-8{padding-right:calc(var(--ui-spacing) * 8)}.ui\:pr-9{padding-right:calc(var(--ui-spacing) * 9)}.ui\:pr-18{padding-right:calc(var(--ui-spacing) * 18)}.ui\:pb-0{padding-bottom:calc(var(--ui-spacing) * 0)}.ui\:pb-2{padding-bottom:calc(var(--ui-spacing) * 2)}.ui\:pb-3{padding-bottom:calc(var(--ui-spacing) * 3)}.ui\:pb-4{padding-bottom:calc(var(--ui-spacing) * 4)}.ui\:pb-5{padding-bottom:calc(var(--ui-spacing) * 5)}.ui\:pb-6{padding-bottom:calc(var(--ui-spacing) * 6)}.ui\:pb-10{padding-bottom:calc(var(--ui-spacing) * 10)}.ui\:pb-12{padding-bottom:calc(var(--ui-spacing) * 12)}.ui\:pb-16{padding-bottom:calc(var(--ui-spacing) * 16)}.ui\:pb-20{padding-bottom:calc(var(--ui-spacing) * 20)}.ui\:pb-24{padding-bottom:calc(var(--ui-spacing) * 24)}.ui\:pb-\[max\(env\(safe-area-inset-bottom\)\,1rem\)\]{padding-bottom:max(env(safe-area-inset-bottom), 1rem)}.ui\:pl-2{padding-left:calc(var(--ui-spacing) * 2)}.ui\:pl-3{padding-left:calc(var(--ui-spacing) * 3)}.ui\:pl-4{padding-left:calc(var(--ui-spacing) * 4)}.ui\:pl-5{padding-left:calc(var(--ui-spacing) * 5)}.ui\:pl-8{padding-left:calc(var(--ui-spacing) * 8)}.ui\:text-center{text-align:center}.ui\:text-left{text-align:left}.ui\:text-right{text-align:right}.ui\:align-middle{vertical-align:middle}.ui\:font-mono{font-family:var(--ui-font-mono)}.ui\:font-sans{font-family:var(--ui-font-sans)}.ui\:font-serif{font-family:var(--ui-font-serif)}.ui\:text-2xl{font-size:var(--ui-text-2xl);line-height:var(--tw-leading,var(--ui-text-2xl--line-height))}.ui\:text-3xl{font-size:var(--ui-text-3xl);line-height:var(--tw-leading,var(--ui-text-3xl--line-height))}.ui\:text-4xl{font-size:var(--ui-text-4xl);line-height:var(--tw-leading,var(--ui-text-4xl--line-height))}.ui\:text-5xl{font-size:var(--ui-text-5xl);line-height:var(--tw-leading,var(--ui-text-5xl--line-height))}.ui\:text-6xl{font-size:var(--ui-text-6xl);line-height:var(--tw-leading,var(--ui-text-6xl--line-height))}.ui\:text-base{font-size:var(--ui-text-base);line-height:var(--tw-leading,var(--ui-text-base--line-height))}.ui\:text-base\!{font-size:var(--ui-text-base)!important;line-height:var(--tw-leading,var(--ui-text-base--line-height))!important}.ui\:text-lg{font-size:var(--ui-text-lg);line-height:var(--tw-leading,var(--ui-text-lg--line-height))}.ui\:text-sm{font-size:var(--ui-text-sm);line-height:var(--tw-leading,var(--ui-text-sm--line-height))}.ui\:text-sm\/relaxed{font-size:var(--ui-text-sm);line-height:var(--ui-leading-relaxed)}.ui\:text-xl{font-size:var(--ui-text-xl);line-height:var(--tw-leading,var(--ui-text-xl--line-height))}.ui\:text-xs{font-size:var(--ui-text-xs);line-height:var(--tw-leading,var(--ui-text-xs--line-height))}.ui\:text-\[0\.7rem\]{font-size:.7rem}.ui\:text-\[10px\]{font-size:10px}.ui\:text-\[11\.5px\]{font-size:11.5px}.ui\:text-\[11px\]{font-size:11px}.ui\:text-\[12\.5px\]{font-size:12.5px}.ui\:text-\[12px\]{font-size:12px}.ui\:text-\[13\.5px\]{font-size:13.5px}.ui\:text-\[13px\]{font-size:13px}.ui\:text-\[14\.5px\]{font-size:14.5px}.ui\:text-\[14px\]{font-size:14px}.ui\:text-\[15px\]{font-size:15px}.ui\:text-\[16px\]{font-size:16px}.ui\:text-\[17px\]{font-size:17px}.ui\:text-\[19px\]{font-size:19px}.ui\:text-\[22px\]{font-size:22px}.ui\:text-\[36px\]{font-size:36px}.ui\:text-\[40px\]{font-size:40px}.ui\:text-\[44px\]{font-size:44px}.ui\:text-\[64px\]{font-size:64px}.ui\:leading-7{--tw-leading:calc(var(--ui-spacing) * 7);line-height:calc(var(--ui-spacing) * 7)}.ui\:leading-8{--tw-leading:calc(var(--ui-spacing) * 8);line-height:calc(var(--ui-spacing) * 8)}.ui\:leading-\[0\.95\]{--tw-leading:.95;line-height:.95}.ui\:leading-\[1\.1\]{--tw-leading:1.1;line-height:1.1}.ui\:leading-\[1\.02\]{--tw-leading:1.02;line-height:1.02}.ui\:leading-\[1\.05\]{--tw-leading:1.05;line-height:1.05}.ui\:leading-\[1\.5\]{--tw-leading:1.5;line-height:1.5}.ui\:leading-\[1\.08\]{--tw-leading:1.08;line-height:1.08}.ui\:leading-\[1\.25\]{--tw-leading:1.25;line-height:1.25}.ui\:leading-\[1\.35\]{--tw-leading:1.35;line-height:1.35}.ui\:leading-none{--tw-leading:1;line-height:1}.ui\:leading-normal{--tw-leading:var(--ui-leading-normal);line-height:var(--ui-leading-normal)}.ui\:leading-relaxed{--tw-leading:var(--ui-leading-relaxed);line-height:var(--ui-leading-relaxed)}.ui\:leading-snug{--tw-leading:var(--ui-leading-snug);line-height:var(--ui-leading-snug)}.ui\:leading-tight{--tw-leading:var(--ui-leading-tight);line-height:var(--ui-leading-tight)}.ui\:font-black{--tw-font-weight:var(--ui-font-weight-black);font-weight:var(--ui-font-weight-black)}.ui\:font-bold{--tw-font-weight:var(--ui-font-weight-bold);font-weight:var(--ui-font-weight-bold)}.ui\:font-extrabold{--tw-font-weight:var(--ui-font-weight-extrabold);font-weight:var(--ui-font-weight-extrabold)}.ui\:font-light{--tw-font-weight:var(--ui-font-weight-light);font-weight:var(--ui-font-weight-light)}.ui\:font-medium{--tw-font-weight:var(--ui-font-weight-medium);font-weight:var(--ui-font-weight-medium)}.ui\:font-normal{--tw-font-weight:var(--ui-font-weight-normal);font-weight:var(--ui-font-weight-normal)}.ui\:font-semibold{--tw-font-weight:var(--ui-font-weight-semibold);font-weight:var(--ui-font-weight-semibold)}.ui\:\[font-weight\:var\(--landing-heading-weight\)\]{font-weight:var(--landing-heading-weight)}.ui\:tracking-\[-0\.02em\]{--tw-tracking:-.02em;letter-spacing:-.02em}.ui\:tracking-\[0\.2em\]{--tw-tracking:.2em;letter-spacing:.2em}.ui\:tracking-\[0\.04em\]{--tw-tracking:.04em;letter-spacing:.04em}.ui\:tracking-\[0\.08em\]{--tw-tracking:.08em;letter-spacing:.08em}.ui\:tracking-\[0\.12em\]{--tw-tracking:.12em;letter-spacing:.12em}.ui\:tracking-\[0\.18em\]{--tw-tracking:.18em;letter-spacing:.18em}.ui\:tracking-tight{--tw-tracking:var(--ui-tracking-tight);letter-spacing:var(--ui-tracking-tight)}.ui\:tracking-tighter{--tw-tracking:var(--ui-tracking-tighter);letter-spacing:var(--ui-tracking-tighter)}.ui\:tracking-wide{--tw-tracking:var(--ui-tracking-wide);letter-spacing:var(--ui-tracking-wide)}.ui\:tracking-wider{--tw-tracking:var(--ui-tracking-wider);letter-spacing:var(--ui-tracking-wider)}.ui\:tracking-widest{--tw-tracking:var(--ui-tracking-widest);letter-spacing:var(--ui-tracking-widest)}.ui\:\[letter-spacing\:var\(--landing-eyebrow-tracking\)\]{letter-spacing:var(--landing-eyebrow-tracking)}.ui\:\[letter-spacing\:var\(--landing-heading-tracking\)\]{letter-spacing:var(--landing-heading-tracking)}.ui\:text-balance{text-wrap:balance}.ui\:text-wrap{text-wrap:wrap}.ui\:break-words{overflow-wrap:break-word}.ui\:break-all{word-break:break-all}.ui\:text-ellipsis{text-overflow:ellipsis}.ui\:whitespace-nowrap{white-space:nowrap}.ui\:text-\[\#0a0b0e\]{color:#0a0b0e}.ui\:text-\[\#1a1a1a\]{color:#1a1a1a}.ui\:text-\[\#2c2b29\]{color:#2c2b29}.ui\:text-\[\#9da1ab\]{color:#9da1ab}.ui\:text-\[\#61656f\]{color:#61656f}.ui\:text-\[\#76746c\]{color:#76746c}.ui\:text-\[\#c25237\]{color:#c25237}.ui\:text-\[\#e9eaed\]{color:#e9eaed}.ui\:text-\[\#fafaf5\]{color:#fafaf5}.ui\:text-\[var\(--landing-accent\)\]{color:var(--landing-accent)}.ui\:text-\[var\(--landing-accent-fg\)\],.ui\:text-\[var\(--landing-accent-fg\)\]\/70{color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-accent-fg\)\]\/70{color:color-mix(in oklab, var(--landing-accent-fg) 70%, transparent)}}.ui\:text-\[var\(--landing-accent-fg\)\]\/80{color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-accent-fg\)\]\/80{color:color-mix(in oklab, var(--landing-accent-fg) 80%, transparent)}}.ui\:text-\[var\(--landing-accent-fg\)\]\/85{color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-accent-fg\)\]\/85{color:color-mix(in oklab, var(--landing-accent-fg) 85%, transparent)}}.ui\:text-\[var\(--landing-bg\)\],.ui\:text-\[var\(--landing-bg\)\]\/50{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/50{color:color-mix(in oklab, var(--landing-bg) 50%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/55{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/55{color:color-mix(in oklab, var(--landing-bg) 55%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/60{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/60{color:color-mix(in oklab, var(--landing-bg) 60%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/65{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/65{color:color-mix(in oklab, var(--landing-bg) 65%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/70{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/70{color:color-mix(in oklab, var(--landing-bg) 70%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/75{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/75{color:color-mix(in oklab, var(--landing-bg) 75%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/80{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/80{color:color-mix(in oklab, var(--landing-bg) 80%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/90{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/90{color:color-mix(in oklab, var(--landing-bg) 90%, transparent)}}.ui\:text-\[var\(--landing-button-primary-fg\)\]{color:var(--landing-button-primary-fg)}.ui\:text-\[var\(--landing-button-secondary-fg\)\]{color:var(--landing-button-secondary-fg)}.ui\:text-\[var\(--landing-button-tertiary-fg\)\]{color:var(--landing-button-tertiary-fg)}.ui\:text-\[var\(--landing-fg\)\],.ui\:text-\[var\(--landing-fg\)\]\/70{color:var(--landing-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-fg\)\]\/70{color:color-mix(in oklab, var(--landing-fg) 70%, transparent)}}.ui\:text-\[var\(--landing-fg\)\]\/72{color:var(--landing-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-fg\)\]\/72{color:color-mix(in oklab, var(--landing-fg) 72%, transparent)}}.ui\:text-\[var\(--landing-fg\)\]\/80{color:var(--landing-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-fg\)\]\/80{color:color-mix(in oklab, var(--landing-fg) 80%, transparent)}}.ui\:text-\[var\(--landing-fg-faint\)\]{color:var(--landing-fg-faint)}.ui\:text-\[var\(--landing-fg-muted\)\]{color:var(--landing-fg-muted)}.ui\:text-accent-foreground{color:var(--accent-foreground)}.ui\:text-amber-200{color:var(--ui-color-amber-200)}.ui\:text-amber-500{color:var(--ui-color-amber-500)}.ui\:text-amber-600{color:var(--ui-color-amber-600)}.ui\:text-amber-900{color:var(--ui-color-amber-900)}.ui\:text-black{color:var(--ui-color-black)}.ui\:text-card-foreground{color:var(--card-foreground)}.ui\:text-current{color:currentColor}.ui\:text-destructive{color:var(--destructive)}.ui\:text-emerald-600{color:var(--ui-color-emerald-600)}.ui\:text-emerald-700{color:var(--ui-color-emerald-700)}.ui\:text-foreground,.ui\:text-foreground\/70{color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-foreground\/70{color:color-mix(in oklab, var(--foreground) 70%, transparent)}}.ui\:text-gray-200{color:var(--ui-color-gray-200)}.ui\:text-green-500{color:var(--ui-color-green-500)}.ui\:text-green-600{color:var(--ui-color-green-600)}.ui\:text-muted-foreground,.ui\:text-muted-foreground\/60{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-muted-foreground\/60{color:color-mix(in oklab, var(--muted-foreground) 60%, transparent)}}.ui\:text-muted-foreground\/75{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-muted-foreground\/75{color:color-mix(in oklab, var(--muted-foreground) 75%, transparent)}}.ui\:text-neutral-600\/50{color:var(--ui-color-neutral-600)}@supports (color:color-mix(in lab, red, red)){.ui\:text-neutral-600\/50{color:color-mix(in oklab, var(--ui-color-neutral-600) 50%, transparent)}}.ui\:text-popover-foreground{color:var(--popover-foreground)}.ui\:text-primary{color:var(--primary)}.ui\:text-primary\!{color:var(--primary)!important}.ui\:text-primary-foreground{color:var(--primary-foreground)}.ui\:text-red-500{color:var(--ui-color-red-500)}.ui\:text-red-600{color:var(--ui-color-red-600)}.ui\:text-red-700{color:var(--ui-color-red-700)}.ui\:text-secondary-foreground{color:var(--secondary-foreground)}.ui\:text-sidebar-foreground,.ui\:text-sidebar-foreground\/70{color:var(--sidebar-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-sidebar-foreground\/70{color:color-mix(in oklab, var(--sidebar-foreground) 70%, transparent)}}.ui\:text-sidebar-foreground\/75{color:var(--sidebar-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-sidebar-foreground\/75{color:color-mix(in oklab, var(--sidebar-foreground) 75%, transparent)}}.ui\:text-sidebar-foreground\/80{color:var(--sidebar-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-sidebar-foreground\/80{color:color-mix(in oklab, var(--sidebar-foreground) 80%, transparent)}}.ui\:text-sky-900{color:var(--ui-color-sky-900)}.ui\:text-transparent{color:#0000}.ui\:text-white{color:var(--ui-color-white)}.ui\:text-white\!{color:var(--ui-color-white)!important}.ui\:\[text-transform\:var\(--landing-eyebrow-case\)\]{text-transform:var(--landing-eyebrow-case)}.ui\:\[text-transform\:var\(--landing-heading-case\)\]{text-transform:var(--landing-heading-case)}.ui\:capitalize{text-transform:capitalize}.ui\:uppercase{text-transform:uppercase}.ui\:italic{font-style:italic}.ui\:tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.ui\:line-through{text-decoration-line:line-through}.ui\:no-underline{text-decoration-line:none}.ui\:underline{text-decoration-line:underline}.ui\:underline-offset-2{text-underline-offset:2px}.ui\:underline-offset-4{text-underline-offset:4px}.ui\:opacity-0{opacity:0}.ui\:opacity-10{opacity:.1}.ui\:opacity-30{opacity:.3}.ui\:opacity-40{opacity:.4}.ui\:opacity-50{opacity:.5}.ui\:opacity-60{opacity:.6}.ui\:opacity-70{opacity:.7}.ui\:opacity-85{opacity:.85}.ui\:opacity-90{opacity:.9}.ui\:opacity-95{opacity:.95}.ui\:opacity-100{opacity:1}.ui\:opacity-\[0\.06\]{opacity:.06}.ui\:opacity-\[0\.08\]{opacity:.08}.ui\:opacity-\[0\.10\]{opacity:.1}.ui\:opacity-\[0\.15\]{opacity:.15}.ui\:shadow-\[var\(--landing-accent\)\]\/20{--tw-shadow-alpha:20%;--tw-shadow:var(--landing-accent);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[var\(--landing-accent\)\]\/25{--tw-shadow-alpha:25%;--tw-shadow:var(--landing-accent);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-2xs{--tw-shadow:0 1px var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_0_0_1px_\#ffffff10\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,#ffffff10);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_0_0_1px_var\(--sidebar-border\)\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,var(--sidebar-border));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_4px_16px_rgba\(0\,0\,0\,0\.10\)\]{--tw-shadow:0 4px 16px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_4px_24px_-8px_rgba\(14\,14\,16\,0\.08\)\]{--tw-shadow:0 4px 24px -8px var(--tw-shadow-color,#0e0e1014);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_18px_40px_rgba\(0\,0\,0\,0\.18\)\,0_6px_12px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 18px 40px var(--tw-shadow-color,#0000002e), 0 6px 12px var(--tw-shadow-color,#0000001f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_20px_60px_-30px_rgba\(14\,14\,16\,0\.25\)\]{--tw-shadow:0 20px 60px -30px var(--tw-shadow-color,#0e0e1040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_40px_90px_-30px_rgba\(0\,0\,0\,0\.35\)\]{--tw-shadow:0 40px 90px -30px var(--tw-shadow-color,#00000059);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[inset_0_-8px_10px_\#ffffff1f\]{--tw-shadow:inset 0 -8px 10px var(--tw-shadow-color,#ffffff1f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:ring-0{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + 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)}.ui\:ring-1{--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)}.ui\:ring-2{--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)}.ui\:ring-3{--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)}.ui\:ring-4{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(4px + 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)}.ui\:\[box-shadow\:var\(--landing-glow\)\]{box-shadow:var(--landing-glow)}.ui\:\[box-shadow\:var\(--landing-shadow-card\)\]{box-shadow:var(--landing-shadow-card)}.ui\:ring-\[var\(--landing-accent\)\]{--tw-ring-color:var(--landing-accent)}.ui\:ring-accent{--tw-ring-color:var(--accent)}.ui\:ring-background{--tw-ring-color:var(--background)}.ui\:ring-border,.ui\:ring-border\/50{--tw-ring-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.ui\:ring-border\/50{--tw-ring-color:color-mix(in oklab, var(--border) 50%, transparent)}}.ui\:ring-primary{--tw-ring-color:var(--primary)}.ui\:ring-sidebar-ring{--tw-ring-color:var(--sidebar-ring)}.ui\:ring-offset-2{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ui\:ring-offset-background{--tw-ring-offset-color:var(--background)}.ui\:outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.ui\:outline-hidden{outline-offset:2px;outline:2px solid #0000}}.ui\:blur-3xl{--tw-blur:blur(var(--ui-blur-3xl));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,)}.ui\:blur-\[2px\]{--tw-blur:blur(2px);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,)}.ui\:brightness-200{--tw-brightness:brightness(200%);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,)}.ui\:drop-shadow-sm{--tw-drop-shadow-size:drop-shadow(0 1px 2px var(--tw-drop-shadow-color,#00000026));--tw-drop-shadow:drop-shadow(var(--ui-drop-shadow-sm));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,)}.ui\:drop-shadow-none{--tw-drop-shadow: ;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,)}.ui\:grayscale{--tw-grayscale:grayscale(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.ui\:backdrop-blur{--tw-backdrop-blur:blur(8px);-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,)}.ui\:backdrop-blur-2xl{--tw-backdrop-blur:blur(var(--ui-blur-2xl));-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,)}.ui\:backdrop-blur-md{--tw-backdrop-blur:blur(var(--ui-blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.ui\:backdrop-blur-sm{--tw-backdrop-blur:blur(var(--ui-blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.ui\:backdrop-blur-xl{--tw-backdrop-blur:blur(var(--ui-blur-xl));-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,)}.ui\:transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[color\,box-shadow\]{transition-property:color,box-shadow;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[left\,right\,width\]{transition-property:left,right,width;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[margin\,opacity\]{transition-property:margin,opacity;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[stroke-dashoffset\]{transition-property:stroke-dashoffset;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[width\,height\,padding\]{transition-property:width,height,padding;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[width\]{transition-property:width;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-none{transition-property:none}.ui\:duration-100{--tw-duration:.1s;transition-duration:.1s}.ui\:duration-200{--tw-duration:.2s;transition-duration:.2s}.ui\:duration-300{--tw-duration:.3s;transition-duration:.3s}.ui\:duration-500{--tw-duration:.5s;transition-duration:.5s}.ui\:duration-700{--tw-duration:.7s;transition-duration:.7s}.ui\:ease-in-out{--tw-ease:var(--ui-ease-in-out);transition-timing-function:var(--ui-ease-in-out)}.ui\:ease-linear{--tw-ease:linear;transition-timing-function:linear}.ui\:ease-out{--tw-ease:var(--ui-ease-out);transition-timing-function:var(--ui-ease-out)}.ui\:fade-in-0{--tw-enter-opacity:0}.ui\:outline-none{--tw-outline-style:none;outline-style:none}.ui\:select-none{-webkit-user-select:none;user-select:none}.ui\:zoom-in-95{--tw-enter-scale:.95}.ui\:\[--dot-field-glow\:\#fff\]{--dot-field-glow:#fff}.ui\:\[background\:conic-gradient\(from_calc\(270deg-\(var\(--spread\)\*0\.5\)\)\,transparent_0\,var\(--shimmer-color\)_var\(--spread\)\,transparent_var\(--spread\)\)\]{background:conic-gradient(from calc(270deg - (var(--spread) * .5)),transparent 0,var(--shimmer-color) var(--spread),transparent var(--spread))}.ui\:\[background\:linear-gradient\(180deg\,var\(--landing-card\)_0\%\,var\(--landing-bg-section\)_100\%\)\]{background:linear-gradient(180deg,var(--landing-card) 0%,var(--landing-bg-section) 100%)}.ui\:\[background\:var\(--bg\)\]{background:var(--bg)}.ui\:\[border-top\:1px_dashed_var\(--landing-border-soft\)\]{border-top:1px dashed var(--landing-border-soft)}.ui\:\[mask\:none\]{-webkit-mask:none;mask:none}.ui\:ring-inset{--tw-ring-inset:inset}:is(.ui\:\*\:w-full>*){width:100%}.ui\:group-focus-within\/menu-item\:opacity-100:is(:where(.ui\:group\/menu-item):focus-within *){opacity:1}@media (hover:hover){.ui\:group-hover\:translate-x-0\.5:is(:where(.ui\:group):hover *){--tw-translate-x:calc(var(--ui-spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:group-hover\:scale-\[1\.02\]:is(:where(.ui\:group):hover *){scale:1.02}.ui\:group-hover\:bg-\[var\(--landing-accent\)\]:is(:where(.ui\:group):hover *){background-color:var(--landing-accent)}.ui\:group-hover\:bg-muted-foreground\/15:is(:where(.ui\:group):hover *){background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:group-hover\:bg-muted-foreground\/15:is(:where(.ui\:group):hover *){background-color:color-mix(in oklab, var(--muted-foreground) 15%, transparent)}}.ui\:group-hover\:bg-secondary\/80:is(:where(.ui\:group):hover *){background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.ui\:group-hover\:bg-secondary\/80:is(:where(.ui\:group):hover *){background-color:color-mix(in oklab, var(--secondary) 80%, transparent)}}.ui\:group-hover\:text-\[var\(--landing-accent\)\]:is(:where(.ui\:group):hover *){color:var(--landing-accent)}.ui\:group-hover\:text-\[var\(--landing-accent-fg\)\]:is(:where(.ui\:group):hover *){color:var(--landing-accent-fg)}.ui\:group-hover\:text-foreground:is(:where(.ui\:group):hover *){color:var(--foreground)}.ui\:group-hover\:text-primary:is(:where(.ui\:group):hover *){color:var(--primary)}.ui\:group-hover\:opacity-100:is(:where(.ui\:group):hover *){opacity:1}.ui\:group-hover\:shadow-\[inset_0_-6px_10px_\#ffffff3f\]:is(:where(.ui\:group):hover *){--tw-shadow:inset 0 -6px 10px var(--tw-shadow-color,#ffffff3f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:group-hover\/menu-item\:opacity-100:is(:where(.ui\:group\/menu-item):hover *){opacity:1}}.ui\:group-focus-visible\:opacity-100:is(:where(.ui\:group):focus-visible *){opacity:1}.ui\:group-active\:shadow-\[inset_0_-10px_10px_\#ffffff3f\]:is(:where(.ui\:group):active *){--tw-shadow:inset 0 -10px 10px var(--tw-shadow-color,#ffffff3f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:group-has-data-\[orientation\=horizontal\]\/field\:text-balance:is(:where(.ui\:group\/field):has([data-orientation=horizontal]) *){text-wrap:balance}.ui\:group-has-data-\[sidebar\=menu-action\]\/menu-item\:pr-8:is(:where(.ui\:group\/menu-item):has([data-sidebar=menu-action]) *){padding-right:calc(var(--ui-spacing) * 8)}.ui\:group-has-\[\[data-slot\=item-description\]\]\/item\:translate-y-0\.5:is(:where(.ui\:group\/item):has([data-slot=item-description]) *){--tw-translate-y:calc(var(--ui-spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:group-has-\[\[data-slot\=item-description\]\]\/item\:self-start:is(:where(.ui\:group\/item):has([data-slot=item-description]) *){align-self:flex-start}.ui\:group-has-\[\>input\]\/input-group\:pt-2\.5:is(:where(.ui\:group\/input-group):has(>input) *){padding-top:calc(var(--ui-spacing) * 2.5)}.ui\:group-has-\[\>input\]\/input-group\:pb-2\.5:is(:where(.ui\:group\/input-group):has(>input) *){padding-bottom:calc(var(--ui-spacing) * 2.5)}.ui\:group-aria-disabled\/file-drop-zone-trigger\:opacity-50:is(:where(.ui\:group\/file-drop-zone-trigger)[aria-disabled=true] *){opacity:.5}.ui\:group-data-\[collapsible\=icon\]\:pointer-events-none:is(:where(.ui\:group)[data-collapsible=icon] *){pointer-events:none}.ui\:group-data-\[collapsible\=icon\]\:-mt-8:is(:where(.ui\:group)[data-collapsible=icon] *){margin-top:calc(var(--ui-spacing) * -8)}.ui\:group-data-\[collapsible\=icon\]\:hidden:is(:where(.ui\:group)[data-collapsible=icon] *){display:none}.ui\:group-data-\[collapsible\=icon\]\:size-8\!:is(:where(.ui\:group)[data-collapsible=icon] *){width:calc(var(--ui-spacing) * 8)!important;height:calc(var(--ui-spacing) * 8)!important}.ui\:group-data-\[collapsible\=icon\]\:w-\(--sidebar-width-icon\):is(:where(.ui\:group)[data-collapsible=icon] *){width:var(--sidebar-width-icon)}.ui\:group-data-\[collapsible\=icon\]\:w-\[calc\(var\(--sidebar-width-icon\)\+\(--spacing\(4\)\)\+2px\)\]:is(:where(.ui\:group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--ui-spacing) * 4)) + 2px)}.ui\:group-data-\[collapsible\=icon\]\:overflow-hidden:is(:where(.ui\:group)[data-collapsible=icon] *){overflow:hidden}.ui\:group-data-\[collapsible\=icon\]\:p-0\!:is(:where(.ui\:group)[data-collapsible=icon] *){padding:calc(var(--ui-spacing) * 0)!important}.ui\:group-data-\[collapsible\=icon\]\:p-2\!:is(:where(.ui\:group)[data-collapsible=icon] *){padding:calc(var(--ui-spacing) * 2)!important}.ui\:group-data-\[collapsible\=icon\]\:opacity-0:is(:where(.ui\:group)[data-collapsible=icon] *){opacity:0}.ui\:group-data-\[collapsible\=offcanvas\]\:right-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.ui\:group)[data-collapsible=offcanvas] *){right:calc(var(--sidebar-width) * -1)}.ui\:group-data-\[collapsible\=offcanvas\]\:left-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.ui\:group)[data-collapsible=offcanvas] *){left:calc(var(--sidebar-width) * -1)}.ui\:group-data-\[collapsible\=offcanvas\]\:w-0:is(:where(.ui\:group)[data-collapsible=offcanvas] *){width:calc(var(--ui-spacing) * 0)}.ui\:group-data-\[collapsible\=offcanvas\]\:translate-x-0:is(:where(.ui\:group)[data-collapsible=offcanvas] *){--tw-translate-x:calc(var(--ui-spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:group-data-\[disabled\=true\]\:pointer-events-none:is(:where(.ui\:group)[data-disabled=true] *){pointer-events:none}.ui\:group-data-\[disabled\=true\]\:opacity-50:is(:where(.ui\:group)[data-disabled=true] *),.ui\:group-data-\[disabled\=true\]\/field\:opacity-50:is(:where(.ui\:group\/field)[data-disabled=true] *),.ui\:group-data-\[disabled\=true\]\/input-group\:opacity-50:is(:where(.ui\:group\/input-group)[data-disabled=true] *){opacity:.5}.ui\:group-data-\[side\=left\]\:-right-4:is(:where(.ui\:group)[data-side=left] *){right:calc(var(--ui-spacing) * -4)}.ui\:group-data-\[side\=left\]\:border-r:is(:where(.ui\:group)[data-side=left] *){border-right-style:var(--tw-border-style);border-right-width:1px}.ui\:group-data-\[side\=right\]\:left-0:is(:where(.ui\:group)[data-side=right] *){left:calc(var(--ui-spacing) * 0)}.ui\:group-data-\[side\=right\]\:rotate-180:is(:where(.ui\:group)[data-side=right] *){rotate:180deg}.ui\:group-data-\[side\=right\]\:border-l:is(:where(.ui\:group)[data-side=right] *){border-left-style:var(--tw-border-style);border-left-width:1px}.ui\:group-data-\[state\=open\]\:rotate-180:is(:where(.ui\:group)[data-state=open] *){rotate:180deg}.ui\:group-data-\[variant\=floating\]\:rounded-lg:is(:where(.ui\:group)[data-variant=floating] *){border-radius:var(--radius)}.ui\:group-data-\[variant\=floating\]\:border:is(:where(.ui\:group)[data-variant=floating] *){border-style:var(--tw-border-style);border-width:1px}.ui\:group-data-\[variant\=floating\]\:border-sidebar-border:is(:where(.ui\:group)[data-variant=floating] *){border-color:var(--sidebar-border)}.ui\:group-data-\[variant\=floating\]\:shadow-sm:is(:where(.ui\:group)[data-variant=floating] *){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:group-data-\[variant\=outline\]\/field-group\:-mb-2:is(:where(.ui\:group\/field-group)[data-variant=outline] *){margin-bottom:calc(var(--ui-spacing) * -2)}.ui\:group-data-\[vaul-drawer-direction\=bottom\]\/drawer-content\:block:is(:where(.ui\:group\/drawer-content)[data-vaul-drawer-direction=bottom] *){display:block}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:top-full:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){top:100%}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:mt-1\.5:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){margin-top:calc(var(--ui-spacing) * 1.5)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:overflow-hidden:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){overflow:hidden}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:rounded-md:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){border-radius:calc(var(--radius) - 2px)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:border:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){border-style:var(--tw-border-style);border-width:1px}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:bg-popover:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){background-color:var(--popover)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:text-popover-foreground:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){color:var(--popover-foreground)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:shadow:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:duration-200:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){--tw-duration:.2s;transition-duration:.2s}@media (hover:hover){.ui\:peer-hover\/menu-button\:text-sidebar-accent-foreground:is(:where(.ui\:peer\/menu-button):hover~*){color:var(--sidebar-accent-foreground)}}.ui\:peer-focus-visible\:opacity-100:is(:where(.ui\:peer):focus-visible~*){opacity:1}.ui\:peer-disabled\:cursor-not-allowed:is(:where(.ui\:peer):disabled~*){cursor:not-allowed}.ui\:peer-disabled\:opacity-50:is(:where(.ui\:peer):disabled~*){opacity:.5}.ui\:peer-data-\[active\=true\]\/menu-button\:text-sidebar-accent-foreground:is(:where(.ui\:peer\/menu-button)[data-active=true]~*){color:var(--sidebar-accent-foreground)}.ui\:peer-data-\[size\=default\]\/menu-button\:top-1\.5:is(:where(.ui\:peer\/menu-button)[data-size=default]~*){top:calc(var(--ui-spacing) * 1.5)}.ui\:peer-data-\[size\=lg\]\/menu-button\:top-2\.5:is(:where(.ui\:peer\/menu-button)[data-size=lg]~*){top:calc(var(--ui-spacing) * 2.5)}.ui\:peer-data-\[size\=sm\]\/menu-button\:top-1:is(:where(.ui\:peer\/menu-button)[data-size=sm]~*){top:calc(var(--ui-spacing) * 1)}.ui\:first-letter\:float-left:first-letter{float:left}.ui\:first-letter\:mr-2:first-letter{margin-right:calc(var(--ui-spacing) * 2)}.ui\:first-letter\:text-5xl:first-letter{font-size:var(--ui-text-5xl);line-height:var(--tw-leading,var(--ui-text-5xl--line-height))}.ui\:first-letter\:leading-none:first-letter{--tw-leading:1;line-height:1}.ui\:first-letter\:\[font-weight\:var\(--landing-heading-weight\)\]:first-letter{font-weight:var(--landing-heading-weight)}.ui\:first-letter\:text-\[var\(--landing-accent\)\]:first-letter{color:var(--landing-accent)}.ui\:selection\:bg-primary ::selection{background-color:var(--primary)}.ui\:selection\:bg-primary::selection{background-color:var(--primary)}.ui\:selection\:text-primary-foreground ::selection{color:var(--primary-foreground)}.ui\:selection\:text-primary-foreground::selection{color:var(--primary-foreground)}.ui\:placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.ui\:before\:mr-1:before{content:var(--tw-content);margin-right:calc(var(--ui-spacing) * 1)}.ui\:before\:size-1\.5:before{content:var(--tw-content);width:calc(var(--ui-spacing) * 1.5);height:calc(var(--ui-spacing) * 1.5)}.ui\:before\:rounded-full:before{content:var(--tw-content);border-radius:3.40282e38px}.ui\:before\:bg-\[var\(--landing-accent\)\]:before{content:var(--tw-content);background-color:var(--landing-accent)}.ui\:before\:text-2xl:before{content:var(--tw-content);font-size:var(--ui-text-2xl);line-height:var(--tw-leading,var(--ui-text-2xl--line-height))}.ui\:before\:text-\[var\(--landing-accent\)\]:before{content:var(--tw-content);color:var(--landing-accent)}.ui\:before\:content-\[\"\"\]:before{--tw-content:"";content:var(--tw-content)}.ui\:before\:content-\[\"“\"\]:before{--tw-content:"“";content:var(--tw-content)}.ui\:after\:absolute:after{content:var(--tw-content);position:absolute}.ui\:after\:-inset-2:after{content:var(--tw-content);inset:calc(var(--ui-spacing) * -2)}.ui\:after\:inset-y-0:after{content:var(--tw-content);inset-block:calc(var(--ui-spacing) * 0)}.ui\:after\:left-\[calc\(1\/2\*100\%-1px\)\]:after{content:var(--tw-content);left:calc(50% - 1px)}.ui\:after\:w-\[2px\]:after{content:var(--tw-content);width:2px}.ui\:group-data-\[collapsible\=offcanvas\]\:after\:left-full:is(:where(.ui\:group)[data-collapsible=offcanvas] *):after{content:var(--tw-content);left:100%}.ui\:first\:border-t-0:first-child{border-top-style:var(--tw-border-style);border-top-width:0}.ui\:last\:mt-0:last-child{margin-top:calc(var(--ui-spacing) * 0)}.ui\:last\:border-b:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.ui\:last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.ui\:focus-within\:border-ring:focus-within{border-color:var(--ring)}.ui\:focus-within\:ring-\[3px\]:focus-within{--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)}.ui\:focus-within\:ring-ring\/50:focus-within{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.ui\:focus-within\:ring-ring\/50:focus-within{--tw-ring-color:color-mix(in oklab, var(--ring) 50%, transparent)}}@media (hover:hover){.ui\:hover\:-translate-y-0\.5:hover{--tw-translate-y:calc(var(--ui-spacing) * -.5);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:hover\:-translate-y-1:hover{--tw-translate-y:calc(var(--ui-spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:hover\:cursor-pointer:hover{cursor:pointer}.ui\:hover\:border:hover{border-style:var(--tw-border-style);border-width:1px}.ui\:hover\:border-\[var\(--landing-accent\)\]:hover{border-color:var(--landing-accent)}.ui\:hover\:border-\[var\(--landing-accent-fg\)\]\/30:hover{border-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:border-\[var\(--landing-accent-fg\)\]\/30:hover{border-color:color-mix(in oklab, var(--landing-accent-fg) 30%, transparent)}}.ui\:hover\:border-\[var\(--landing-bg\)\]\/60:hover{border-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:border-\[var\(--landing-bg\)\]\/60:hover{border-color:color-mix(in oklab, var(--landing-bg) 60%, transparent)}}.ui\:hover\:border-\[var\(--landing-border\)\]:hover{border-color:var(--landing-border)}.ui\:hover\:border-\[var\(--landing-fg\)\]\/30:hover{border-color:var(--landing-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:border-\[var\(--landing-fg\)\]\/30:hover{border-color:color-mix(in oklab, var(--landing-fg) 30%, transparent)}}.ui\:hover\:border-primary\/40:hover{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:border-primary\/40:hover{border-color:color-mix(in oklab, var(--primary) 40%, transparent)}}.ui\:hover\:bg-\[\#2c2b29\]:hover{background-color:#2c2b29}.ui\:hover\:bg-\[\#14171f\]:hover{background-color:#14171f}.ui\:hover\:bg-\[\#e2e1d9\]:hover{background-color:#e2e1d9}.ui\:hover\:bg-\[\#ebeae3\]:hover{background-color:#ebeae3}.ui\:hover\:bg-\[var\(--landing-accent\)\]:hover,.ui\:hover\:bg-\[var\(--landing-accent\)\]\/90:hover{background-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-accent\)\]\/90:hover{background-color:color-mix(in oklab, var(--landing-accent) 90%, transparent)}}.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/5:hover{background-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/5:hover{background-color:color-mix(in oklab, var(--landing-accent-fg) 5%, transparent)}}.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/10:hover{background-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/10:hover{background-color:color-mix(in oklab, var(--landing-accent-fg) 10%, transparent)}}.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/90:hover{background-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/90:hover{background-color:color-mix(in oklab, var(--landing-accent-fg) 90%, transparent)}}.ui\:hover\:bg-\[var\(--landing-bg\)\]\/10:hover{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-bg\)\]\/10:hover{background-color:color-mix(in oklab, var(--landing-bg) 10%, transparent)}}.ui\:hover\:bg-\[var\(--landing-bg-section\)\]:hover{background-color:var(--landing-bg-section)}.ui\:hover\:bg-\[var\(--landing-button-primary-bg-hover\)\]:hover{background-color:var(--landing-button-primary-bg-hover)}.ui\:hover\:bg-\[var\(--landing-button-secondary-bg-hover\)\]:hover{background-color:var(--landing-button-secondary-bg-hover)}.ui\:hover\:bg-\[var\(--landing-button-tertiary-bg-hover\)\]:hover{background-color:var(--landing-button-tertiary-bg-hover)}.ui\:hover\:bg-\[var\(--landing-card\)\]:hover{background-color:var(--landing-card)}.ui\:hover\:bg-\[var\(--landing-card-soft\)\]:hover,.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/30:hover{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/30:hover{background-color:color-mix(in oklab, var(--landing-card-soft) 30%, transparent)}}.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/40:hover{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/40:hover{background-color:color-mix(in oklab, var(--landing-card-soft) 40%, transparent)}}.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/60:hover{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/60:hover{background-color:color-mix(in oklab, var(--landing-card-soft) 60%, transparent)}}.ui\:hover\:bg-\[var\(--landing-fg\)\]:hover{background-color:var(--landing-fg)}.ui\:hover\:bg-accent:hover,.ui\:hover\:bg-accent\/25:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-accent\/25:hover{background-color:color-mix(in oklab, var(--accent) 25%, transparent)}}.ui\:hover\:bg-accent\/50:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-accent\/50:hover{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}.ui\:hover\:bg-amber-500\/10:hover{background-color:var(--ui-color-amber-500)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-amber-500\/10:hover{background-color:color-mix(in oklab, var(--ui-color-amber-500) 10%, transparent)}}.ui\:hover\:bg-black\/20:hover{background-color:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-black\/20:hover{background-color:color-mix(in oklab, var(--ui-color-black) 20%, transparent)}}.ui\:hover\:bg-black\/80:hover{background-color:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-black\/80:hover{background-color:color-mix(in oklab, var(--ui-color-black) 80%, transparent)}}.ui\:hover\:bg-muted:hover,.ui\:hover\:bg-muted\/40:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-muted\/40:hover{background-color:color-mix(in oklab, var(--muted) 40%, transparent)}}.ui\:hover\:bg-muted\/50:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-muted\/50:hover{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}.ui\:hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--primary) 90%, transparent)}}.ui\:hover\:bg-sidebar-accent:hover{background-color:var(--sidebar-accent)}.ui\:hover\:bg-transparent\!:hover{background-color:#0000!important}.ui\:hover\:bg-white:hover,.ui\:hover\:bg-white\/5:hover{background-color:var(--ui-color-white)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-white\/5:hover{background-color:color-mix(in oklab, var(--ui-color-white) 5%, transparent)}}.ui\:hover\:bg-white\/10:hover{background-color:var(--ui-color-white)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-white\/10:hover{background-color:color-mix(in oklab, var(--ui-color-white) 10%, transparent)}}.ui\:hover\:text-\[\#1a1a1a\]:hover{color:#1a1a1a}.ui\:hover\:text-\[\#e9eaed\]:hover{color:#e9eaed}.ui\:hover\:text-\[var\(--landing-accent\)\]:hover{color:var(--landing-accent)}.ui\:hover\:text-\[var\(--landing-accent-fg\)\]:hover{color:var(--landing-accent-fg)}.ui\:hover\:text-\[var\(--landing-bg\)\]:hover{color:var(--landing-bg)}.ui\:hover\:text-\[var\(--landing-fg\)\]:hover{color:var(--landing-fg)}.ui\:hover\:text-\[var\(--landing-fg-muted\)\]:hover{color:var(--landing-fg-muted)}.ui\:hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.ui\:hover\:text-foreground:hover{color:var(--foreground)}.ui\:hover\:text-muted-foreground:hover{color:var(--muted-foreground)}.ui\:hover\:text-primary:hover{color:var(--primary)}.ui\:hover\:text-sidebar-accent-foreground:hover{color:var(--sidebar-accent-foreground)}.ui\:hover\:underline:hover{text-decoration-line:underline}.ui\:hover\:opacity-90:hover{opacity:.9}.ui\:hover\:opacity-100:hover{opacity:1}.ui\:hover\:shadow-2xs:hover{--tw-shadow:0 1px var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:hover\:shadow-\[0_0_0_1px_var\(--sidebar-accent\)\]:hover{--tw-shadow:0 0 0 1px var(--tw-shadow-color,var(--sidebar-accent));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:hover\:shadow-xl:hover{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:hover\:ring-2:hover{--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)}.ui\:hover\:shadow-primary\/5:hover{--tw-shadow-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:shadow-primary\/5:hover{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--primary) 5%, transparent) var(--tw-shadow-alpha), transparent)}}.ui\:hover\:ring-primary\/40:hover{--tw-ring-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:ring-primary\/40:hover{--tw-ring-color:color-mix(in oklab, var(--primary) 40%, transparent)}}.ui\:hover\:ring-inset:hover{--tw-ring-inset:inset}.ui\:group-aria-disabled\/file-drop-zone-trigger\:hover\:cursor-not-allowed:is(:where(.ui\:group\/file-drop-zone-trigger)[aria-disabled=true] *):hover{cursor:not-allowed}.ui\:hover\:group-data-\[collapsible\=offcanvas\]\:bg-sidebar:hover:is(:where(.ui\:group)[data-collapsible=offcanvas] *){background-color:var(--sidebar)}.ui\:hover\:after\:bg-sidebar-border:hover:after{content:var(--tw-content);background-color:var(--sidebar-border)}}.ui\:focus\:bg-accent:focus{background-color:var(--accent)}.ui\:focus\:text-accent-foreground:focus{color:var(--accent-foreground)}.ui\: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)}.ui\:focus\:ring-ring:focus{--tw-ring-color:var(--ring)}.ui\:focus\:ring-offset-2:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ui\:focus\:outline-hidden:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.ui\:focus\:outline-hidden:focus{outline-offset:2px;outline:2px solid #0000}}.ui\:focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.ui\:focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.ui\:focus-visible\:ring-0:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + 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)}.ui\:focus-visible\:ring-0\!:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.ui\:focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:focus-visible\:ring-\[3px\]:focus-visible{--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)}.ui\:focus-visible\:ring-\[var\(--landing-accent\)\]\/50:focus-visible{--tw-ring-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:focus-visible\:ring-\[var\(--landing-accent\)\]\/50:focus-visible{--tw-ring-color:color-mix(in oklab, var(--landing-accent) 50%, transparent)}}.ui\:focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.ui\:focus-visible\:ring-ring:focus-visible,.ui\:focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.ui\:focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab, var(--ring) 50%, transparent)}}.ui\:focus-visible\:ring-offset-0\!:focus-visible{--tw-ring-offset-width:0px!important;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)!important}.ui\:focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ui\:focus-visible\:outline-hidden:focus-visible{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.ui\:focus-visible\:outline-hidden:focus-visible{outline-offset:2px;outline:2px solid #0000}}.ui\:focus-visible\:outline-1:focus-visible{outline-style:var(--tw-outline-style);outline-width:1px}.ui\:focus-visible\:outline-ring:focus-visible{outline-color:var(--ring)}.ui\:focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.ui\:active\:translate-y-px:active{--tw-translate-y:1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:active\:bg-sidebar-accent:active{background-color:var(--sidebar-accent)}.ui\:active\:text-sidebar-accent-foreground:active{color:var(--sidebar-accent-foreground)}.ui\:disabled\:pointer-events-none:disabled{pointer-events:none}.ui\:disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.ui\:disabled\:opacity-30:disabled{opacity:.3}.ui\:disabled\:opacity-40:disabled{opacity:.4}.ui\:disabled\:opacity-50:disabled{opacity:.5}:where([data-side=left]) .ui\:in-data-\[side\=left\]\:cursor-w-resize{cursor:w-resize}:where([data-side=right]) .ui\:in-data-\[side\=right\]\:cursor-e-resize{cursor:e-resize}:where([data-slot=tooltip-content]) .ui\:in-data-\[slot\=tooltip-content\]\:bg-background\/20{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){:where([data-slot=tooltip-content]) .ui\:in-data-\[slot\=tooltip-content\]\:bg-background\/20{background-color:color-mix(in oklab, var(--background) 20%, transparent)}}:where([data-slot=tooltip-content]) .ui\:in-data-\[slot\=tooltip-content\]\:text-background{color:var(--background)}.ui\:has-data-\[slot\=card-action\]\:grid-cols-\[1fr_auto\]:has([data-slot=card-action]){grid-template-columns:1fr auto}.ui\:has-data-\[state\=checked\]\:border-primary:has([data-state=checked]){border-color:var(--primary)}.ui\:has-data-\[state\=checked\]\:bg-primary\/5:has([data-state=checked]){background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:has-data-\[state\=checked\]\:bg-primary\/5:has([data-state=checked]){background-color:color-mix(in oklab, var(--primary) 5%, transparent)}}.ui\:has-data-\[variant\=inset\]\:bg-sidebar:has([data-variant=inset]){background-color:var(--sidebar)}.ui\:has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:border-ring:has([data-slot=input-group-control]:focus-visible){border-color:var(--ring)}.ui\:has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-\[3px\]:has([data-slot=input-group-control]:focus-visible){--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)}.ui\:has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-ring\/50:has([data-slot=input-group-control]:focus-visible){--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.ui\:has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-ring\/50:has([data-slot=input-group-control]:focus-visible){--tw-ring-color:color-mix(in oklab, var(--ring) 50%, transparent)}}.ui\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:border-destructive:has([data-slot][aria-invalid=true]){border-color:var(--destructive)}.ui\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/20:has([data-slot][aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/20:has([data-slot][aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.ui\:has-\[\>\[data-align\=block-end\]\]\:h-auto:has(>[data-align=block-end]){height:auto}.ui\:has-\[\>\[data-align\=block-end\]\]\:flex-col:has(>[data-align=block-end]){flex-direction:column}.ui\:has-\[\>\[data-align\=block-start\]\]\:h-auto:has(>[data-align=block-start]){height:auto}.ui\:has-\[\>\[data-align\=block-start\]\]\:flex-col:has(>[data-align=block-start]){flex-direction:column}.ui\:has-\[\>\[data-slot\=button-group\]\]\:gap-2:has(>[data-slot=button-group]){gap:calc(var(--ui-spacing) * 2)}.ui\:has-\[\>\[data-slot\=checkbox-group\]\]\:gap-3:has(>[data-slot=checkbox-group]){gap:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>\[data-slot\=field-content\]\]\:items-start:has(>[data-slot=field-content]){align-items:flex-start}.ui\:has-\[\>\[data-slot\=field\]\]\:w-full:has(>[data-slot=field]){width:100%}.ui\:has-\[\>\[data-slot\=field\]\]\:cursor-pointer:has(>[data-slot=field]){cursor:pointer}.ui\:has-\[\>\[data-slot\=field\]\]\:flex-col:has(>[data-slot=field]){flex-direction:column}.ui\:has-\[\>\[data-slot\=field\]\]\:rounded-md:has(>[data-slot=field]){border-radius:calc(var(--radius) - 2px)}.ui\:has-\[\>\[data-slot\=field\]\]\:border:has(>[data-slot=field]){border-style:var(--tw-border-style);border-width:1px}@media (hover:hover){.ui\:has-\[\>\[data-slot\=field\]\]\:hover\:bg-primary\/5:has(>[data-slot=field]):hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:has-\[\>\[data-slot\=field\]\]\:hover\:bg-primary\/5:has(>[data-slot=field]):hover{background-color:color-mix(in oklab, var(--primary) 5%, transparent)}}}.ui\:has-\[\>\[data-slot\=radio-group\]\]\:gap-3:has(>[data-slot=radio-group]){gap:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>button\]\:ms-\[-0\.45rem\]:has(>button){margin-inline-start:-.45rem}.ui\:has-\[\>button\]\:me-\[-0\.45rem\]:has(>button){margin-inline-end:-.45rem}.ui\:has-\[\>kbd\]\:ms-\[-0\.35rem\]:has(>kbd){margin-inline-start:-.35rem}.ui\:has-\[\>kbd\]\:me-\[-0\.35rem\]:has(>kbd){margin-inline-end:-.35rem}.ui\:has-\[\>svg\]\:grid-cols-\[calc\(var\(--spacing\)\*4\)_1fr\]:has(>svg){grid-template-columns:calc(var(--spacing) * 4) 1fr}.ui\:has-\[\>svg\]\:gap-x-3:has(>svg){column-gap:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>svg\]\:p-0:has(>svg){padding:calc(var(--ui-spacing) * 0)}.ui\:has-\[\>svg\]\:px-2:has(>svg){padding-inline:calc(var(--ui-spacing) * 2)}.ui\:has-\[\>svg\]\:px-2\.5:has(>svg){padding-inline:calc(var(--ui-spacing) * 2.5)}.ui\:has-\[\>svg\]\:px-3:has(>svg){padding-inline:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>svg\]\:px-4:has(>svg){padding-inline:calc(var(--ui-spacing) * 4)}.ui\:has-\[\>textarea\]\:h-auto:has(>textarea){height:auto}.ui\:aria-disabled\:pointer-events-none[aria-disabled=true]{pointer-events:none}.ui\:aria-disabled\:opacity-50[aria-disabled=true]{opacity:.5}.ui\:aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.ui\:aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.ui\:aria-selected\:bg-accent[aria-selected=true]{background-color:var(--accent)}.ui\:aria-selected\:text-accent-foreground[aria-selected=true]{color:var(--accent-foreground)}:is(.ui\:\*\*\:data-command-group\:px-2 *)[data-command-group]{padding-inline:calc(var(--ui-spacing) * 2)}:is(.ui\:\*\*\:data-command-input\:h-12 *)[data-command-input]{height:calc(var(--ui-spacing) * 12)}:is(.ui\:\*\*\:data-command-item\:px-2 *)[data-command-item]{padding-inline:calc(var(--ui-spacing) * 2)}:is(.ui\:\*\*\:data-command-item\:py-3 *)[data-command-item]{padding-block:calc(var(--ui-spacing) * 3)}.ui\:data-disabled\:pointer-events-none[data-disabled]{pointer-events:none}.ui\:data-disabled\:cursor-not-allowed[data-disabled]{cursor:not-allowed}.ui\:data-disabled\:opacity-50[data-disabled]{opacity:.5}.ui\:data-highlighted\:bg-accent[data-highlighted]{background-color:var(--accent)}.ui\:data-highlighted\:text-accent-foreground[data-highlighted]{color:var(--accent-foreground)}.ui\:data-inset\:pl-8[data-inset]{padding-left:calc(var(--ui-spacing) * 8)}.ui\:data-placeholder\:text-muted-foreground[data-placeholder]{color:var(--muted-foreground)}.ui\:data-\[active\=true\]\:bg-accent\/50[data-active=true]{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui\:data-\[active\=true\]\:bg-accent\/50[data-active=true]{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}.ui\:data-\[active\=true\]\:bg-primary\/10[data-active=true]{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:data-\[active\=true\]\:bg-primary\/10[data-active=true]{background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.ui\:data-\[active\=true\]\:text-accent-foreground[data-active=true]{color:var(--accent-foreground)}.ui\:data-\[active\=true\]\:text-primary[data-active=true]{color:var(--primary)}@media (hover:hover){.ui\:data-\[active\=true\]\:hover\:bg-accent[data-active=true]:hover{background-color:var(--accent)}}.ui\:data-\[active\=true\]\:focus\:bg-accent[data-active=true]:focus{background-color:var(--accent)}.ui\:data-\[collapsed\=true\]\:max-h-\[300px\][data-collapsed=true]{max-height:300px}.ui\:data-\[current\=true\]\:bg-muted[data-current=true]{background-color:var(--muted)}.ui\:data-\[disabled\=true\]\:pointer-events-none[data-disabled=true]{pointer-events:none}.ui\:data-\[disabled\=true\]\:opacity-50[data-disabled=true]{opacity:.5}.ui\:data-\[inset\]\:pl-8[data-inset]{padding-left:calc(var(--ui-spacing) * 8)}.ui\:data-\[invalid\=true\]\:text-destructive[data-invalid=true]{color:var(--destructive)}.ui\:data-\[motion\=from-end\]\:slide-in-from-end-52[data-motion=from-end]:where(:dir(ltr),[dir=ltr]){--tw-enter-translate-x:calc(52*var(--spacing))}.ui\:data-\[motion\=from-end\]\:slide-in-from-end-52[data-motion=from-end]:where(:dir(rtl),[dir=rtl]),.ui\:data-\[motion\=from-start\]\:slide-in-from-start-52[data-motion=from-start]:where(:dir(ltr),[dir=ltr]){--tw-enter-translate-x:calc(52*var(--spacing)*-1)}.ui\:data-\[motion\=from-start\]\:slide-in-from-start-52[data-motion=from-start]:where(:dir(rtl),[dir=rtl]){--tw-enter-translate-x:calc(52*var(--spacing))}.ui\:data-\[motion\=to-end\]\:slide-out-to-end-52[data-motion=to-end]:where(:dir(ltr),[dir=ltr]){--tw-exit-translate-x:calc(52*var(--spacing))}.ui\:data-\[motion\=to-end\]\:slide-out-to-end-52[data-motion=to-end]:where(:dir(rtl),[dir=rtl]),.ui\:data-\[motion\=to-start\]\:slide-out-to-start-52[data-motion=to-start]:where(:dir(ltr),[dir=ltr]){--tw-exit-translate-x:calc(52*var(--spacing)*-1)}.ui\:data-\[motion\=to-start\]\:slide-out-to-start-52[data-motion=to-start]:where(:dir(rtl),[dir=rtl]){--tw-exit-translate-x:calc(52*var(--spacing))}.ui\:data-\[motion\^\=from-\]\:animate-in[data-motion^=from-]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[motion\^\=from-\]\:fade-in[data-motion^=from-]{--tw-enter-opacity:0}.ui\:data-\[motion\^\=to-\]\:animate-out[data-motion^=to-]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[motion\^\=to-\]\:fade-out[data-motion^=to-]{--tw-exit-opacity:0}.ui\:data-\[orientation\=horizontal\]\:h-px[data-orientation=horizontal]{height:1px}.ui\:data-\[orientation\=horizontal\]\:w-full[data-orientation=horizontal]{width:100%}.ui\:data-\[orientation\=vertical\]\:h-auto[data-orientation=vertical]{height:auto}.ui\:data-\[orientation\=vertical\]\:h-full[data-orientation=vertical]{height:100%}.ui\:data-\[orientation\=vertical\]\:w-px[data-orientation=vertical]{width:1px}.ui\:data-\[side\=bottom\]\:-translate-x-1\/2[data-side=bottom]{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=bottom\]\:-translate-y-\[calc\(-50\%\+1px\)\][data-side=bottom]{--tw-translate-y:calc(calc(-50% + 1px) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y:calc(var(--ui-spacing) * 1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=bottom\]\:slide-in-from-top-2[data-side=bottom]{--tw-enter-translate-y:calc(2*var(--spacing)*-1)}.ui\:data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x:calc(var(--ui-spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=left\]\:-translate-y-\[calc\(50\%-3px\)\][data-side=left]{--tw-translate-y:calc(calc(50% - 3px) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=left\]\:slide-in-from-end-2[data-side=left]:where(:dir(ltr),[dir=ltr]){--tw-enter-translate-x:calc(2*var(--spacing))}.ui\:data-\[side\=left\]\:slide-in-from-end-2[data-side=left]:where(:dir(rtl),[dir=rtl]){--tw-enter-translate-x:calc(2*var(--spacing)*-1)}.ui\:data-\[side\=left\]\:slide-in-from-right-2[data-side=left]{--tw-enter-translate-x:calc(2*var(--spacing))}.ui\:data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x:calc(var(--ui-spacing) * 1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=right\]\:translate-x-\[calc\(50\%\+2px\)\][data-side=right]{--tw-translate-x:calc(50% + 2px);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=right\]\:translate-y-1\/2[data-side=right]{--tw-translate-y:calc(1 / 2 * 100%);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=right\]\:slide-in-from-start-2[data-side=right]:where(:dir(ltr),[dir=ltr]){--tw-enter-translate-x:calc(2*var(--spacing)*-1)}.ui\:data-\[side\=right\]\:slide-in-from-start-2[data-side=right]:where(:dir(rtl),[dir=rtl]){--tw-enter-translate-x:calc(2*var(--spacing))}.ui\:data-\[side\=right\]\:slide-in-from-left-2[data-side=right]{--tw-enter-translate-x:calc(2*var(--spacing)*-1)}.ui\:data-\[side\=top\]\:translate-x-1\/2[data-side=top]{--tw-translate-x:calc(1 / 2 * 100%);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y:calc(var(--ui-spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=top\]\:translate-y-\[calc\(-50\%\+2px\)\][data-side=top]{--tw-translate-y:calc(-50% + 2px);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=top\]\:slide-in-from-bottom-2[data-side=top]{--tw-enter-translate-y:calc(2*var(--spacing))}.ui\:data-\[size\=default\]\:h-9[data-size=default]{height:calc(var(--ui-spacing) * 9)}.ui\:data-\[size\=sm\]\:h-8[data-size=sm]{height:calc(var(--ui-spacing) * 8)}.ui\:data-\[slot\=checkbox-group\]\:gap-3[data-slot=checkbox-group]{gap:calc(var(--ui-spacing) * 3)}:is(.ui\:\*\:data-\[slot\=field\]\:p-4>*)[data-slot=field]{padding:calc(var(--ui-spacing) * 4)}:is(.ui\:\*\:data-\[slot\=field-group\]\:gap-4>*)[data-slot=field-group]{gap:calc(var(--ui-spacing) * 4)}:is(.ui\:\*\*\:data-\[slot\=navigation-menu-link\]\:focus\:ring-0 *)[data-slot=navigation-menu-link]:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + 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)}:is(.ui\:\*\*\:data-\[slot\=navigation-menu-link\]\:focus\:outline-none *)[data-slot=navigation-menu-link]:focus{--tw-outline-style:none;outline-style:none}:is(.ui\:\*\*\:data-\[slot\=select-value\]\:line-clamp-1 *)[data-slot=select-value]{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}:is(.ui\:\*\*\:data-\[slot\=select-value\]\:flex *)[data-slot=select-value]{display:flex}:is(.ui\:\*\*\:data-\[slot\=select-value\]\:items-center *)[data-slot=select-value]{align-items:center}:is(.ui\:\*\*\:data-\[slot\=select-value\]\:gap-2 *)[data-slot=select-value]{gap:calc(var(--ui-spacing) * 2)}.ui\:data-\[state\=active\]\:bg-background[data-state=active]{background-color:var(--background)}.ui\:data-\[state\=active\]\:text-foreground[data-state=active]{color:var(--foreground)}.ui\:data-\[state\=active\]\:shadow-sm[data-state=active]{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:data-\[state\=checked\]\:translate-x-\[calc\(100\%-2px\)\][data-state=checked]{--tw-translate-x:calc(100% - 2px);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[state\=checked\]\:border-primary[data-state=checked]{border-color:var(--primary)}.ui\:data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:var(--primary)}.ui\:data-\[state\=checked\]\:text-primary-foreground[data-state=checked]{color:var(--primary-foreground)}.ui\:data-\[state\=closed\]\:animate-accordion-up[data-state=closed]{animation:accordion-up var(--tw-animation-duration,var(--tw-duration,.2s))var(--tw-ease,ease-out)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=closed\]\:animate-out[data-state=closed]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=closed\]\:duration-300[data-state=closed]{--tw-duration:.3s;transition-duration:.3s}.ui\:data-\[state\=closed\]\:fade-out-0[data-state=closed]{--tw-exit-opacity:0}.ui\:data-\[state\=closed\]\:zoom-out-95[data-state=closed]{--tw-exit-scale:.95}.ui\:data-\[state\=closed\]\:slide-out-to-bottom[data-state=closed]{--tw-exit-translate-y:100%}.ui\:data-\[state\=closed\]\:slide-out-to-left[data-state=closed]{--tw-exit-translate-x:-100%}.ui\:data-\[state\=closed\]\:slide-out-to-right[data-state=closed]{--tw-exit-translate-x:100%}.ui\:data-\[state\=closed\]\:slide-out-to-top[data-state=closed]{--tw-exit-translate-y:-100%}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=closed\]\:animate-out:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=closed]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=closed\]\:fade-out-0:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=closed]{--tw-exit-opacity:0}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=closed\]\:zoom-out-95:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=closed]{--tw-exit-scale:.95}.ui\:data-\[state\=hidden\]\:animate-out[data-state=hidden]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=hidden\]\:fade-out[data-state=hidden]{--tw-exit-opacity:0}.ui\:data-\[state\=off\]\:text-muted-foreground[data-state=off]{color:var(--muted-foreground)}@media (hover:hover){.ui\:hover\:data-\[state\=off\]\:text-accent-foreground:hover[data-state=off]{color:var(--accent-foreground)}}.ui\:data-\[state\=on\]\:bg-accent[data-state=on]{background-color:var(--accent)}.ui\:data-\[state\=on\]\:bg-primary[data-state=on]{background-color:var(--primary)}.ui\:data-\[state\=on\]\:bg-transparent[data-state=on]{background-color:#0000}.ui\:data-\[state\=on\]\:text-accent-foreground[data-state=on]{color:var(--accent-foreground)}.ui\:data-\[state\=on\]\:text-muted-foreground[data-state=on]{color:var(--muted-foreground)}.ui\:data-\[state\=on\]\:text-primary-foreground[data-state=on]{color:var(--primary-foreground)}@media (hover:hover){.ui\:hover\:data-\[state\=on\]\:text-accent-foreground:hover[data-state=on]{color:var(--accent-foreground)}}.ui\:data-\[state\=open\]\:animate-accordion-down[data-state=open]{animation:accordion-down var(--tw-animation-duration,var(--tw-duration,.2s))var(--tw-ease,ease-out)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=open\]\:animate-in[data-state=open]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=open\]\:bg-accent[data-state=open],.ui\:data-\[state\=open\]\:bg-accent\/50[data-state=open]{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui\:data-\[state\=open\]\:bg-accent\/50[data-state=open]{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}.ui\:data-\[state\=open\]\:text-accent-foreground[data-state=open]{color:var(--accent-foreground)}.ui\:data-\[state\=open\]\:opacity-100[data-state=open]{opacity:1}.ui\:data-\[state\=open\]\:duration-500[data-state=open]{--tw-duration:.5s;transition-duration:.5s}.ui\:data-\[state\=open\]\:fade-in-0[data-state=open]{--tw-enter-opacity:0}.ui\:data-\[state\=open\]\:zoom-in-90[data-state=open]{--tw-enter-scale:.9}.ui\:data-\[state\=open\]\:zoom-in-95[data-state=open]{--tw-enter-scale:.95}.ui\:data-\[state\=open\]\:slide-in-from-bottom[data-state=open]{--tw-enter-translate-y:100%}.ui\:data-\[state\=open\]\:slide-in-from-left[data-state=open]{--tw-enter-translate-x:-100%}.ui\:data-\[state\=open\]\:slide-in-from-right[data-state=open]{--tw-enter-translate-x:100%}.ui\:data-\[state\=open\]\:slide-in-from-top[data-state=open]{--tw-enter-translate-y:-100%}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=open\]\:animate-in:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=open]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=open\]\:fade-in-0:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=open]{--tw-enter-opacity:0}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=open\]\:zoom-in-95:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=open]{--tw-enter-scale:.95}@media (hover:hover){.ui\:data-\[state\=open\]\:hover\:bg-accent[data-state=open]:hover{background-color:var(--accent)}.ui\:data-\[state\=open\]\:hover\:bg-sidebar-accent[data-state=open]:hover{background-color:var(--sidebar-accent)}.ui\:data-\[state\=open\]\:hover\:text-sidebar-accent-foreground[data-state=open]:hover{color:var(--sidebar-accent-foreground)}}.ui\:data-\[state\=open\]\:focus\:bg-accent[data-state=open]:focus{background-color:var(--accent)}.ui\:data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:var(--muted)}.ui\:data-\[state\=unchecked\]\:translate-x-0[data-state=unchecked]{--tw-translate-x:calc(var(--ui-spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[state\=unchecked\]\:bg-input[data-state=unchecked]{background-color:var(--input)}.ui\:data-\[state\=visible\]\:animate-in[data-state=visible]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=visible\]\:fade-in[data-state=visible]{--tw-enter-opacity:0}.ui\:data-\[variant\=destructive\]\:text-destructive[data-variant=destructive]{color:var(--destructive)}.ui\:data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:color-mix(in oklab, var(--destructive) 10%, transparent)}}.ui\:data-\[variant\=destructive\]\:focus\:text-destructive[data-variant=destructive]:focus{color:var(--destructive)}.ui\:data-\[variant\=destructive\]\:data-highlighted\:bg-destructive\/10[data-variant=destructive][data-highlighted]{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:data-\[variant\=destructive\]\:data-highlighted\:bg-destructive\/10[data-variant=destructive][data-highlighted]{background-color:color-mix(in oklab, var(--destructive) 10%, transparent)}}.ui\:data-\[variant\=destructive\]\:data-highlighted\:text-destructive[data-variant=destructive][data-highlighted]{color:var(--destructive)}.ui\:data-\[variant\=label\]\:text-sm[data-variant=label]{font-size:var(--ui-text-sm);line-height:var(--tw-leading,var(--ui-text-sm--line-height))}.ui\:data-\[variant\=legend\]\:text-base[data-variant=legend]{font-size:var(--ui-text-base);line-height:var(--tw-leading,var(--ui-text-base--line-height))}.ui\:data-\[vaul-drawer-direction\=bottom\]\:inset-x-0[data-vaul-drawer-direction=bottom]{inset-inline:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=bottom\]\:bottom-0[data-vaul-drawer-direction=bottom]{bottom:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=bottom\]\:mt-24[data-vaul-drawer-direction=bottom]{margin-top:calc(var(--ui-spacing) * 24)}.ui\:data-\[vaul-drawer-direction\=bottom\]\:max-h-\[80vh\][data-vaul-drawer-direction=bottom]{max-height:80vh}.ui\:data-\[vaul-drawer-direction\=bottom\]\:rounded-t-lg[data-vaul-drawer-direction=bottom]{border-top-left-radius:var(--radius);border-top-right-radius:var(--radius)}.ui\:data-\[vaul-drawer-direction\=bottom\]\:border-t[data-vaul-drawer-direction=bottom]{border-top-style:var(--tw-border-style);border-top-width:1px}.ui\:data-\[vaul-drawer-direction\=left\]\:inset-y-0[data-vaul-drawer-direction=left]{inset-block:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=left\]\:start-0[data-vaul-drawer-direction=left]{inset-inline-start:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=left\]\:w-3\/4[data-vaul-drawer-direction=left]{width:75%}.ui\:data-\[vaul-drawer-direction\=left\]\:border-e[data-vaul-drawer-direction=left]{border-inline-end-style:var(--tw-border-style);border-inline-end-width:1px}.ui\:data-\[vaul-drawer-direction\=right\]\:inset-y-0[data-vaul-drawer-direction=right]{inset-block:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=right\]\:end-0[data-vaul-drawer-direction=right]{inset-inline-end:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=right\]\:w-3\/4[data-vaul-drawer-direction=right]{width:75%}.ui\:data-\[vaul-drawer-direction\=right\]\:border-s[data-vaul-drawer-direction=right]{border-inline-start-style:var(--tw-border-style);border-inline-start-width:1px}.ui\:data-\[vaul-drawer-direction\=top\]\:inset-x-0[data-vaul-drawer-direction=top]{inset-inline:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=top\]\:top-0[data-vaul-drawer-direction=top]{top:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=top\]\:mb-24[data-vaul-drawer-direction=top]{margin-bottom:calc(var(--ui-spacing) * 24)}.ui\:data-\[vaul-drawer-direction\=top\]\:max-h-\[80vh\][data-vaul-drawer-direction=top]{max-height:80vh}.ui\:data-\[vaul-drawer-direction\=top\]\:rounded-b-lg[data-vaul-drawer-direction=top]{border-bottom-right-radius:var(--radius);border-bottom-left-radius:var(--radius)}.ui\:data-\[vaul-drawer-direction\=top\]\:border-b[data-vaul-drawer-direction=top]{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.ui\:nth-last-2\:-mt-1:nth-last-child(2){margin-top:calc(var(--ui-spacing) * -1)}@supports ((-webkit-backdrop-filter:var(--tw)) or (backdrop-filter:var(--tw))){.ui\:supports-\[backdrop-filter\]\:bg-background\/80{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.ui\:supports-\[backdrop-filter\]\:bg-background\/80{background-color:color-mix(in oklab, var(--background) 80%, transparent)}}}@media (min-width:40rem){.ui\:sm\:top-6{top:calc(var(--ui-spacing) * 6)}.ui\:sm\:bottom-6{bottom:calc(var(--ui-spacing) * 6)}.ui\:sm\:col-span-2{grid-column:span 2/span 2}.ui\:sm\:flex{display:flex}.ui\:sm\:inline-flex{display:inline-flex}.ui\:sm\:w-64{width:calc(var(--ui-spacing) * 64)}.ui\:sm\:max-w-lg{max-width:var(--ui-container-lg)}.ui\:sm\:max-w-sm{max-width:var(--ui-container-sm)}.ui\:sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ui\:sm\:flex-row{flex-direction:row}.ui\:sm\:items-center{align-items:center}.ui\:sm\:items-end{align-items:flex-end}.ui\:sm\:justify-between{justify-content:space-between}.ui\:sm\:justify-end{justify-content:flex-end}.ui\:sm\:gap-2\.5{gap:calc(var(--ui-spacing) * 2.5)}.ui\:sm\:gap-3{gap:calc(var(--ui-spacing) * 3)}.ui\:sm\:rounded-lg{border-radius:var(--radius)}.ui\:sm\:border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.ui\:sm\:p-6{padding:calc(var(--ui-spacing) * 6)}.ui\:sm\:px-6{padding-inline:calc(var(--ui-spacing) * 6)}.ui\:sm\:py-32{padding-block:calc(var(--ui-spacing) * 32)}.ui\:sm\:pr-2\.5{padding-right:calc(var(--ui-spacing) * 2.5)}.ui\:sm\:pl-2\.5{padding-left:calc(var(--ui-spacing) * 2.5)}.ui\:sm\:text-3xl{font-size:var(--ui-text-3xl);line-height:var(--tw-leading,var(--ui-text-3xl--line-height))}.ui\:sm\:text-5xl{font-size:var(--ui-text-5xl);line-height:var(--tw-leading,var(--ui-text-5xl--line-height))}.ui\:sm\:text-xl{font-size:var(--ui-text-xl);line-height:var(--tw-leading,var(--ui-text-xl--line-height))}.ui\:data-\[vaul-drawer-direction\=left\]\:sm\:max-w-sm[data-vaul-drawer-direction=left],.ui\:data-\[vaul-drawer-direction\=right\]\:sm\:max-w-sm[data-vaul-drawer-direction=right]{max-width:var(--ui-container-sm)}}@media (min-width:48rem){.ui\:md\:absolute{position:absolute}.ui\:md\:top-8{top:calc(var(--ui-spacing) * 8)}.ui\:md\:bottom-8{bottom:calc(var(--ui-spacing) * 8)}.ui\:md\:col-span-1{grid-column:span 1/span 1}.ui\:md\:col-span-4{grid-column:span 4/span 4}.ui\:md\:col-span-7{grid-column:span 7/span 7}.ui\:md\:col-start-9{grid-column-start:9}.ui\:md\:mx-0{margin-inline:calc(var(--ui-spacing) * 0)}.ui\:md\:mt-12{margin-top:calc(var(--ui-spacing) * 12)}.ui\:md\:mb-12{margin-bottom:calc(var(--ui-spacing) * 12)}.ui\:md\:block{display:block}.ui\:md\:flex{display:flex}.ui\:md\:size-\[1\.125rem\]{width:1.125rem;height:1.125rem}.ui\:md\:h-7{height:calc(var(--ui-spacing) * 7)}.ui\:md\:h-8{height:calc(var(--ui-spacing) * 8)}.ui\:md\:h-14{height:calc(var(--ui-spacing) * 14)}.ui\:md\:h-\[220px\]{height:220px}.ui\:md\:h-\[480px\]{height:480px}.ui\:md\:w-24{width:calc(var(--ui-spacing) * 24)}.ui\:md\:w-52{width:calc(var(--ui-spacing) * 52)}.ui\:md\:w-\[var\(--bits-navigation-menu-viewport-width\)\]{width:var(--bits-navigation-menu-viewport-width)}.ui\:md\:w-auto{width:auto}.ui\:md\:w-full{width:100%}.ui\:md\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ui\:md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ui\:md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.ui\:md\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.ui\:md\:grid-cols-\[1fr_2fr\]{grid-template-columns:1fr 2fr}.ui\:md\:grid-cols-\[180px_1fr\]{grid-template-columns:180px 1fr}.ui\:md\:grid-cols-\[260px_1fr\]{grid-template-columns:260px 1fr}.ui\:md\:grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.ui\:md\:grid-cols-\[minmax\(0\,1\.4fr\)_repeat\(auto-fit\,minmax\(140px\,1fr\)\)\]{grid-template-columns:minmax(0,1.4fr) repeat(auto-fit,minmax(140px,1fr))}.ui\:md\:grid-cols-\[minmax\(0\,220px\)_1fr\]{grid-template-columns:minmax(0,220px) 1fr}.ui\:md\:flex-col{flex-direction:column}.ui\:md\:flex-row{flex-direction:row}.ui\:md\:items-baseline{align-items:baseline}.ui\:md\:items-center{align-items:center}.ui\:md\:items-end{align-items:flex-end}.ui\:md\:items-start{align-items:flex-start}.ui\:md\:justify-between{justify-content:space-between}.ui\:md\:justify-center{justify-content:center}.ui\:md\:justify-end{justify-content:flex-end}.ui\:md\:gap-4{gap:calc(var(--ui-spacing) * 4)}.ui\:md\:gap-8{gap:calc(var(--ui-spacing) * 8)}.ui\:md\:gap-10{gap:calc(var(--ui-spacing) * 10)}.ui\:md\:gap-x-12{column-gap:calc(var(--ui-spacing) * 12)}.ui\:md\:gap-y-12{row-gap:calc(var(--ui-spacing) * 12)}.ui\:md\:self-auto{align-self:auto}.ui\:md\:overflow-x-auto{overflow-x:auto}.ui\:md\:overflow-x-visible{overflow-x:visible}.ui\:md\:overflow-y-visible{overflow-y:visible}.ui\:md\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.ui\:md\:border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.ui\:md\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.ui\:md\:border-border{border-color:var(--border)}.ui\:md\:p-6{padding:calc(var(--ui-spacing) * 6)}.ui\:md\:p-8{padding:calc(var(--ui-spacing) * 8)}.ui\:md\:p-12{padding:calc(var(--ui-spacing) * 12)}.ui\:md\:px-6{padding-inline:calc(var(--ui-spacing) * 6)}.ui\:md\:px-8{padding-inline:calc(var(--ui-spacing) * 8)}.ui\:md\:py-0{padding-block:calc(var(--ui-spacing) * 0)}.ui\:md\:py-1{padding-block:calc(var(--ui-spacing) * 1)}.ui\:md\:py-14{padding-block:calc(var(--ui-spacing) * 14)}.ui\:md\:py-16{padding-block:calc(var(--ui-spacing) * 16)}.ui\:md\:py-20{padding-block:calc(var(--ui-spacing) * 20)}.ui\:md\:py-24{padding-block:calc(var(--ui-spacing) * 24)}.ui\:md\:py-28{padding-block:calc(var(--ui-spacing) * 28)}.ui\:md\:py-32{padding-block:calc(var(--ui-spacing) * 32)}.ui\:md\:py-40{padding-block:calc(var(--ui-spacing) * 40)}.ui\:md\:pt-16{padding-top:calc(var(--ui-spacing) * 16)}.ui\:md\:pt-20{padding-top:calc(var(--ui-spacing) * 20)}.ui\:md\:pt-24{padding-top:calc(var(--ui-spacing) * 24)}.ui\:md\:pb-20{padding-bottom:calc(var(--ui-spacing) * 20)}.ui\:md\:pb-24{padding-bottom:calc(var(--ui-spacing) * 24)}.ui\:md\:pb-28{padding-bottom:calc(var(--ui-spacing) * 28)}.ui\:md\:pl-8{padding-left:calc(var(--ui-spacing) * 8)}.ui\:md\:text-right{text-align:right}.ui\:md\:text-2xl{font-size:var(--ui-text-2xl);line-height:var(--tw-leading,var(--ui-text-2xl--line-height))}.ui\:md\:text-3xl{font-size:var(--ui-text-3xl);line-height:var(--tw-leading,var(--ui-text-3xl--line-height))}.ui\:md\:text-4xl{font-size:var(--ui-text-4xl);line-height:var(--tw-leading,var(--ui-text-4xl--line-height))}.ui\:md\:text-5xl{font-size:var(--ui-text-5xl);line-height:var(--tw-leading,var(--ui-text-5xl--line-height))}.ui\:md\:text-6xl{font-size:var(--ui-text-6xl);line-height:var(--tw-leading,var(--ui-text-6xl--line-height))}.ui\:md\:text-7xl{font-size:var(--ui-text-7xl);line-height:var(--tw-leading,var(--ui-text-7xl--line-height))}.ui\:md\:text-lg{font-size:var(--ui-text-lg);line-height:var(--tw-leading,var(--ui-text-lg--line-height))}.ui\:md\:text-sm{font-size:var(--ui-text-sm);line-height:var(--tw-leading,var(--ui-text-sm--line-height))}.ui\:md\:text-xl{font-size:var(--ui-text-xl);line-height:var(--tw-leading,var(--ui-text-xl--line-height))}.ui\:md\:text-\[38px\]{font-size:38px}.ui\:md\:text-\[40px\]{font-size:40px}.ui\:md\:text-\[56px\]{font-size:56px}.ui\:md\:text-\[88px\]{font-size:88px}.ui\:md\:leading-20{--tw-leading:calc(var(--ui-spacing) * 20);line-height:calc(var(--ui-spacing) * 20)}.ui\:md\:opacity-0{opacity:0}.ui\:md\:peer-data-\[variant\=inset\]\:m-2:is(:where(.ui\:peer)[data-variant=inset]~*){margin:calc(var(--ui-spacing) * 2)}.ui\:md\:peer-data-\[variant\=inset\]\:ml-0:is(:where(.ui\:peer)[data-variant=inset]~*){margin-left:calc(var(--ui-spacing) * 0)}.ui\:md\:peer-data-\[variant\=inset\]\:rounded-xl:is(:where(.ui\:peer)[data-variant=inset]~*){border-radius:calc(var(--radius) + 4px)}.ui\:md\:peer-data-\[variant\=inset\]\:shadow-sm:is(:where(.ui\:peer)[data-variant=inset]~*){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:md\:peer-data-\[variant\=inset\]\:peer-data-\[state\=collapsed\]\:ml-2:is(:where(.ui\:peer)[data-variant=inset]~*):is(:where(.ui\:peer)[data-state=collapsed]~*){margin-left:calc(var(--ui-spacing) * 2)}.ui\:md\:after\:hidden:after{content:var(--tw-content);display:none}}@media (min-width:64rem){.ui\:lg\:block{display:block}.ui\:lg\:hidden{display:none}.ui\:lg\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ui\:lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ui\:lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.ui\:lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.ui\:lg\:grid-cols-\[1\.15fr_1fr\]{grid-template-columns:1.15fr 1fr}.ui\:lg\:grid-cols-\[1fr_1\.05fr\]{grid-template-columns:1fr 1.05fr}.ui\:lg\:gap-14{gap:calc(var(--ui-spacing) * 14)}.ui\:lg\:gap-20{gap:calc(var(--ui-spacing) * 20)}.ui\:lg\:px-6{padding-inline:calc(var(--ui-spacing) * 6)}.ui\:lg\:px-8{padding-inline:calc(var(--ui-spacing) * 8)}.ui\:lg\:py-10{padding-block:calc(var(--ui-spacing) * 10)}.ui\:lg\:py-24{padding-block:calc(var(--ui-spacing) * 24)}.ui\:lg\:pb-12{padding-bottom:calc(var(--ui-spacing) * 12)}.ui\:lg\:text-4xl{font-size:var(--ui-text-4xl);line-height:var(--tw-leading,var(--ui-text-4xl--line-height))}.ui\:lg\:text-5xl{font-size:var(--ui-text-5xl);line-height:var(--tw-leading,var(--ui-text-5xl--line-height))}.ui\:lg\:text-6xl{font-size:var(--ui-text-6xl);line-height:var(--tw-leading,var(--ui-text-6xl--line-height))}.ui\:lg\:text-7xl{font-size:var(--ui-text-7xl);line-height:var(--tw-leading,var(--ui-text-7xl--line-height))}.ui\:lg\:text-xl{font-size:var(--ui-text-xl);line-height:var(--tw-leading,var(--ui-text-xl--line-height))}.ui\:lg\:text-\[22px\]{font-size:22px}.ui\:lg\:text-\[40px\]{font-size:40px}.ui\:lg\:text-\[56px\]{font-size:56px}.ui\:lg\:text-\[64px\]{font-size:64px}.ui\:lg\:text-\[80px\]{font-size:80px}.ui\:lg\:text-\[110px\]{font-size:110px}}@container field-group (min-width:28rem){.ui\:\@md\/field-group\:flex-row{flex-direction:row}.ui\:\@md\/field-group\:items-center{align-items:center}.ui\:\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:items-start:has(>[data-slot=field-content]){align-items:flex-start}}@container (min-width:32rem){.ui\:\@lg\:w-48{width:calc(var(--ui-spacing) * 48)}.ui\:\@lg\:shrink-0{flex-shrink:0}.ui\:\@lg\:flex-row{flex-direction:row}}@container (min-width:36rem){.ui\:\@xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@container (min-width:42rem){.ui\:\@2xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@container (min-width:56rem){.ui\:\@4xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}.ui\:dark\:scale-0:where(.dark,.dark *){--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x) var(--tw-scale-y)}.ui\:dark\:scale-100:where(.dark,.dark *){--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}.ui\:dark\:-rotate-90:where(.dark,.dark *){rotate:-90deg}.ui\:dark\:rotate-0:where(.dark,.dark *){rotate:none}.ui\:dark\:border-amber-900:where(.dark,.dark *){border-color:var(--ui-color-amber-900)}.ui\:dark\:border-input:where(.dark,.dark *){border-color:var(--input)}.ui\:dark\:border-sky-900:where(.dark,.dark *){border-color:var(--ui-color-sky-900)}.ui\:dark\:border-slate-800:where(.dark,.dark *){border-color:var(--ui-color-slate-800)}.ui\:dark\:border-zinc-700:where(.dark,.dark *){border-color:var(--ui-color-zinc-700)}.ui\:dark\:border-zinc-800:where(.dark,.dark *){border-color:var(--ui-color-zinc-800)}.ui\:dark\:bg-\[\#09090B\]:where(.dark,.dark *){background-color:#09090b}.ui\:dark\:bg-amber-500:where(.dark,.dark *){background-color:var(--ui-color-amber-500)}.ui\:dark\:bg-amber-950:where(.dark,.dark *){background-color:var(--ui-color-amber-950)}.ui\:dark\:bg-card\!:where(.dark,.dark *){background-color:var(--card)!important}.ui\:dark\:bg-destructive\/60:where(.dark,.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-destructive\/60:where(.dark,.dark *){background-color:color-mix(in oklab, var(--destructive) 60%, transparent)}}.ui\:dark\:bg-destructive\/70:where(.dark,.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-destructive\/70:where(.dark,.dark *){background-color:color-mix(in oklab, var(--destructive) 70%, transparent)}}.ui\:dark\:bg-emerald-500:where(.dark,.dark *){background-color:var(--ui-color-emerald-500)}.ui\:dark\:bg-emerald-950\/20:where(.dark,.dark *){background-color:var(--ui-color-emerald-950)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-emerald-950\/20:where(.dark,.dark *){background-color:color-mix(in oklab, var(--ui-color-emerald-950) 20%, transparent)}}.ui\:dark\:bg-emerald-950\/30:where(.dark,.dark *){background-color:var(--ui-color-emerald-950)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-emerald-950\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--ui-color-emerald-950) 30%, transparent)}}.ui\:dark\:bg-input\/30:where(.dark,.dark *){background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-input\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--input) 30%, transparent)}}.ui\:dark\:bg-neutral-900:where(.dark,.dark *){background-color:var(--ui-color-neutral-900)}.ui\:dark\:bg-red-950\/30:where(.dark,.dark *){background-color:var(--ui-color-red-950)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-red-950\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--ui-color-red-950) 30%, transparent)}}.ui\:dark\:bg-sky-950:where(.dark,.dark *){background-color:var(--ui-color-sky-950)}.ui\:dark\:bg-slate-950:where(.dark,.dark *){background-color:var(--ui-color-slate-950)}.ui\:dark\:bg-transparent:where(.dark,.dark *){background-color:#0000}.ui\:dark\:bg-zinc-700:where(.dark,.dark *){background-color:var(--ui-color-zinc-700)}.ui\:dark\:via-white\/80:where(.dark,.dark *){--tw-gradient-via:var(--ui-color-white)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:via-white\/80:where(.dark,.dark *){--tw-gradient-via:color-mix(in oklab, var(--ui-color-white) 80%, transparent)}}.ui\:dark\:via-white\/80:where(.dark,.dark *){--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.ui\:dark\:fill-amber-400:where(.dark,.dark *){fill:var(--ui-color-amber-400)}.ui\:dark\:text-amber-50:where(.dark,.dark *){color:var(--ui-color-amber-50)}.ui\:dark\:text-amber-300:where(.dark,.dark *){color:var(--ui-color-amber-300)}.ui\:dark\:text-amber-400:where(.dark,.dark *){color:var(--ui-color-amber-400)}.ui\:dark\:text-amber-500\/40:where(.dark,.dark *){color:var(--ui-color-amber-500)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:text-amber-500\/40:where(.dark,.dark *){color:color-mix(in oklab, var(--ui-color-amber-500) 40%, transparent)}}.ui\:dark\:text-amber-950:where(.dark,.dark *){color:var(--ui-color-amber-950)}.ui\:dark\:text-emerald-950:where(.dark,.dark *){color:var(--ui-color-emerald-950)}.ui\:dark\:text-gray-700:where(.dark,.dark *){color:var(--ui-color-gray-700)}.ui\:dark\:text-muted-foreground:where(.dark,.dark *){color:var(--muted-foreground)}.ui\:dark\:text-neutral-400\/50:where(.dark,.dark *){color:var(--ui-color-neutral-400)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:text-neutral-400\/50:where(.dark,.dark *){color:color-mix(in oklab, var(--ui-color-neutral-400) 50%, transparent)}}.ui\:dark\:text-sky-50:where(.dark,.dark *){color:var(--ui-color-sky-50)}.ui\:dark\:text-white:where(.dark,.dark *){color:var(--ui-color-white)}.ui\:dark\:\[--dot-field-glow\:\#0a0a0a\]:where(.dark,.dark *){--dot-field-glow:#0a0a0a}@media (hover:hover){.ui\:dark\:hover\:border-input:where(.dark,.dark *):hover{border-color:var(--input)}.ui\:dark\:hover\:bg-input\/50:where(.dark,.dark *):hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:hover\:bg-input\/50:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--input) 50%, transparent)}}}.ui\:dark\:focus-visible\:ring-destructive\/40:where(.dark,.dark *):focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:focus-visible\:ring-destructive\/40:where(.dark,.dark *):focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}:where([data-slot=tooltip-content]) .ui\:dark\:in-data-\[slot\=tooltip-content\]\:bg-background\/10:where(.dark,.dark *){background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){:where([data-slot=tooltip-content]) .ui\:dark\:in-data-\[slot\=tooltip-content\]\:bg-background\/10:where(.dark,.dark *){background-color:color-mix(in oklab, var(--background) 10%, transparent)}}.ui\:dark\:has-data-\[state\=checked\]\:bg-primary\/10:where(.dark,.dark *):has([data-state=checked]){background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:has-data-\[state\=checked\]\:bg-primary\/10:where(.dark,.dark *):has([data-state=checked]){background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.ui\:dark\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/40:where(.dark,.dark *):has([data-slot][aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/40:where(.dark,.dark *):has([data-slot][aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.ui\:dark\:aria-invalid\:ring-destructive\/40:where(.dark,.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:aria-invalid\:ring-destructive\/40:where(.dark,.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.ui\:dark\:data-\[active\=true\]\:bg-primary\/20:where(.dark,.dark *)[data-active=true]{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:data-\[active\=true\]\:bg-primary\/20:where(.dark,.dark *)[data-active=true]{background-color:color-mix(in oklab, var(--primary) 20%, transparent)}}.ui\:dark\:data-\[state\=active\]\:border-input:where(.dark,.dark *)[data-state=active]{border-color:var(--input)}.ui\:dark\:data-\[state\=active\]\:bg-input\/30:where(.dark,.dark *)[data-state=active]{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:data-\[state\=active\]\:bg-input\/30:where(.dark,.dark *)[data-state=active]{background-color:color-mix(in oklab, var(--input) 30%, transparent)}}.ui\:dark\:data-\[state\=active\]\:text-foreground:where(.dark,.dark *)[data-state=active]{color:var(--foreground)}.ui\:dark\:data-\[state\=checked\]\:bg-primary:where(.dark,.dark *)[data-state=checked]{background-color:var(--primary)}.ui\:dark\:data-\[state\=checked\]\:bg-primary-foreground:where(.dark,.dark *)[data-state=checked]{background-color:var(--primary-foreground)}.ui\:dark\:data-\[state\=unchecked\]\:bg-foreground:where(.dark,.dark *)[data-state=unchecked]{background-color:var(--foreground)}.ui\:dark\:data-\[state\=unchecked\]\:bg-input\/80:where(.dark,.dark *)[data-state=unchecked]{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:data-\[state\=unchecked\]\:bg-input\/80:where(.dark,.dark *)[data-state=unchecked]{background-color:color-mix(in oklab, var(--input) 80%, transparent)}}.ui\:dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive]:focus{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.ui\:dark\:data-\[variant\=destructive\]\:data-highlighted\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive][data-highlighted]{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:data-\[variant\=destructive\]\:data-highlighted\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive][data-highlighted]{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.ui\:\[\&_\.lc-area-path\]\:opacity-100 .lc-area-path{opacity:1}.ui\:\[\&_\.lc-axis-tick\]\:stroke-0 .lc-axis-tick{stroke-width:0}.ui\:\[\&_\.lc-axis-tick-label\]\:fill-muted-foreground .lc-axis-tick-label{fill:var(--muted-foreground)}.ui\:\[\&_\.lc-axis-tick-label\]\:font-normal .lc-axis-tick-label{--tw-font-weight:var(--ui-font-weight-normal);font-weight:var(--ui-font-weight-normal)}.ui\:\[\&_\.lc-grid-x-radial-circle\]\:stroke-border .lc-grid-x-radial-circle,.ui\:\[\&_\.lc-grid-x-radial-line\]\:stroke-border .lc-grid-x-radial-line,.ui\:\[\&_\.lc-grid-y-radial-circle\]\:stroke-border .lc-grid-y-radial-circle,.ui\:\[\&_\.lc-grid-y-radial-line\]\:stroke-border .lc-grid-y-radial-line{stroke:var(--border)}.ui\:\[\&_\.lc-highlight-line\]\:stroke-0 .lc-highlight-line{stroke-width:0}.ui\:\[\&_\.lc-highlight-line\]\:opacity-100 .lc-highlight-line,.ui\:\[\&_\.lc-highlight-point\]\:opacity-100 .lc-highlight-point{opacity:1}.ui\:\[\&_\.lc-labels-text\:not\(\[fill\]\)\]\:fill-foreground .lc-labels-text:not([fill]){fill:var(--foreground)}.ui\:\[\&_\.lc-layout-svg-g\]\:fill-transparent .lc-layout-svg-g{fill:#0000}.ui\:\[\&_\.lc-legend-swatch\]\:size-2\.5 .lc-legend-swatch{width:calc(var(--ui-spacing) * 2.5);height:calc(var(--ui-spacing) * 2.5)}.ui\:\[\&_\.lc-legend-swatch\]\:rounded-\[2px\] .lc-legend-swatch{border-radius:2px}.ui\:\[\&_\.lc-legend-swatch-button\]\:items-center .lc-legend-swatch-button{align-items:center}.ui\:\[\&_\.lc-legend-swatch-button\]\:gap-1\.5 .lc-legend-swatch-button{gap:calc(var(--ui-spacing) * 1.5)}.ui\:\[\&_\.lc-legend-swatch-group\]\:items-center .lc-legend-swatch-group{align-items:center}.ui\:\[\&_\.lc-legend-swatch-group\]\:gap-4 .lc-legend-swatch-group{gap:calc(var(--ui-spacing) * 4)}.ui\:\[\&_\.lc-line\]\:stroke-border\/50 .lc-line{stroke:var(--border)}@supports (color:color-mix(in lab, red, red)){.ui\:\[\&_\.lc-line\]\:stroke-border\/50 .lc-line{stroke:color-mix(in oklab, var(--border) 50%, transparent)}}.ui\:\[\&_\.lc-root-container\]\:w-full .lc-root-container{width:100%}.ui\:\[\&_\.lc-rule-x-line\:not\(\.lc-grid-x-rule\)\]\:stroke-0 .lc-rule-x-line:not(.lc-grid-x-rule),.ui\:\[\&_\.lc-rule-y-line\:not\(\.lc-grid-y-rule\)\]\:stroke-0 .lc-rule-y-line:not(.lc-grid-y-rule){stroke-width:0}.ui\:\[\&_\.lc-spline-path\]\:opacity-100 .lc-spline-path{opacity:1}.ui\:\[\&_\.lc-text\]\:text-xs .lc-text{font-size:var(--ui-text-xs);line-height:var(--tw-leading,var(--ui-text-xs--line-height))}.ui\:\[\&_\.lc-text-svg\]\:overflow-visible .lc-text-svg{overflow:visible}.ui\:\[\&_\.lc-tooltip-rects-g\]\:fill-transparent .lc-tooltip-rects-g{fill:#0000}.ui\:\[\&_\.stroke-white\]\:stroke-transparent .stroke-white{stroke:#0000}.ui\:\[\&_\[data-command-group\]\:not\(\[hidden\]\)_\~\[data-command-group\]\]\:pt-0 [data-command-group]:not([hidden])~[data-command-group]{padding-top:calc(var(--ui-spacing) * 0)}.ui\:\[\&_\[data-command-input-wrapper\]_svg\]\:h-5 [data-command-input-wrapper] svg{height:calc(var(--ui-spacing) * 5)}.ui\:\[\&_\[data-command-input-wrapper\]_svg\]\:w-5 [data-command-input-wrapper] svg{width:calc(var(--ui-spacing) * 5)}.ui\:\[\&_\[data-command-item\]_svg\]\:h-5 [data-command-item] svg{height:calc(var(--ui-spacing) * 5)}.ui\:\[\&_\[data-command-item\]_svg\]\:w-5 [data-command-item] svg{width:calc(var(--ui-spacing) * 5)}.ui\:\[\&_img\]\:size-full img{width:100%;height:100%}.ui\:\[\&_img\]\:object-cover img{object-fit:cover}.ui\:\[\&_li\]\:mb-1 li{margin-bottom:calc(var(--ui-spacing) * 1)}.ui\:\[\&_p\]\:mb-2 p{margin-bottom:calc(var(--ui-spacing) * 2)}.ui\:\[\&_p\]\:leading-relaxed p{--tw-leading:var(--ui-leading-relaxed);line-height:var(--ui-leading-relaxed)}.ui\:\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.ui\:\[\&_svg\]\:size-8\! svg{width:calc(var(--ui-spacing) * 8)!important;height:calc(var(--ui-spacing) * 8)!important}.ui\:\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.ui\:\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3 svg:not([class*=size-]){width:calc(var(--ui-spacing) * 3);height:calc(var(--ui-spacing) * 3)}.ui\:\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--ui-spacing) * 4);height:calc(var(--ui-spacing) * 4)}.ui\:\[\&_svg\:not\(\[class\*\=\'text-\'\]\)\]\:text-muted-foreground svg:not([class*=text-]){color:var(--muted-foreground)}.ui\:\[\&_svg\:not\(\[class\*\=\'ui\:size-\'\]\)\]\:size-4 svg:not([class*=ui\:size-]){width:calc(var(--ui-spacing) * 4);height:calc(var(--ui-spacing) * 4)}.ui\:\[\&_svg\:not\(\[class\*\=\'ui\:size-\'\]\)\]\:size-6 svg:not([class*=ui\:size-]){width:calc(var(--ui-spacing) * 6);height:calc(var(--ui-spacing) * 6)}.ui\:\[\&_text\]\:stroke-transparent text{stroke:#0000}.ui\:\[\&_tr\]\:border-b tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.ui\:\[\&_tr\:last-child\]\:border-0 tr:last-child{border-style:var(--tw-border-style);border-width:0}.ui\:\[\&_ul\]\:list-disc ul{list-style-type:disc}.ui\:\[\&_ul\]\:pl-5 ul{padding-left:calc(var(--ui-spacing) * 5)}.ui\:\[\&\+\[data-slot\=item-content\]\]\:flex-none+[data-slot=item-content]{flex:none}.ui\:\[\&\:has\(\[data-slot\=dialog-footer\]\[data-sticky\=true\]\)\]\:pb-0:has([data-slot=dialog-footer][data-sticky=true]){padding-bottom:calc(var(--ui-spacing) * 0)}.ui\:\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:calc(var(--ui-spacing) * 0)}.ui\:\[\.border-b\]\:pb-3.border-b{padding-bottom:calc(var(--ui-spacing) * 3)}.ui\:\[\.border-b\]\:pb-6.border-b{padding-bottom:calc(var(--ui-spacing) * 6)}.ui\:\[\.border-t\]\:pt-3.border-t{padding-top:calc(var(--ui-spacing) * 3)}.ui\:\[\.border-t\]\:pt-6.border-t{padding-top:calc(var(--ui-spacing) * 6)}.ui\:\[a\]\:transition-colors:is(a){transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}@media (hover:hover){.ui\:\[a\]\:hover\:bg-accent\/50:is(a):hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui\:\[a\]\:hover\:bg-accent\/50:is(a):hover{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}}:is(.ui\:\*\:\[span\]\:last\:flex>*):is(span):last-child{display:flex}:is(.ui\:\*\:\[span\]\:last\:items-center>*):is(span):last-child{align-items:center}:is(.ui\:\*\:\[span\]\:last\:gap-2>*):is(span):last-child{gap:calc(var(--ui-spacing) * 2)}:is(.ui\:data-\[variant\=destructive\]\:\*\:\[svg\]\:text-destructive\![data-variant=destructive]>*):is(svg){color:var(--destructive)!important}.ui\:\[\&\>\*\]\:focus-visible\:relative>:focus-visible{position:relative}.ui\:\[\&\>\*\]\:focus-visible\:z-10>:focus-visible{z-index:10}@container field-group (min-width:28rem){.ui\:\@md\/field-group\:\[\&\>\*\]\:w-auto>*{width:auto}}.ui\:\[\&\>\*\:not\(\:first-child\)\]\:rounded-s-none>:not(:first-child){border-start-start-radius:0;border-end-start-radius:0}.ui\:\[\&\>\*\:not\(\:first-child\)\]\:rounded-t-none>:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.ui\:\[\&\>\*\:not\(\:first-child\)\]\:border-s-0>:not(:first-child){border-inline-start-style:var(--tw-border-style);border-inline-start-width:0}.ui\:\[\&\>\*\:not\(\:first-child\)\]\:border-t-0>:not(:first-child){border-top-style:var(--tw-border-style);border-top-width:0}.ui\:\[\&\>\*\:not\(\:last-child\)\]\:rounded-e-none>:not(:last-child){border-start-end-radius:0;border-end-end-radius:0}.ui\:\[\&\>\*\:not\(\:last-child\)\]\:rounded-b-none>:not(:last-child){border-bottom-right-radius:0;border-bottom-left-radius:0}.ui\:\[\&\>\[data-slot\=field-label\]\]\:flex-auto>[data-slot=field-label]{flex:auto}@container field-group (min-width:28rem){.ui\:\@md\/field-group\:\[\&\>\[data-slot\=field-label\]\]\:flex-auto>[data-slot=field-label]{flex:auto}}.ui\:has-\[select\[aria-hidden\=true\]\:last-child\]\:\[\&\>\[data-slot\=select-trigger\]\:last-of-type\]\:rounded-e-md:has(:is(select[aria-hidden=true]:last-child))>[data-slot=select-trigger]:last-of-type{border-start-end-radius:calc(var(--radius) - 2px);border-end-end-radius:calc(var(--radius) - 2px)}.ui\:\[\&\>\[data-slot\=select-trigger\]\:not\(\[class\*\=\'ui\:w-\'\]\)\]\:w-fit>[data-slot=select-trigger]:not([class*=ui\:w-]){width:fit-content}.ui\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content])>[role=checkbox],.ui\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content]) [role=radio]{margin-top:1px}@container field-group (min-width:28rem){.ui\:\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content])>[role=checkbox],.ui\:\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content]) [role=radio]{margin-top:1px}}.ui\:\[\&\>a\]\:underline>a{text-decoration-line:underline}.ui\:\[\&\>a\]\:underline-offset-4>a{text-underline-offset:4px}.ui\:\[\&\>a\:hover\]\:text-primary>a:hover{color:var(--primary)}.ui\:\[\&\>button\]\:hidden>button{display:none}.ui\:\[\&\>input\]\:flex-1>input{flex:1}.ui\:has-\[\>\[data-align\=block-end\]\]\:\[\&\>input\]\:pt-3:has(>[data-align=block-end])>input{padding-top:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>\[data-align\=block-start\]\]\:\[\&\>input\]\:pb-3:has(>[data-align=block-start])>input{padding-bottom:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>\[data-align\=inline-end\]\]\:\[\&\>input\]\:pe-2:has(>[data-align=inline-end])>input{padding-inline-end:calc(var(--ui-spacing) * 2)}.ui\:has-\[\>\[data-align\=inline-start\]\]\:\[\&\>input\]\:ps-2:has(>[data-align=inline-start])>input{padding-inline-start:calc(var(--ui-spacing) * 2)}.ui\:\[\&\>kbd\]\:rounded-\[calc\(var\(--radius\)-5px\)\]>kbd{border-radius:calc(var(--radius) - 5px)}.ui\:\[\&\>span\:last-child\]\:truncate>span:last-child{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ui\:\[\&\>svg\]\:pointer-events-none>svg{pointer-events:none}.ui\:\[\&\>svg\]\:size-2\.5>svg{width:calc(var(--ui-spacing) * 2.5);height:calc(var(--ui-spacing) * 2.5)}.ui\:\[\&\>svg\]\:size-3>svg{width:calc(var(--ui-spacing) * 3);height:calc(var(--ui-spacing) * 3)}.ui\:\[\&\>svg\]\:size-3\.5>svg{width:calc(var(--ui-spacing) * 3.5);height:calc(var(--ui-spacing) * 3.5)}.ui\:\[\&\>svg\]\:size-4>svg{width:calc(var(--ui-spacing) * 4);height:calc(var(--ui-spacing) * 4)}.ui\:\[\&\>svg\]\:shrink-0>svg{flex-shrink:0}.ui\:\[\&\>svg\]\:translate-y-0\.5>svg{--tw-translate-y:calc(var(--ui-spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:\[\&\>svg\]\:text-current>svg{color:currentColor}.ui\:\[\&\>svg\]\:text-muted-foreground>svg{color:var(--muted-foreground)}.ui\:\[\&\>svg\]\:text-sidebar-accent-foreground>svg{color:var(--sidebar-accent-foreground)}.ui\:data-\[active\=true\]\:\[\&\>svg\]\:text-primary[data-active=true]>svg{color:var(--primary)}.ui\:\[\&\>svg\:not\(\[class\*\=\'ui\:size-\'\]\)\]\:size-3\.5>svg:not([class*=ui\:size-]){width:calc(var(--ui-spacing) * 3.5);height:calc(var(--ui-spacing) * 3.5)}.ui\:\[\&\>svg\:not\(\[class\*\=\'ui\:size-\'\]\)\]\:size-4>svg:not([class*=ui\:size-]){width:calc(var(--ui-spacing) * 4);height:calc(var(--ui-spacing) * 4)}@media (hover:hover){:is(.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover,.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover>svelte-css-wrapper)>th,:is(.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover,.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover>svelte-css-wrapper) td{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){:is(.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover,.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover>svelte-css-wrapper)>th,:is(.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover,.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover>svelte-css-wrapper) td{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}}.ui\:\[\&\>tr\]\:last\:border-b-0>tr:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.ui\:\[\&\[data-state\=open\]\>svg\]\:rotate-180[data-state=open]>svg{rotate:180deg}.ui\:\[\&\[for\]\]\:cursor-pointer[for]{cursor:pointer}[data-side=left][data-collapsible=offcanvas] .ui\:\[\[data-side\=left\]\[data-collapsible\=offcanvas\]_\&\]\:-right-2{right:calc(var(--ui-spacing) * -2)}[data-side=left][data-state=collapsed] .ui\:\[\[data-side\=left\]\[data-state\=collapsed\]_\&\]\:cursor-e-resize{cursor:e-resize}[data-side=right][data-collapsible=offcanvas] .ui\:\[\[data-side\=right\]\[data-collapsible\=offcanvas\]_\&\]\:-left-2{left:calc(var(--ui-spacing) * -2)}[data-side=right][data-state=collapsed] .ui\:\[\[data-side\=right\]\[data-state\=collapsed\]_\&\]\:cursor-w-resize{cursor:w-resize}[data-variant=legend]+.ui\:\[\[data-variant\=legend\]\+\&\]\:-mt-1\.5{margin-top:calc(var(--ui-spacing) * -1.5)}@media (hover:hover){a.ui\:\[a\&\]\:hover\:bg-accent:hover{background-color:var(--accent)}a.ui\:\[a\&\]\:hover\:bg-amber-600\/90:hover{background-color:var(--ui-color-amber-600)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-amber-600\/90:hover{background-color:color-mix(in oklab, var(--ui-color-amber-600) 90%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-destructive\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab, var(--destructive) 90%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-emerald-600\/90:hover{background-color:var(--ui-color-emerald-600)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-emerald-600\/90:hover{background-color:color-mix(in oklab, var(--ui-color-emerald-600) 90%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-primary\/30:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-primary\/30:hover{background-color:color-mix(in oklab, var(--primary) 30%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--primary) 90%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-secondary\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab, var(--secondary) 80%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-secondary\/90:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-secondary\/90:hover{background-color:color-mix(in oklab, var(--secondary) 90%, transparent)}}a.ui\:\[a\&\]\:hover\:text-accent-foreground:hover{color:var(--accent-foreground)}a.ui\:\[a\&\]\:hover\:text-primary:hover{color:var(--primary)}a.ui\:\[a\&\]\:hover\:underline:hover{text-decoration-line:underline}a.ui\:dark\:\[a\&\]\:hover\:bg-accent\/50:where(.dark,.dark *):hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){a.ui\:dark\:\[a\&\]\:hover\:bg-accent\/50:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}}}@property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}@keyframes border-beam{to{offset-distance:100%}}@keyframes meteor{0%{opacity:1;transform:rotate(215deg)translate(0)}70%{opacity:1}to{opacity:0;transform:rotate(215deg)translate(-500px)}}@keyframes shimmer-marketing{0%,90%,to{background-position:calc(-100% - var(--shimmer-width)) 0}30%,60%{background-position:calc(100% + var(--shimmer-width)) 0}}@keyframes spin-around{0%{transform:translateZ(0)rotate(0)}15%,35%{transform:translateZ(0)rotate(90deg)}65%,85%{transform:translateZ(0)rotate(270deg)}to{transform:translateZ(0)rotate(360deg)}}@keyframes magicslide{to{transform:translate(calc(100cqw - 100%))}}:root{--background:oklch(100% 0 0);--foreground:oklch(14.5% 0 0);--card:oklch(100% 0 0);--card-foreground:oklch(14.5% 0 0);--popover:oklch(100% 0 0);--popover-foreground:oklch(14.5% 0 0);--primary:oklch(48.8% .243 264.376);--primary-foreground:oklch(97% .014 254.604);--secondary:oklch(96.7% .001 286.375);--secondary-foreground:oklch(21% .006 285.885);--muted:oklch(97% 0 0);--muted-foreground:oklch(55.6% 0 0);--accent:oklch(97% 0 0);--accent-foreground:oklch(20.5% 0 0);--destructive:oklch(57.7% .245 27.325);--border:oklch(92.2% 0 0);--input:oklch(92.2% 0 0);--ring:oklch(70.8% 0 0);--chart-1:oklch(80.9% .105 251.813);--chart-2:oklch(62.3% .214 259.815);--chart-3:oklch(54.6% .245 262.881);--chart-4:oklch(48.8% .243 264.376);--chart-5:oklch(42.4% .199 265.638);--radius:.625rem;--sidebar:oklch(98.5% 0 0);--sidebar-foreground:oklch(14.5% 0 0);--sidebar-primary:oklch(54.6% .245 262.881);--sidebar-primary-foreground:oklch(97% .014 254.604);--sidebar-accent:oklch(97% 0 0);--sidebar-accent-foreground:oklch(20.5% 0 0);--sidebar-border:oklch(92.2% 0 0);--sidebar-ring:oklch(70.8% 0 0)}.dark{--background:oklch(14.5% 0 0);--foreground:oklch(98.5% 0 0);--card:oklch(20.5% 0 0);--card-foreground:oklch(98.5% 0 0);--popover:oklch(20.5% 0 0);--popover-foreground:oklch(98.5% 0 0);--primary:oklch(42.4% .199 265.638);--primary-foreground:oklch(97% .014 254.604);--secondary:oklch(27.4% .006 286.033);--secondary-foreground:oklch(98.5% 0 0);--muted:oklch(26.9% 0 0);--muted-foreground:oklch(70.8% 0 0);--accent:oklch(26.9% 0 0);--accent-foreground:oklch(98.5% 0 0);--destructive:oklch(70.4% .191 22.216);--border:oklch(100% 0 0/.1);--input:oklch(100% 0 0/.15);--ring:oklch(55.6% 0 0);--chart-1:oklch(80.9% .105 251.813);--chart-2:oklch(62.3% .214 259.815);--chart-3:oklch(54.6% .245 262.881);--chart-4:oklch(48.8% .243 264.376);--chart-5:oklch(42.4% .199 265.638);--sidebar:oklch(20.5% 0 0);--sidebar-foreground:oklch(98.5% 0 0);--sidebar-primary:oklch(62.3% .214 259.815);--sidebar-primary-foreground:oklch(97% .014 254.604);--sidebar-accent:oklch(26.9% 0 0);--sidebar-accent-foreground:oklch(98.5% 0 0);--sidebar-border:oklch(100% 0 0/.1);--sidebar-ring:oklch(55.6% 0 0)}@property --border-angle{syntax:"";inherits:false;initial-value:0deg}@keyframes border{to{--border-angle:360deg}}@keyframes flip{to{transform:rotate(360deg)}}@keyframes kitrotate{to{transform:rotate(90deg)}}@keyframes shine{0%{background-position:0 0}to{background-position:-200% 0}}.animate-gradient-border{background:linear-gradient(45deg, white, white) padding-box, conic-gradient(from var(--border-angle), #94a3b84d 75%, var(--primary,#1d4ee2) 82%, var(--primary-foreground,white) 88%, var(--primary,#1d4ee2) 92%, #94a3b84d 100%) border-box;border:1px solid #0000;transition:--border-angle 3s ease-in-out}.animate-gradient-border:hover{animation:4s ease-in-out infinite border}.dark.animate-gradient-border{background:linear-gradient(45deg, #000, #000) padding-box, conic-gradient(from var(--border-angle), #4755697a 75%, var(--primary,#1d4ee2) 82%, var(--primary-foreground,black) 88%, var(--primary,#1d4ee2) 92%, #4755697a 100%) border-box}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";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-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0)scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1))rotate(var(--tw-enter-rotate,0));filter:blur(var(--tw-enter-blur,0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity,1);transform:translate3d(var(--tw-exit-translate-x,0),var(--tw-exit-translate-y,0),0)scale3d(var(--tw-exit-scale,1),var(--tw-exit-scale,1),var(--tw-exit-scale,1))rotate(var(--tw-exit-rotate,0));filter:blur(var(--tw-exit-blur,0))}}@keyframes accordion-down{0%{height:0}to{height:var(--radix-accordion-content-height,var(--bits-accordion-content-height,var(--reka-accordion-content-height,var(--kb-accordion-content-height,var(--ngp-accordion-content-height,auto)))))}}@keyframes accordion-up{0%{height:var(--radix-accordion-content-height,var(--bits-accordion-content-height,var(--reka-accordion-content-height,var(--kb-accordion-content-height,var(--ngp-accordion-content-height,auto)))))}to{height:0}} \ No newline at end of file +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:"";--tw-outline-style:solid;--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0;--border-angle:0deg}}}@layer theme{:root,:host{--ui-font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--ui-font-serif:ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;--ui-font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--ui-color-red-50:oklch(97.1% .013 17.38);--ui-color-red-500:oklch(63.7% .237 25.331);--ui-color-red-600:oklch(57.7% .245 27.325);--ui-color-red-700:oklch(50.5% .213 27.518);--ui-color-red-950:oklch(25.8% .092 26.042);--ui-color-orange-500:oklch(70.5% .213 47.604);--ui-color-amber-50:oklch(98.7% .022 95.277);--ui-color-amber-200:oklch(92.4% .12 95.746);--ui-color-amber-300:oklch(87.9% .169 91.605);--ui-color-amber-400:oklch(82.8% .189 84.429);--ui-color-amber-500:oklch(76.9% .188 70.08);--ui-color-amber-600:oklch(66.6% .179 58.318);--ui-color-amber-900:oklch(41.4% .112 45.904);--ui-color-amber-950:oklch(27.9% .077 45.635);--ui-color-yellow-500:oklch(79.5% .184 86.047);--ui-color-green-500:oklch(72.3% .219 149.579);--ui-color-green-600:oklch(62.7% .194 149.214);--ui-color-emerald-50:oklch(97.9% .021 166.113);--ui-color-emerald-300:oklch(84.5% .143 164.978);--ui-color-emerald-400:oklch(76.5% .177 163.223);--ui-color-emerald-500:oklch(69.6% .17 162.48);--ui-color-emerald-600:oklch(59.6% .145 163.225);--ui-color-emerald-700:oklch(50.8% .118 165.612);--ui-color-emerald-950:oklch(26.2% .051 172.552);--ui-color-sky-50:oklch(97.7% .013 236.62);--ui-color-sky-200:oklch(90.1% .058 230.902);--ui-color-sky-900:oklch(39.1% .09 240.876);--ui-color-sky-950:oklch(29.3% .066 243.157);--ui-color-blue-600:oklch(54.6% .245 262.881);--ui-color-violet-500:oklch(60.6% .25 292.717);--ui-color-pink-500:oklch(65.6% .241 354.308);--ui-color-rose-500:oklch(64.5% .246 16.439);--ui-color-slate-500:oklch(55.4% .046 257.417);--ui-color-slate-800:oklch(27.9% .041 260.031);--ui-color-slate-950:oklch(12.9% .042 264.695);--ui-color-gray-200:oklch(92.8% .006 264.531);--ui-color-gray-700:oklch(37.3% .034 259.733);--ui-color-zinc-100:oklch(96.7% .001 286.375);--ui-color-zinc-300:oklch(87.1% .006 286.286);--ui-color-zinc-400:oklch(70.5% .015 286.067);--ui-color-zinc-700:oklch(37% .013 285.805);--ui-color-zinc-800:oklch(27.4% .006 286.033);--ui-color-neutral-100:oklch(97% 0 0);--ui-color-neutral-400:oklch(70.8% 0 0);--ui-color-neutral-600:oklch(43.9% 0 0);--ui-color-neutral-800:oklch(26.9% 0 0);--ui-color-neutral-900:oklch(20.5% 0 0);--ui-color-black:#000;--ui-color-white:#fff;--ui-spacing:.25rem;--ui-container-xs:20rem;--ui-container-sm:24rem;--ui-container-md:28rem;--ui-container-lg:32rem;--ui-container-xl:36rem;--ui-container-2xl:42rem;--ui-container-3xl:48rem;--ui-container-4xl:56rem;--ui-container-5xl:64rem;--ui-container-7xl:80rem;--ui-text-xs:.75rem;--ui-text-xs--line-height:calc(1 / .75);--ui-text-sm:.875rem;--ui-text-sm--line-height:calc(1.25 / .875);--ui-text-base:1rem;--ui-text-base--line-height:calc(1.5 / 1);--ui-text-lg:1.125rem;--ui-text-lg--line-height:calc(1.75 / 1.125);--ui-text-xl:1.25rem;--ui-text-xl--line-height:calc(1.75 / 1.25);--ui-text-2xl:1.5rem;--ui-text-2xl--line-height:calc(2 / 1.5);--ui-text-3xl:1.875rem;--ui-text-3xl--line-height:calc(2.25 / 1.875);--ui-text-4xl:2.25rem;--ui-text-4xl--line-height:calc(2.5 / 2.25);--ui-text-5xl:3rem;--ui-text-5xl--line-height:1;--ui-text-6xl:3.75rem;--ui-text-6xl--line-height:1;--ui-text-7xl:4.5rem;--ui-text-7xl--line-height:1;--ui-font-weight-light:300;--ui-font-weight-normal:400;--ui-font-weight-medium:500;--ui-font-weight-semibold:600;--ui-font-weight-bold:700;--ui-font-weight-extrabold:800;--ui-font-weight-black:900;--ui-tracking-tighter:-.05em;--ui-tracking-tight:-.025em;--ui-tracking-wide:.025em;--ui-tracking-wider:.05em;--ui-tracking-widest:.1em;--ui-leading-tight:1.25;--ui-leading-snug:1.375;--ui-leading-normal:1.5;--ui-leading-relaxed:1.625;--ui-radius-xs:.125rem;--ui-radius-2xl:1rem;--ui-radius-3xl:1.5rem;--ui-drop-shadow-sm:0 1px 2px #00000026;--ui-ease-out:cubic-bezier(0, 0, .2, 1);--ui-ease-in-out:cubic-bezier(.4, 0, .2, 1);--ui-animate-spin:spin 1s linear infinite;--ui-animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--ui-blur-sm:8px;--ui-blur-md:12px;--ui-blur-xl:24px;--ui-blur-2xl:40px;--ui-blur-3xl:64px;--ui-aspect-video:16 / 9;--ui-default-transition-duration:.15s;--ui-default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--ui-default-mono-font-family:var(--ui-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(--font-cio,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--ui-default-font-feature-settings,normal);font-variation-settings:var(--ui-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(--ui-default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--ui-default-mono-font-feature-settings,normal);font-variation-settings:var(--ui-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}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){*{outline-color:color-mix(in oklab, var(--ring) 50%, transparent)}}body{background-color:var(--background);font-family:var(--font-sans);color:var(--foreground)}button,input,select,optgroup,textarea{font-family:var(--font-sans)}::file-selector-button{font-family:var(--font-sans)}.toaster{--normal-bg:var(--color-popover);--normal-text:var(--color-popover-foreground);--normal-border:var(--color-border)}}@layer components{.cio-marketing-border-beam{pointer-events:none;border-radius:inherit;border:calc(var(--border-width) * 1px) solid transparent;-webkit-mask-composite:source-in;-webkit-mask-source-type:auto,auto;position:absolute;inset:0;-webkit-mask-image:linear-gradient(#0000,#0000),linear-gradient(#fff,#fff);mask-image:linear-gradient(#0000,#0000),linear-gradient(#fff,#fff);-webkit-mask-position:0 0,0 0;mask-position:0 0,0 0;-webkit-mask-size:auto,auto;mask-size:auto,auto;-webkit-mask-repeat:repeat,repeat;mask-repeat:repeat,repeat;-webkit-mask-clip:padding-box,border-box;mask-clip:padding-box,border-box;-webkit-mask-origin:border-box,border-box;mask-origin:border-box,border-box;-webkit-mask-composite:source-in;mask-composite:intersect;-webkit-mask-source-type:auto,auto;mask-mode:match-source,match-source}.cio-marketing-border-beam:after{content:"";aspect-ratio:1;width:calc(var(--size) * 1px);animation-delay:var(--delay);background:linear-gradient(to left, var(--color-from), var(--color-to), transparent);offset-anchor:calc(var(--anchor) * 1%) 50%;offset-path:rect(0 auto auto 0 round calc(var(--size) * 1px));animation:border-beam calc(var(--duration) * 1s) infinite linear;position:absolute}}@layer utilities{.ui\:\@container\/field-group{container:field-group/inline-size}.ui\:\@container{container-type:inline-size}.ui\:\@container-\[size\]{container-type:size}.ui\:pointer-events-none{pointer-events:none}.ui\:sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.ui\:absolute{position:absolute}.ui\:fixed{position:fixed}.ui\:relative{position:relative}.ui\:sticky{position:sticky}.ui\:-inset-full{inset:-100%}.ui\:-inset-px{inset:-1px}.ui\:inset-\(--cut\){inset:var(--cut)}.ui\:inset-0{inset:calc(var(--ui-spacing) * 0)}.ui\:inset-x-0{inset-inline:calc(var(--ui-spacing) * 0)}.ui\:inset-x-\[-10\%\]{inset-inline:-10%}.ui\:inset-y-0{inset-block:calc(var(--ui-spacing) * 0)}.ui\:start-0{inset-inline-start:calc(var(--ui-spacing) * 0)}.ui\:end-4{inset-inline-end:calc(var(--ui-spacing) * 4)}.ui\:-top-2{top:calc(var(--ui-spacing) * -2)}.ui\:-top-3{top:calc(var(--ui-spacing) * -3)}.ui\:-top-16{top:calc(var(--ui-spacing) * -16)}.ui\:-top-20{top:calc(var(--ui-spacing) * -20)}.ui\:-top-32{top:calc(var(--ui-spacing) * -32)}.ui\:top-0{top:calc(var(--ui-spacing) * 0)}.ui\:top-1\.5{top:calc(var(--ui-spacing) * 1.5)}.ui\:top-1\/2{top:50%}.ui\:top-2{top:calc(var(--ui-spacing) * 2)}.ui\:top-3{top:calc(var(--ui-spacing) * 3)}.ui\:top-3\.5{top:calc(var(--ui-spacing) * 3.5)}.ui\:top-4{top:calc(var(--ui-spacing) * 4)}.ui\:top-11{top:calc(var(--ui-spacing) * 11)}.ui\:top-12{top:calc(var(--ui-spacing) * 12)}.ui\:top-\[-12px\]{top:-12px}.ui\:top-\[6px\]{top:6px}.ui\:top-\[50\%\]{top:50%}.ui\:top-\[60\%\]{top:60%}.ui\:top-full{top:100%}.ui\:top-px{top:1px}.ui\:-right-4{right:calc(var(--ui-spacing) * -4)}.ui\:right-0{right:calc(var(--ui-spacing) * 0)}.ui\:right-1{right:calc(var(--ui-spacing) * 1)}.ui\:right-2{right:calc(var(--ui-spacing) * 2)}.ui\:right-3{right:calc(var(--ui-spacing) * 3)}.ui\:right-3\.5{right:calc(var(--ui-spacing) * 3.5)}.ui\:right-4{right:calc(var(--ui-spacing) * 4)}.ui\:right-9{right:calc(var(--ui-spacing) * 9)}.ui\:right-\[-10\%\]{right:-10%}.ui\:right-\[-12px\]{right:-12px}.ui\:-bottom-px{bottom:-1px}.ui\:bottom-0{bottom:calc(var(--ui-spacing) * 0)}.ui\:bottom-2{bottom:calc(var(--ui-spacing) * 2)}.ui\:bottom-3{bottom:calc(var(--ui-spacing) * 3)}.ui\:bottom-3\.5{bottom:calc(var(--ui-spacing) * 3.5)}.ui\:bottom-4{bottom:calc(var(--ui-spacing) * 4)}.ui\:bottom-\[-50\%\]{bottom:-50%}.ui\:bottom-\[-220px\]{bottom:-220px}.ui\:bottom-full{bottom:100%}.ui\:-left-24{left:calc(var(--ui-spacing) * -24)}.ui\:left-0{left:calc(var(--ui-spacing) * 0)}.ui\:left-1\/2{left:50%}.ui\:left-2{left:calc(var(--ui-spacing) * 2)}.ui\:left-3{left:calc(var(--ui-spacing) * 3)}.ui\:left-3\.5{left:calc(var(--ui-spacing) * 3.5)}.ui\:left-\[50\%\]{left:50%}.ui\:left-\[calc\(50\%-3rem\)\]{left:calc(50% - 3rem)}.ui\:left-auto{left:auto}.ui\:left-full{left:100%}.ui\:isolate{isolation:isolate}.ui\:-z-10{z-index:calc(10 * -1)}.ui\:-z-20{z-index:calc(20 * -1)}.ui\:-z-30{z-index:calc(30 * -1)}.ui\:z-0{z-index:0}.ui\:z-1{z-index:1}.ui\:z-10{z-index:10}.ui\:z-20{z-index:20}.ui\:z-30{z-index:30}.ui\:z-40{z-index:40}.ui\:z-50{z-index:50}.ui\:z-100{z-index:100}.ui\:z-200{z-index:200}.ui\:z-999{z-index:999}.ui\:z-\[1\]{z-index:1}.ui\:z-\[110\]{z-index:110}.ui\:order-first{order:-9999}.ui\:order-last{order:9999}.ui\:col-start-2{grid-column-start:2}.ui\:row-span-2{grid-row:span 2/span 2}.ui\:row-start-1{grid-row-start:1}.ui\:m-0{margin:calc(var(--ui-spacing) * 0)}.ui\:m-0\!{margin:calc(var(--ui-spacing) * 0)!important}.ui\:-mx-1{margin-inline:calc(var(--ui-spacing) * -1)}.ui\:-mx-6{margin-inline:calc(var(--ui-spacing) * -6)}.ui\:-mx-\[2\.5px\]{margin-inline:-2.5px}.ui\:-mx-\[2px\]{margin-inline:-2px}.ui\:mx-0\.5{margin-inline:calc(var(--ui-spacing) * .5)}.ui\:mx-2{margin-inline:calc(var(--ui-spacing) * 2)}.ui\:mx-4{margin-inline:calc(var(--ui-spacing) * 4)}.ui\:mx-5{margin-inline:calc(var(--ui-spacing) * 5)}.ui\:mx-auto{margin-inline:auto}.ui\:my-0{margin-block:calc(var(--ui-spacing) * 0)}.ui\:my-0\.5{margin-block:calc(var(--ui-spacing) * .5)}.ui\:my-1{margin-block:calc(var(--ui-spacing) * 1)}.ui\:my-2{margin-block:calc(var(--ui-spacing) * 2)}.ui\:my-3{margin-block:calc(var(--ui-spacing) * 3)}.ui\:my-4{margin-block:calc(var(--ui-spacing) * 4)}.ui\:my-10{margin-block:calc(var(--ui-spacing) * 10)}.ui\:ms-1{margin-inline-start:calc(var(--ui-spacing) * 1)}.ui\:ms-4{margin-inline-start:calc(var(--ui-spacing) * 4)}.ui\:-mt-1{margin-top:calc(var(--ui-spacing) * -1)}.ui\:mt-0\.5{margin-top:calc(var(--ui-spacing) * .5)}.ui\:mt-1{margin-top:calc(var(--ui-spacing) * 1)}.ui\:mt-1\.5{margin-top:calc(var(--ui-spacing) * 1.5)}.ui\:mt-2{margin-top:calc(var(--ui-spacing) * 2)}.ui\:mt-2\.5{margin-top:calc(var(--ui-spacing) * 2.5)}.ui\:mt-3{margin-top:calc(var(--ui-spacing) * 3)}.ui\:mt-4{margin-top:calc(var(--ui-spacing) * 4)}.ui\:mt-6{margin-top:calc(var(--ui-spacing) * 6)}.ui\:mt-7{margin-top:calc(var(--ui-spacing) * 7)}.ui\:mt-8{margin-top:calc(var(--ui-spacing) * 8)}.ui\:mt-9{margin-top:calc(var(--ui-spacing) * 9)}.ui\:mt-10{margin-top:calc(var(--ui-spacing) * 10)}.ui\:mt-12{margin-top:calc(var(--ui-spacing) * 12)}.ui\:mt-14{margin-top:calc(var(--ui-spacing) * 14)}.ui\:mt-16{margin-top:calc(var(--ui-spacing) * 16)}.ui\:mt-auto{margin-top:auto}.ui\:mr-1{margin-right:calc(var(--ui-spacing) * 1)}.ui\:mr-2{margin-right:calc(var(--ui-spacing) * 2)}.ui\:-mb-6{margin-bottom:calc(var(--ui-spacing) * -6)}.ui\:mb-1{margin-bottom:calc(var(--ui-spacing) * 1)}.ui\:mb-1\.5{margin-bottom:calc(var(--ui-spacing) * 1.5)}.ui\:mb-2{margin-bottom:calc(var(--ui-spacing) * 2)}.ui\:mb-2\.5{margin-bottom:calc(var(--ui-spacing) * 2.5)}.ui\:mb-3{margin-bottom:calc(var(--ui-spacing) * 3)}.ui\:mb-4{margin-bottom:calc(var(--ui-spacing) * 4)}.ui\:mb-5{margin-bottom:calc(var(--ui-spacing) * 5)}.ui\:mb-6{margin-bottom:calc(var(--ui-spacing) * 6)}.ui\:mb-7{margin-bottom:calc(var(--ui-spacing) * 7)}.ui\:mb-8{margin-bottom:calc(var(--ui-spacing) * 8)}.ui\:mb-9{margin-bottom:calc(var(--ui-spacing) * 9)}.ui\:mb-10{margin-bottom:calc(var(--ui-spacing) * 10)}.ui\:mb-12{margin-bottom:calc(var(--ui-spacing) * 12)}.ui\:mb-14{margin-bottom:calc(var(--ui-spacing) * 14)}.ui\:mb-16{margin-bottom:calc(var(--ui-spacing) * 16)}.ui\:ml-1{margin-left:calc(var(--ui-spacing) * 1)}.ui\:ml-2{margin-left:calc(var(--ui-spacing) * 2)}.ui\:ml-2\.5{margin-left:calc(var(--ui-spacing) * 2.5)}.ui\:ml-auto{margin-left:auto}.ui\:box-border{box-sizing:border-box}.ui\:line-clamp-1{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.ui\:line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.ui\:line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.ui\:block{display:block}.ui\:flex{display:flex}.ui\:grid{display:grid}.ui\:hidden{display:none}.ui\:inline-block{display:inline-block}.ui\:inline-flex{display:inline-flex}.ui\:field-sizing-content{field-sizing:content}.ui\:aspect-\[1\],.ui\:aspect-square{aspect-ratio:1}.ui\:aspect-video{aspect-ratio:var(--ui-aspect-video)}.ui\:\!size-6{width:calc(var(--ui-spacing) * 6)!important;height:calc(var(--ui-spacing) * 6)!important}.ui\:size-1{width:calc(var(--ui-spacing) * 1);height:calc(var(--ui-spacing) * 1)}.ui\:size-1\.5{width:calc(var(--ui-spacing) * 1.5);height:calc(var(--ui-spacing) * 1.5)}.ui\:size-2{width:calc(var(--ui-spacing) * 2);height:calc(var(--ui-spacing) * 2)}.ui\:size-2\.5{width:calc(var(--ui-spacing) * 2.5);height:calc(var(--ui-spacing) * 2.5)}.ui\:size-3{width:calc(var(--ui-spacing) * 3);height:calc(var(--ui-spacing) * 3)}.ui\:size-3\.5{width:calc(var(--ui-spacing) * 3.5);height:calc(var(--ui-spacing) * 3.5)}.ui\:size-4{width:calc(var(--ui-spacing) * 4);height:calc(var(--ui-spacing) * 4)}.ui\:size-5{width:calc(var(--ui-spacing) * 5);height:calc(var(--ui-spacing) * 5)}.ui\:size-6{width:calc(var(--ui-spacing) * 6);height:calc(var(--ui-spacing) * 6)}.ui\:size-7{width:calc(var(--ui-spacing) * 7);height:calc(var(--ui-spacing) * 7)}.ui\:size-8{width:calc(var(--ui-spacing) * 8);height:calc(var(--ui-spacing) * 8)}.ui\:size-9{width:calc(var(--ui-spacing) * 9);height:calc(var(--ui-spacing) * 9)}.ui\:size-10{width:calc(var(--ui-spacing) * 10);height:calc(var(--ui-spacing) * 10)}.ui\:size-11{width:calc(var(--ui-spacing) * 11);height:calc(var(--ui-spacing) * 11)}.ui\:size-12{width:calc(var(--ui-spacing) * 12);height:calc(var(--ui-spacing) * 12)}.ui\:size-14{width:calc(var(--ui-spacing) * 14);height:calc(var(--ui-spacing) * 14)}.ui\:size-14\!{width:calc(var(--ui-spacing) * 14)!important;height:calc(var(--ui-spacing) * 14)!important}.ui\:size-16{width:calc(var(--ui-spacing) * 16);height:calc(var(--ui-spacing) * 16)}.ui\:size-20{width:calc(var(--ui-spacing) * 20);height:calc(var(--ui-spacing) * 20)}.ui\:size-24{width:calc(var(--ui-spacing) * 24);height:calc(var(--ui-spacing) * 24)}.ui\:size-28{width:calc(var(--ui-spacing) * 28);height:calc(var(--ui-spacing) * 28)}.ui\:size-32{width:calc(var(--ui-spacing) * 32);height:calc(var(--ui-spacing) * 32)}.ui\:size-\[2\.4px\]{width:2.4px;height:2.4px}.ui\:size-\[11px\]{width:11px;height:11px}.ui\:size-\[22px\]{width:22px;height:22px}.ui\:size-\[640px\]{width:640px;height:640px}.ui\:size-\[800px\]{width:800px;height:800px}.ui\:size-fit{width:fit-content;height:fit-content}.ui\:size-full{width:100%;height:100%}.ui\:h-\(--bits-navigation-menu-viewport-height\){height:var(--bits-navigation-menu-viewport-height)}.ui\:h-\(--bits-select-anchor-height\){height:var(--bits-select-anchor-height)}.ui\:h-0{height:calc(var(--ui-spacing) * 0)}.ui\:h-0\.5{height:calc(var(--ui-spacing) * .5)}.ui\:h-0\.5\!{height:calc(var(--ui-spacing) * .5)!important}.ui\:h-1{height:calc(var(--ui-spacing) * 1)}.ui\:h-1\.5{height:calc(var(--ui-spacing) * 1.5)}.ui\:h-2{height:calc(var(--ui-spacing) * 2)}.ui\:h-2\.5{height:calc(var(--ui-spacing) * 2.5)}.ui\:h-3{height:calc(var(--ui-spacing) * 3)}.ui\:h-4{height:calc(var(--ui-spacing) * 4)}.ui\:h-5{height:calc(var(--ui-spacing) * 5)}.ui\:h-6{height:calc(var(--ui-spacing) * 6)}.ui\:h-7{height:calc(var(--ui-spacing) * 7)}.ui\:h-8{height:calc(var(--ui-spacing) * 8)}.ui\:h-9{height:calc(var(--ui-spacing) * 9)}.ui\:h-10{height:calc(var(--ui-spacing) * 10)}.ui\:h-12{height:calc(var(--ui-spacing) * 12)}.ui\:h-14{height:calc(var(--ui-spacing) * 14)}.ui\:h-16{height:calc(var(--ui-spacing) * 16)}.ui\:h-20{height:calc(var(--ui-spacing) * 20)}.ui\:h-24{height:calc(var(--ui-spacing) * 24)}.ui\:h-28{height:calc(var(--ui-spacing) * 28)}.ui\:h-40{height:calc(var(--ui-spacing) * 40)}.ui\:h-48{height:calc(var(--ui-spacing) * 48)}.ui\:h-50\!{height:calc(var(--ui-spacing) * 50)!important}.ui\:h-96{height:calc(var(--ui-spacing) * 96)}.ui\:h-128{height:calc(var(--ui-spacing) * 128)}.ui\:h-\[1\.2rem\]{height:1.2rem}.ui\:h-\[1\.15rem\]{height:1.15rem}.ui\:h-\[6px\]{height:6px}.ui\:h-\[10px\]{height:10px}.ui\:h-\[14px\]{height:14px}.ui\:h-\[22px\]{height:22px}.ui\:h-\[70px\]{height:70px}.ui\:h-\[72px\]{height:72px}.ui\:h-\[100cqh\]{height:100cqh}.ui\:h-\[168px\]{height:168px}.ui\:h-\[180px\]{height:180px}.ui\:h-\[200px\]{height:200px}.ui\:h-\[280px\]{height:280px}.ui\:h-\[380px\]{height:380px}.ui\:h-\[420px\]{height:420px}.ui\:h-\[440px\]{height:440px}.ui\:h-\[460px\]{height:460px}.ui\:h-\[500px\]{height:500px}.ui\:h-\[520px\]{height:520px}.ui\:h-\[680px\]{height:680px}.ui\:h-\[calc\(100\%-1px\)\]{height:calc(100% - 1px)}.ui\:h-\[calc\(100\%-3px\)\]{height:calc(100% - 3px)}.ui\:h-\[calc\(100dvh-3rem\)\]{height:calc(100dvh - 3rem)}.ui\:h-auto{height:auto}.ui\:h-fit{height:fit-content}.ui\:h-fit\!{height:fit-content!important}.ui\:h-full{height:100%}.ui\:h-px{height:1px}.ui\:h-screen{height:100vh}.ui\:max-h-\(--bits-dropdown-menu-content-available-height\){max-height:var(--bits-dropdown-menu-content-available-height)}.ui\:max-h-\(--bits-select-content-available-height\){max-height:var(--bits-select-content-available-height)}.ui\:max-h-32{max-height:calc(var(--ui-spacing) * 32)}.ui\:max-h-52{max-height:calc(var(--ui-spacing) * 52)}.ui\:max-h-60{max-height:calc(var(--ui-spacing) * 60)}.ui\:max-h-64{max-height:calc(var(--ui-spacing) * 64)}.ui\:max-h-72{max-height:calc(var(--ui-spacing) * 72)}.ui\:max-h-80{max-height:calc(var(--ui-spacing) * 80)}.ui\:max-h-90{max-height:calc(var(--ui-spacing) * 90)}.ui\:max-h-96{max-height:calc(var(--ui-spacing) * 96)}.ui\:max-h-\[85vh\]{max-height:85vh}.ui\:max-h-\[300px\]{max-height:300px}.ui\:max-h-svh{max-height:100svh}.ui\:min-h-0{min-height:calc(var(--ui-spacing) * 0)}.ui\:min-h-4{min-height:calc(var(--ui-spacing) * 4)}.ui\:min-h-8{min-height:calc(var(--ui-spacing) * 8)}.ui\:min-h-14{min-height:calc(var(--ui-spacing) * 14)}.ui\:min-h-16{min-height:calc(var(--ui-spacing) * 16)}.ui\:min-h-40{min-height:calc(var(--ui-spacing) * 40)}.ui\:min-h-96{min-height:calc(var(--ui-spacing) * 96)}.ui\:min-h-\[32rem\]{min-height:32rem}.ui\:min-h-\[44px\]{min-height:44px}.ui\:min-h-\[63px\]{min-height:63px}.ui\:min-h-\[240px\]{min-height:240px}.ui\:min-h-\[320px\]{min-height:320px}.ui\:min-h-\[calc\(100dvh-3rem\)\]{min-height:calc(100dvh - 3rem)}.ui\:min-h-\[calc\(100vh-48px\)\]{min-height:calc(100vh - 48px)}.ui\:min-h-dvh{min-height:100dvh}.ui\:min-h-screen{min-height:100vh}.ui\:w-\(--sidebar-width\){width:var(--sidebar-width)}.ui\:w-0{width:calc(var(--ui-spacing) * 0)}.ui\:w-1{width:calc(var(--ui-spacing) * 1)}.ui\:w-1\.5{width:calc(var(--ui-spacing) * 1.5)}.ui\:w-1\/4{width:25%}.ui\:w-2{width:calc(var(--ui-spacing) * 2)}.ui\:w-2\.5{width:calc(var(--ui-spacing) * 2.5)}.ui\:w-2\/4{width:50%}.ui\:w-3\/4{width:75%}.ui\:w-4{width:calc(var(--ui-spacing) * 4)}.ui\:w-5{width:calc(var(--ui-spacing) * 5)}.ui\:w-6{width:calc(var(--ui-spacing) * 6)}.ui\:w-7{width:calc(var(--ui-spacing) * 7)}.ui\:w-8{width:calc(var(--ui-spacing) * 8)}.ui\:w-10{width:calc(var(--ui-spacing) * 10)}.ui\:w-14{width:calc(var(--ui-spacing) * 14)}.ui\:w-16{width:calc(var(--ui-spacing) * 16)}.ui\:w-20{width:calc(var(--ui-spacing) * 20)}.ui\:w-24{width:calc(var(--ui-spacing) * 24)}.ui\:w-28{width:calc(var(--ui-spacing) * 28)}.ui\:w-40{width:calc(var(--ui-spacing) * 40)}.ui\:w-48{width:calc(var(--ui-spacing) * 48)}.ui\:w-52{width:calc(var(--ui-spacing) * 52)}.ui\:w-64{width:calc(var(--ui-spacing) * 64)}.ui\:w-72{width:calc(var(--ui-spacing) * 72)}.ui\:w-88{width:calc(var(--ui-spacing) * 88)}.ui\:w-96{width:calc(var(--ui-spacing) * 96)}.ui\:w-\[1\.2rem\]{width:1.2rem}.ui\:w-\[10px\]{width:10px}.ui\:w-\[25px\]{width:25px}.ui\:w-\[50px\]{width:50px}.ui\:w-\[80\%\]{width:80%}.ui\:w-\[84\%\]{width:84%}.ui\:w-\[100px\]{width:100px}.ui\:w-\[260px\]{width:260px}.ui\:w-\[420px\]{width:420px}.ui\:w-\[520px\]{width:520px}.ui\:w-auto{width:auto}.ui\:w-fit{width:fit-content}.ui\:w-fit\!{width:fit-content!important}.ui\:w-full{width:100%}.ui\:w-full\!{width:100%!important}.ui\:w-max{width:max-content}.ui\:w-px{width:1px}.ui\:w-screen{width:100vw}.ui\:max-w-\(--skeleton-width\){max-width:var(--skeleton-width)}.ui\:max-w-2xl{max-width:var(--ui-container-2xl)}.ui\:max-w-3xl{max-width:var(--ui-container-3xl)}.ui\:max-w-4xl{max-width:var(--ui-container-4xl)}.ui\:max-w-5xl{max-width:var(--ui-container-5xl)}.ui\:max-w-6{max-width:calc(var(--ui-spacing) * 6)}.ui\:max-w-7xl{max-width:var(--ui-container-7xl)}.ui\:max-w-40{max-width:calc(var(--ui-spacing) * 40)}.ui\:max-w-80{max-width:calc(var(--ui-spacing) * 80)}.ui\:max-w-\[16rem\]{max-width:16rem}.ui\:max-w-\[18ch\]{max-width:18ch}.ui\:max-w-\[20ch\]{max-width:20ch}.ui\:max-w-\[55vw\]{max-width:55vw}.ui\:max-w-\[60\%\]{max-width:60%}.ui\:max-w-\[200px\]{max-width:200px}.ui\:max-w-\[240px\]{max-width:240px}.ui\:max-w-\[260px\]{max-width:260px}.ui\:max-w-\[280px\]{max-width:280px}.ui\:max-w-\[300px\]{max-width:300px}.ui\:max-w-\[320px\]{max-width:320px}.ui\:max-w-\[480px\]{max-width:480px}.ui\:max-w-\[520px\]{max-width:520px}.ui\:max-w-\[600px\]{max-width:600px}.ui\:max-w-\[640px\]{max-width:640px}.ui\:max-w-\[700px\]{max-width:700px}.ui\:max-w-\[820px\]{max-width:820px}.ui\:max-w-\[880px\]{max-width:880px}.ui\:max-w-\[1080px\]{max-width:1080px}.ui\:max-w-\[1100px\]{max-width:1100px}.ui\:max-w-\[1120px\]{max-width:1120px}.ui\:max-w-\[1180px\]{max-width:1180px}.ui\:max-w-\[1200px\]{max-width:1200px}.ui\:max-w-\[1240px\]{max-width:1240px}.ui\:max-w-\[1280px\]{max-width:1280px}.ui\:max-w-\[1320px\]{max-width:1320px}.ui\:max-w-\[calc\(100\%-2rem\)\]{max-width:calc(100% - 2rem)}.ui\:max-w-full{max-width:100%}.ui\:max-w-max{max-width:max-content}.ui\:max-w-md{max-width:var(--ui-container-md)}.ui\:max-w-none{max-width:none}.ui\:max-w-sm{max-width:var(--ui-container-sm)}.ui\:max-w-xl{max-width:var(--ui-container-xl)}.ui\:max-w-xs{max-width:var(--ui-container-xs)}.ui\:min-w-\(--bits-select-anchor-width\){min-width:var(--bits-select-anchor-width)}.ui\:min-w-0{min-width:calc(var(--ui-spacing) * 0)}.ui\:min-w-5{min-width:calc(var(--ui-spacing) * 5)}.ui\:min-w-7{min-width:calc(var(--ui-spacing) * 7)}.ui\:min-w-8{min-width:calc(var(--ui-spacing) * 8)}.ui\:min-w-9{min-width:calc(var(--ui-spacing) * 9)}.ui\:min-w-10{min-width:calc(var(--ui-spacing) * 10)}.ui\:min-w-18{min-width:calc(var(--ui-spacing) * 18)}.ui\:min-w-32{min-width:calc(var(--ui-spacing) * 32)}.ui\:min-w-48{min-width:calc(var(--ui-spacing) * 48)}.ui\:min-w-\[3ch\]{min-width:3ch}.ui\:min-w-\[5rem\]{min-width:5rem}.ui\:min-w-\[9rem\]{min-width:9rem}.ui\:min-w-\[min\(24rem\,calc\(100vw-5rem\)\)\]{min-width:min(24rem,100vw - 5rem)}.ui\:min-w-full{min-width:100%}.ui\:flex-1{flex:1}.ui\:flex-shrink-0{flex-shrink:0}.ui\:shrink{flex-shrink:1}.ui\:shrink-0{flex-shrink:0}.ui\:basis-full{flex-basis:100%}.ui\:origin-\(--bits-dropdown-menu-content-transform-origin\){transform-origin:var(--bits-dropdown-menu-content-transform-origin)}.ui\:origin-\(--bits-menubar-content-transform-origin\){transform-origin:var(--bits-menubar-content-transform-origin)}.ui\:origin-\(--bits-popover-content-transform-origin\){transform-origin:var(--bits-popover-content-transform-origin)}.ui\:origin-\(--bits-select-content-transform-origin\){transform-origin:var(--bits-select-content-transform-origin)}.ui\:origin-\(--bits-tooltip-content-transform-origin\){transform-origin:var(--bits-tooltip-content-transform-origin)}.ui\:origin-center{transform-origin:50%}.ui\:-translate-x-0{--tw-translate-x:calc(var(--ui-spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:-translate-x-full{--tw-translate-x:-100%;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:-translate-x-px{--tw-translate-x:-1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-x-3{--tw-translate-x:calc(var(--ui-spacing) * 3);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-x-4{--tw-translate-x:calc(var(--ui-spacing) * 4);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-x-\[-50\%\]{--tw-translate-x:-50%;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-x-px{--tw-translate-x:1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:-translate-y-full{--tw-translate-y:-100%;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-y-0\.5{--tw-translate-y:calc(var(--ui-spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-y-3{--tw-translate-y:calc(var(--ui-spacing) * 3);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-y-4{--tw-translate-y:calc(var(--ui-spacing) * 4);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:translate-y-\[-50\%\]{--tw-translate-y:-50%;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:\[translate\:0_0\]{translate:0}.ui\:scale-0{--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x) var(--tw-scale-y)}.ui\:scale-100{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}.ui\:-rotate-90{rotate:-90deg}.ui\:rotate-0{rotate:none}.ui\:rotate-5{rotate:5deg}.ui\:rotate-45{rotate:45deg}.ui\:rotate-90{rotate:90deg}.ui\:\[transform\:scaleX\(-1\)\]{transform:scaleX(-1)}.ui\:transform-gpu{transform:translateZ(0) var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.ui\:animate-in{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:animate-magicslide{animation:magicslide var(--speed) ease-in-out infinite alternate}.ui\:animate-meteor{animation:5s linear infinite meteor}.ui\:animate-pulse{animation:var(--ui-animate-pulse)}.ui\:animate-shine{animation:2s linear infinite shine}.ui\:animate-spin{animation:var(--ui-animate-spin)}.ui\:animate-spin-around{animation:spin-around calc(var(--speed) * 2) infinite linear}.ui\:cursor-auto{cursor:auto}.ui\:cursor-col-resize{cursor:col-resize}.ui\:cursor-default{cursor:default}.ui\:cursor-default\!{cursor:default!important}.ui\:cursor-grab{cursor:grab}.ui\:cursor-not-allowed{cursor:not-allowed}.ui\:cursor-pointer{cursor:pointer}.ui\:cursor-text{cursor:text}.ui\:resize-none{resize:none}.ui\:scroll-my-1{scroll-margin-block:calc(var(--ui-spacing) * 1)}.ui\:scroll-py-1{scroll-padding-block:calc(var(--ui-spacing) * 1)}.ui\:list-disc{list-style-type:disc}.ui\:list-none{list-style-type:none}.ui\:auto-rows-min{grid-auto-rows:min-content}.ui\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ui\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ui\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.ui\:grid-cols-\[0_1fr\]{grid-template-columns:0 1fr}.ui\:grid-cols-\[1fr_auto_1fr\]{grid-template-columns:1fr auto 1fr}.ui\:grid-cols-\[6px_6px\]{grid-template-columns:6px 6px}.ui\:grid-rows-\[auto_auto\]{grid-template-rows:auto auto}.ui\:flex-col{flex-direction:column}.ui\:flex-col-reverse{flex-direction:column-reverse}.ui\:flex-row{flex-direction:row}.ui\:flex-nowrap\!{flex-wrap:nowrap!important}.ui\:flex-wrap{flex-wrap:wrap}.ui\:place-content-between{place-content:space-between}.ui\:place-content-center{place-content:center}.ui\:place-items-center{place-items:center}.ui\:items-baseline{align-items:baseline}.ui\:items-center{align-items:center}.ui\:items-end{align-items:flex-end}.ui\:items-start{align-items:flex-start}.ui\:items-stretch{align-items:stretch}.ui\:justify-around{justify-content:space-around}.ui\:justify-between{justify-content:space-between}.ui\:justify-center{justify-content:center}.ui\:justify-end{justify-content:flex-end}.ui\:justify-start{justify-content:flex-start}.ui\:justify-start\!{justify-content:flex-start!important}.ui\:justify-items-center{justify-items:center}.ui\:justify-items-start{justify-items:start}.ui\:gap-0{gap:calc(var(--ui-spacing) * 0)}.ui\:gap-0\.5{gap:calc(var(--ui-spacing) * .5)}.ui\:gap-1{gap:calc(var(--ui-spacing) * 1)}.ui\:gap-1\.5{gap:calc(var(--ui-spacing) * 1.5)}.ui\:gap-2{gap:calc(var(--ui-spacing) * 2)}.ui\:gap-2\.5{gap:calc(var(--ui-spacing) * 2.5)}.ui\:gap-3{gap:calc(var(--ui-spacing) * 3)}.ui\:gap-4{gap:calc(var(--ui-spacing) * 4)}.ui\:gap-5{gap:calc(var(--ui-spacing) * 5)}.ui\:gap-6{gap:calc(var(--ui-spacing) * 6)}.ui\:gap-7{gap:calc(var(--ui-spacing) * 7)}.ui\:gap-8{gap:calc(var(--ui-spacing) * 8)}.ui\:gap-10{gap:calc(var(--ui-spacing) * 10)}.ui\:gap-12{gap:calc(var(--ui-spacing) * 12)}.ui\:gap-16{gap:calc(var(--ui-spacing) * 16)}.ui\:gap-20{gap:calc(var(--ui-spacing) * 20)}.ui\:gap-\[1px\]{gap:1px}.ui\:gap-\[14px\]{gap:14px}.ui\:gap-px{gap:1px}:where(.ui\:space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.ui\:space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.ui\:space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.ui\:space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.ui\:space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.ui\:space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--ui-spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--ui-spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.ui\:gap-x-3{column-gap:calc(var(--ui-spacing) * 3)}.ui\:gap-x-4{column-gap:calc(var(--ui-spacing) * 4)}.ui\:gap-x-5{column-gap:calc(var(--ui-spacing) * 5)}.ui\:gap-x-6{column-gap:calc(var(--ui-spacing) * 6)}.ui\:gap-x-8{column-gap:calc(var(--ui-spacing) * 8)}:where(.ui\:space-x-1>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--ui-spacing) * 1) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--ui-spacing) * 1) * calc(1 - var(--tw-space-x-reverse)))}:where(.ui\:space-x-8>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--ui-spacing) * 8) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--ui-spacing) * 8) * calc(1 - var(--tw-space-x-reverse)))}.ui\:gap-y-0\.5{row-gap:calc(var(--ui-spacing) * .5)}.ui\:gap-y-1{row-gap:calc(var(--ui-spacing) * 1)}.ui\:gap-y-2{row-gap:calc(var(--ui-spacing) * 2)}.ui\:gap-y-10{row-gap:calc(var(--ui-spacing) * 10)}.ui\:gap-y-12{row-gap:calc(var(--ui-spacing) * 12)}.ui\:place-self-end{place-self:end}.ui\:self-center{align-self:center}.ui\:self-start{align-self:flex-start}.ui\:self-stretch{align-self:stretch}.ui\:justify-self-center{justify-self:center}.ui\:justify-self-end{justify-self:flex-end}.ui\:truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ui\:overflow-auto{overflow:auto}.ui\:overflow-hidden{overflow:hidden}.ui\:overflow-visible{overflow:visible}.ui\:overflow-x-auto{overflow-x:auto}.ui\:overflow-x-hidden{overflow-x:hidden}.ui\:overflow-y-auto{overflow-y:auto}.ui\:overflow-y-hidden{overflow-y:hidden}.ui\:scroll-smooth{scroll-behavior:smooth}.ui\:\[border-radius\:9999px\]{border-radius:9999px}.ui\:\[border-radius\:var\(--landing-radius-card\)\]{border-radius:var(--landing-radius-card)}.ui\:\[border-radius\:var\(--landing-radius-pill\)\]{border-radius:var(--landing-radius-pill)}.ui\:rounded{border-radius:.25rem}.ui\:rounded-\(--radius\){border-radius:var(--radius)}.ui\:rounded-2xl{border-radius:var(--ui-radius-2xl)}.ui\:rounded-3xl{border-radius:var(--ui-radius-3xl)}.ui\:rounded-\[2px\]{border-radius:2px}.ui\:rounded-\[3px\]{border-radius:3px}.ui\:rounded-\[4px\]{border-radius:4px}.ui\:rounded-\[10px\]{border-radius:10px}.ui\:rounded-\[14px\]{border-radius:14px}.ui\:rounded-\[20px\]{border-radius:20px}.ui\:rounded-\[calc\(var\(--radius\)-5px\)\]{border-radius:calc(var(--radius) - 5px)}.ui\:rounded-full{border-radius:3.40282e38px}.ui\:rounded-lg{border-radius:var(--radius)}.ui\:rounded-md{border-radius:calc(var(--radius) - 2px)}.ui\:rounded-md\!{border-radius:calc(var(--radius) - 2px)!important}.ui\:rounded-none{border-radius:0}.ui\:rounded-sm{border-radius:calc(var(--radius) - 4px)}.ui\:rounded-xl{border-radius:calc(var(--radius) + 4px)}.ui\:rounded-xs{border-radius:var(--ui-radius-xs)}.ui\:rounded-t-md{border-top-left-radius:calc(var(--radius) - 2px);border-top-right-radius:calc(var(--radius) - 2px)}.ui\:rounded-t-xl{border-top-left-radius:calc(var(--radius) + 4px);border-top-right-radius:calc(var(--radius) + 4px)}.ui\:border{border-style:var(--tw-border-style);border-width:1px}.ui\:border-0{border-style:var(--tw-border-style);border-width:0}.ui\:border-0\!{border-style:var(--tw-border-style)!important;border-width:0!important}.ui\:border-2{border-style:var(--tw-border-style);border-width:2px}.ui\:border-\[1\.5px\]{border-style:var(--tw-border-style);border-width:1.5px}.ui\:border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.ui\:border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}.ui\:border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.ui\:border-y-\[10px\]{border-block-style:var(--tw-border-style);border-block-width:10px}.ui\:border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.ui\:border-t-2{border-top-style:var(--tw-border-style);border-top-width:2px}.ui\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.ui\:border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.ui\:border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.ui\:border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.ui\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.ui\:border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.ui\:border-l-\[16px\]{border-left-style:var(--tw-border-style);border-left-width:16px}.ui\:border-dashed{--tw-border-style:dashed;border-style:dashed}.ui\:border-none{--tw-border-style:none;border-style:none}.ui\:border-solid{--tw-border-style:solid;border-style:solid}.ui\:border-\(--color-border\){border-color:var(--color-border)}.ui\:border-\[\#1c1f28\]{border-color:#1c1f28}.ui\:border-\[\#262a35\]{border-color:#262a35}.ui\:border-\[\#d9d8d0\]{border-color:#d9d8d0}.ui\:border-\[var\(--landing-accent\)\]{border-color:var(--landing-accent)}.ui\:border-\[var\(--landing-accent-fg\)\],.ui\:border-\[var\(--landing-accent-fg\)\]\/15{border-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-accent-fg\)\]\/15{border-color:color-mix(in oklab, var(--landing-accent-fg) 15%, transparent)}}.ui\:border-\[var\(--landing-accent-fg\)\]\/20{border-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-accent-fg\)\]\/20{border-color:color-mix(in oklab, var(--landing-accent-fg) 20%, transparent)}}.ui\:border-\[var\(--landing-bg\)\]\/15{border-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-bg\)\]\/15{border-color:color-mix(in oklab, var(--landing-bg) 15%, transparent)}}.ui\:border-\[var\(--landing-bg\)\]\/40{border-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-bg\)\]\/40{border-color:color-mix(in oklab, var(--landing-bg) 40%, transparent)}}.ui\:border-\[var\(--landing-border\)\],.ui\:border-\[var\(--landing-border\)\]\/40{border-color:var(--landing-border)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-border\)\]\/40{border-color:color-mix(in oklab, var(--landing-border) 40%, transparent)}}.ui\:border-\[var\(--landing-border\)\]\/50{border-color:var(--landing-border)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-border\)\]\/50{border-color:color-mix(in oklab, var(--landing-border) 50%, transparent)}}.ui\:border-\[var\(--landing-border\)\]\/60{border-color:var(--landing-border)}@supports (color:color-mix(in lab, red, red)){.ui\:border-\[var\(--landing-border\)\]\/60{border-color:color-mix(in oklab, var(--landing-border) 60%, transparent)}}.ui\:border-\[var\(--landing-border-soft\)\]{border-color:var(--landing-border-soft)}.ui\:border-\[var\(--landing-button-secondary-border\)\]{border-color:var(--landing-button-secondary-border)}.ui\:border-\[var\(--landing-fg\)\]{border-color:var(--landing-fg)}.ui\:border-amber-200{border-color:var(--ui-color-amber-200)}.ui\:border-amber-400{border-color:var(--ui-color-amber-400)}.ui\:border-black{border-color:var(--ui-color-black)}.ui\:border-border,.ui\:border-border\/50{border-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.ui\:border-border\/50{border-color:color-mix(in oklab, var(--border) 50%, transparent)}}.ui\:border-emerald-300{border-color:var(--ui-color-emerald-300)}.ui\:border-emerald-400{border-color:var(--ui-color-emerald-400)}.ui\:border-emerald-500{border-color:var(--ui-color-emerald-500)}.ui\:border-input{border-color:var(--input)}.ui\:border-muted{border-color:var(--muted)}.ui\:border-muted-foreground,.ui\:border-muted-foreground\/40{border-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:border-muted-foreground\/40{border-color:color-mix(in oklab, var(--muted-foreground) 40%, transparent)}}.ui\:border-neutral-400{border-color:var(--ui-color-neutral-400)}.ui\:border-neutral-800{border-color:var(--ui-color-neutral-800)}.ui\:border-primary,.ui\:border-primary\/30{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:border-primary\/30{border-color:color-mix(in oklab, var(--primary) 30%, transparent)}}.ui\:border-primary\/40{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:border-primary\/40{border-color:color-mix(in oklab, var(--primary) 40%, transparent)}}.ui\:border-primary\/50{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:border-primary\/50{border-color:color-mix(in oklab, var(--primary) 50%, transparent)}}.ui\:border-red-500{border-color:var(--ui-color-red-500)}.ui\:border-sidebar-border{border-color:var(--sidebar-border)}.ui\:border-sky-200{border-color:var(--ui-color-sky-200)}.ui\:border-transparent{border-color:#0000}.ui\:border-white,.ui\:border-white\/10{border-color:var(--ui-color-white)}@supports (color:color-mix(in lab, red, red)){.ui\:border-white\/10{border-color:color-mix(in oklab, var(--ui-color-white) 10%, transparent)}}.ui\:border-zinc-300{border-color:var(--ui-color-zinc-300)}.ui\:border-zinc-400{border-color:var(--ui-color-zinc-400)}.ui\:border-y-transparent{border-block-color:#0000}.ui\:border-l-current{border-left-color:currentColor}.ui\:border-l-foreground{border-left-color:var(--foreground)}.ui\:border-l-transparent{border-left-color:#0000}.ui\:bg-\(--color-bg\){background-color:var(--color-bg)}.ui\:bg-\[\#0f1218\]{background-color:#0f1218}.ui\:bg-\[\#1a1a1a\]{background-color:#1a1a1a}.ui\:bg-\[\#06070a\]{background-color:#06070a}.ui\:bg-\[\#e2e1d9\]{background-color:#e2e1d9}.ui\:bg-\[\#ebeae3\]{background-color:#ebeae3}.ui\:bg-\[\#ecebe5\]{background-color:#ecebe5}.ui\:bg-\[\#f4f3ed\]{background-color:#f4f3ed}.ui\:bg-\[\#f4f5f7\]{background-color:#f4f5f7}.ui\:bg-\[\#fafaf5\]{background-color:#fafaf5}.ui\:bg-\[var\(--landing-accent\)\],.ui\:bg-\[var\(--landing-accent\)\]\/5{background-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent\)\]\/5{background-color:color-mix(in oklab, var(--landing-accent) 5%, transparent)}}.ui\:bg-\[var\(--landing-accent\)\]\/10{background-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent\)\]\/10{background-color:color-mix(in oklab, var(--landing-accent) 10%, transparent)}}.ui\:bg-\[var\(--landing-accent\)\]\/60{background-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent\)\]\/60{background-color:color-mix(in oklab, var(--landing-accent) 60%, transparent)}}.ui\:bg-\[var\(--landing-accent\)\]\/70{background-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent\)\]\/70{background-color:color-mix(in oklab, var(--landing-accent) 70%, transparent)}}.ui\:bg-\[var\(--landing-accent-fg\)\],.ui\:bg-\[var\(--landing-accent-fg\)\]\/10{background-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent-fg\)\]\/10{background-color:color-mix(in oklab, var(--landing-accent-fg) 10%, transparent)}}.ui\:bg-\[var\(--landing-accent-fg\)\]\/15{background-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-accent-fg\)\]\/15{background-color:color-mix(in oklab, var(--landing-accent-fg) 15%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\],.ui\:bg-\[var\(--landing-bg\)\]\/5{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/5{background-color:color-mix(in oklab, var(--landing-bg) 5%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\]\/30{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/30{background-color:color-mix(in oklab, var(--landing-bg) 30%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\]\/75{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/75{background-color:color-mix(in oklab, var(--landing-bg) 75%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\]\/85{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/85{background-color:color-mix(in oklab, var(--landing-bg) 85%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\]\/90{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/90{background-color:color-mix(in oklab, var(--landing-bg) 90%, transparent)}}.ui\:bg-\[var\(--landing-bg\)\]\/95{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-bg\)\]\/95{background-color:color-mix(in oklab, var(--landing-bg) 95%, transparent)}}.ui\:bg-\[var\(--landing-bg-section\)\]{background-color:var(--landing-bg-section)}.ui\:bg-\[var\(--landing-border\)\]{background-color:var(--landing-border)}.ui\:bg-\[var\(--landing-button-primary-bg\)\]{background-color:var(--landing-button-primary-bg)}.ui\:bg-\[var\(--landing-button-secondary-bg\)\]{background-color:var(--landing-button-secondary-bg)}.ui\:bg-\[var\(--landing-card\)\],.ui\:bg-\[var\(--landing-card\)\]\/70{background-color:var(--landing-card)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-card\)\]\/70{background-color:color-mix(in oklab, var(--landing-card) 70%, transparent)}}.ui\:bg-\[var\(--landing-card-soft\)\],.ui\:bg-\[var\(--landing-card-soft\)\]\/30{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-card-soft\)\]\/30{background-color:color-mix(in oklab, var(--landing-card-soft) 30%, transparent)}}.ui\:bg-\[var\(--landing-card-soft\)\]\/40{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-card-soft\)\]\/40{background-color:color-mix(in oklab, var(--landing-card-soft) 40%, transparent)}}.ui\:bg-\[var\(--landing-card-soft\)\]\/50{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-card-soft\)\]\/50{background-color:color-mix(in oklab, var(--landing-card-soft) 50%, transparent)}}.ui\:bg-\[var\(--landing-card-soft\)\]\/60{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-\[var\(--landing-card-soft\)\]\/60{background-color:color-mix(in oklab, var(--landing-card-soft) 60%, transparent)}}.ui\:bg-\[var\(--landing-fg\)\]{background-color:var(--landing-fg)}.ui\:bg-accent{background-color:var(--accent)}.ui\:bg-amber-50,.ui\:bg-amber-50\/30{background-color:var(--ui-color-amber-50)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-amber-50\/30{background-color:color-mix(in oklab, var(--ui-color-amber-50) 30%, transparent)}}.ui\:bg-amber-500{background-color:var(--ui-color-amber-500)}.ui\:bg-amber-500\!{background-color:var(--ui-color-amber-500)!important}.ui\:bg-amber-600{background-color:var(--ui-color-amber-600)}.ui\:bg-background,.ui\:bg-background\/50{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-background\/50{background-color:color-mix(in oklab, var(--background) 50%, transparent)}}.ui\:bg-background\/90{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-background\/90{background-color:color-mix(in oklab, var(--background) 90%, transparent)}}.ui\:bg-background\/95{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-background\/95{background-color:color-mix(in oklab, var(--background) 95%, transparent)}}.ui\:bg-black,.ui\:bg-black\/10{background-color:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-black\/10{background-color:color-mix(in oklab, var(--ui-color-black) 10%, transparent)}}.ui\:bg-black\/40{background-color:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-black\/40{background-color:color-mix(in oklab, var(--ui-color-black) 40%, transparent)}}.ui\:bg-black\/50{background-color:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-black\/50{background-color:color-mix(in oklab, var(--ui-color-black) 50%, transparent)}}.ui\:bg-blue-600{background-color:var(--ui-color-blue-600)}.ui\:bg-blue-600\!{background-color:var(--ui-color-blue-600)!important}.ui\:bg-border{background-color:var(--border)}.ui\:bg-card,.ui\:bg-card\/95{background-color:var(--card)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-card\/95{background-color:color-mix(in oklab, var(--card) 95%, transparent)}}.ui\:bg-current{background-color:currentColor}.ui\:bg-destructive{background-color:var(--destructive)}.ui\:bg-emerald-50\/20{background-color:var(--ui-color-emerald-50)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-emerald-50\/20{background-color:color-mix(in oklab, var(--ui-color-emerald-50) 20%, transparent)}}.ui\:bg-emerald-50\/30{background-color:var(--ui-color-emerald-50)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-emerald-50\/30{background-color:color-mix(in oklab, var(--ui-color-emerald-50) 30%, transparent)}}.ui\:bg-emerald-50\/40{background-color:var(--ui-color-emerald-50)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-emerald-50\/40{background-color:color-mix(in oklab, var(--ui-color-emerald-50) 40%, transparent)}}.ui\:bg-emerald-500{background-color:var(--ui-color-emerald-500)}.ui\:bg-emerald-500\!{background-color:var(--ui-color-emerald-500)!important}.ui\:bg-emerald-600{background-color:var(--ui-color-emerald-600)}.ui\:bg-gray-200{background-color:var(--ui-color-gray-200)}.ui\:bg-green-500{background-color:var(--ui-color-green-500)}.ui\:bg-inherit{background-color:inherit}.ui\:bg-input{background-color:var(--input)}.ui\:bg-muted{background-color:var(--muted)}.ui\:bg-muted-foreground\/30{background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-muted-foreground\/30{background-color:color-mix(in oklab, var(--muted-foreground) 30%, transparent)}}.ui\:bg-muted\/30{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-muted\/30{background-color:color-mix(in oklab, var(--muted) 30%, transparent)}}.ui\:bg-muted\/50{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-muted\/50{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}.ui\:bg-muted\/95{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-muted\/95{background-color:color-mix(in oklab, var(--muted) 95%, transparent)}}.ui\:bg-neutral-100{background-color:var(--ui-color-neutral-100)}.ui\:bg-neutral-900\/50{background-color:var(--ui-color-neutral-900)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-neutral-900\/50{background-color:color-mix(in oklab, var(--ui-color-neutral-900) 50%, transparent)}}.ui\:bg-popover{background-color:var(--popover)}.ui\:bg-primary{background-color:var(--primary)}.ui\:bg-primary-foreground{background-color:var(--primary-foreground)}.ui\:bg-primary\/10{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-primary\/10{background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.ui\:bg-primary\/20{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-primary\/20{background-color:color-mix(in oklab, var(--primary) 20%, transparent)}}.ui\:bg-red-50\/40{background-color:var(--ui-color-red-50)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-red-50\/40{background-color:color-mix(in oklab, var(--ui-color-red-50) 40%, transparent)}}.ui\:bg-red-500{background-color:var(--ui-color-red-500)}.ui\:bg-rose-500{background-color:var(--ui-color-rose-500)}.ui\:bg-rose-500\!{background-color:var(--ui-color-rose-500)!important}.ui\:bg-secondary,.ui\:bg-secondary\/50{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-secondary\/50{background-color:color-mix(in oklab, var(--secondary) 50%, transparent)}}.ui\:bg-sidebar{background-color:var(--sidebar)}.ui\:bg-sidebar-border{background-color:var(--sidebar-border)}.ui\:bg-sky-50{background-color:var(--ui-color-sky-50)}.ui\:bg-slate-500{background-color:var(--ui-color-slate-500)}.ui\:bg-slate-500\!{background-color:var(--ui-color-slate-500)!important}.ui\:bg-transparent{background-color:#0000}.ui\:bg-violet-500{background-color:var(--ui-color-violet-500)}.ui\:bg-violet-500\!{background-color:var(--ui-color-violet-500)!important}.ui\:bg-white,.ui\:bg-white\/5{background-color:var(--ui-color-white)}@supports (color:color-mix(in lab, red, red)){.ui\:bg-white\/5{background-color:color-mix(in oklab, var(--ui-color-white) 5%, transparent)}}.ui\:bg-yellow-500{background-color:var(--ui-color-yellow-500)}.ui\:bg-zinc-100{background-color:var(--ui-color-zinc-100)}.ui\:bg-zinc-400{background-color:var(--ui-color-zinc-400)}.ui\:bg-linear-to-r{--tw-gradient-position:to right}@supports (background-image:linear-gradient(in lab, red, red)){.ui\:bg-linear-to-r{--tw-gradient-position:to right in oklab}}.ui\:bg-linear-to-r{background-image:linear-gradient(var(--tw-gradient-stops))}.ui\:bg-linear-to-t{--tw-gradient-position:to top}@supports (background-image:linear-gradient(in lab, red, red)){.ui\:bg-linear-to-t{--tw-gradient-position:to top in oklab}}.ui\:bg-linear-to-t{background-image:linear-gradient(var(--tw-gradient-stops))}.ui\:bg-\[linear-gradient\(110deg\,\#000103\,45\%\,\#1e2631\,55\%\,\#000103\)\]{background-image:linear-gradient(110deg,#000103,45%,#1e2631,55%,#000103)}.ui\:from-background{--tw-gradient-from:var(--background);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:from-pink-500{--tw-gradient-from:var(--ui-color-pink-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:from-slate-500{--tw-gradient-from:var(--ui-color-slate-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:from-transparent{--tw-gradient-from:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:via-black\/80{--tw-gradient-via:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:via-black\/80{--tw-gradient-via:color-mix(in oklab, var(--ui-color-black) 80%, transparent)}}.ui\:via-black\/80{--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.ui\:via-blue-600\/30{--tw-gradient-via:var(--ui-color-blue-600)}@supports (color:color-mix(in lab, red, red)){.ui\:via-blue-600\/30{--tw-gradient-via:color-mix(in oklab, var(--ui-color-blue-600) 30%, transparent)}}.ui\:via-blue-600\/30{--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.ui\:via-50\%{--tw-gradient-via-position:50%}.ui\:to-orange-500{--tw-gradient-to:var(--ui-color-orange-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:to-transparent{--tw-gradient-to:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.ui\:bg-\[length\:200\%_100\%\]{background-size:200% 100%}.ui\:bg-cover{background-size:cover}.ui\:bg-size-\[var\(--shimmer-width\)_100\%\]{background-size:var(--shimmer-width) 100%}.ui\:bg-clip-padding{background-clip:padding-box}.ui\:bg-clip-text{-webkit-background-clip:text;background-clip:text}.ui\:bg-center{background-position:50%}.ui\:bg-position-\[0_0\]{background-position:0 0}.ui\:bg-no-repeat{background-repeat:no-repeat}.ui\:fill-amber-400{fill:var(--ui-color-amber-400)}.ui\:fill-current{fill:currentColor}.ui\:fill-none{fill:none}.ui\:fill-primary{fill:var(--primary)}.ui\:object-contain{object-fit:contain}.ui\:object-cover{object-fit:cover}.ui\:p-0{padding:calc(var(--ui-spacing) * 0)}.ui\:p-0\!{padding:calc(var(--ui-spacing) * 0)!important}.ui\:p-0\.5{padding:calc(var(--ui-spacing) * .5)}.ui\:p-1{padding:calc(var(--ui-spacing) * 1)}.ui\:p-1\!{padding:calc(var(--ui-spacing) * 1)!important}.ui\:p-1\.5{padding:calc(var(--ui-spacing) * 1.5)}.ui\:p-2{padding:calc(var(--ui-spacing) * 2)}.ui\:p-3{padding:calc(var(--ui-spacing) * 3)}.ui\:p-3\!{padding:calc(var(--ui-spacing) * 3)!important}.ui\:p-4{padding:calc(var(--ui-spacing) * 4)}.ui\:p-5{padding:calc(var(--ui-spacing) * 5)}.ui\:p-6{padding:calc(var(--ui-spacing) * 6)}.ui\:p-7{padding:calc(var(--ui-spacing) * 7)}.ui\:p-8{padding:calc(var(--ui-spacing) * 8)}.ui\:p-10{padding:calc(var(--ui-spacing) * 10)}.ui\:p-\[3px\]{padding:3px}.ui\:px-1{padding-inline:calc(var(--ui-spacing) * 1)}.ui\:px-1\.5{padding-inline:calc(var(--ui-spacing) * 1.5)}.ui\:px-2{padding-inline:calc(var(--ui-spacing) * 2)}.ui\:px-2\.5{padding-inline:calc(var(--ui-spacing) * 2.5)}.ui\:px-3{padding-inline:calc(var(--ui-spacing) * 3)}.ui\:px-3\.5{padding-inline:calc(var(--ui-spacing) * 3.5)}.ui\:px-4{padding-inline:calc(var(--ui-spacing) * 4)}.ui\:px-5{padding-inline:calc(var(--ui-spacing) * 5)}.ui\:px-6{padding-inline:calc(var(--ui-spacing) * 6)}.ui\:px-7{padding-inline:calc(var(--ui-spacing) * 7)}.ui\:px-8{padding-inline:calc(var(--ui-spacing) * 8)}.ui\:py-0{padding-block:calc(var(--ui-spacing) * 0)}.ui\:py-0\.5{padding-block:calc(var(--ui-spacing) * .5)}.ui\:py-1{padding-block:calc(var(--ui-spacing) * 1)}.ui\:py-1\.5{padding-block:calc(var(--ui-spacing) * 1.5)}.ui\:py-2{padding-block:calc(var(--ui-spacing) * 2)}.ui\:py-2\.5{padding-block:calc(var(--ui-spacing) * 2.5)}.ui\:py-3{padding-block:calc(var(--ui-spacing) * 3)}.ui\:py-3\.5{padding-block:calc(var(--ui-spacing) * 3.5)}.ui\:py-4{padding-block:calc(var(--ui-spacing) * 4)}.ui\:py-5{padding-block:calc(var(--ui-spacing) * 5)}.ui\:py-6{padding-block:calc(var(--ui-spacing) * 6)}.ui\:py-8{padding-block:calc(var(--ui-spacing) * 8)}.ui\:py-10{padding-block:calc(var(--ui-spacing) * 10)}.ui\:py-12{padding-block:calc(var(--ui-spacing) * 12)}.ui\:py-14{padding-block:calc(var(--ui-spacing) * 14)}.ui\:py-16{padding-block:calc(var(--ui-spacing) * 16)}.ui\:py-20{padding-block:calc(var(--ui-spacing) * 20)}.ui\:py-24{padding-block:calc(var(--ui-spacing) * 24)}.ui\:py-32{padding-block:calc(var(--ui-spacing) * 32)}.ui\:ps-3{padding-inline-start:calc(var(--ui-spacing) * 3)}.ui\:pe-3{padding-inline-end:calc(var(--ui-spacing) * 3)}.ui\:pt-0{padding-top:calc(var(--ui-spacing) * 0)}.ui\:pt-1{padding-top:calc(var(--ui-spacing) * 1)}.ui\:pt-1\.5{padding-top:calc(var(--ui-spacing) * 1.5)}.ui\:pt-2{padding-top:calc(var(--ui-spacing) * 2)}.ui\:pt-2\.5{padding-top:calc(var(--ui-spacing) * 2.5)}.ui\:pt-3{padding-top:calc(var(--ui-spacing) * 3)}.ui\:pt-3\!{padding-top:calc(var(--ui-spacing) * 3)!important}.ui\:pt-3\.5{padding-top:calc(var(--ui-spacing) * 3.5)}.ui\:pt-4{padding-top:calc(var(--ui-spacing) * 4)}.ui\:pt-5{padding-top:calc(var(--ui-spacing) * 5)}.ui\:pt-6{padding-top:calc(var(--ui-spacing) * 6)}.ui\:pt-8{padding-top:calc(var(--ui-spacing) * 8)}.ui\:pt-10{padding-top:calc(var(--ui-spacing) * 10)}.ui\:pt-12{padding-top:calc(var(--ui-spacing) * 12)}.ui\:pt-16{padding-top:calc(var(--ui-spacing) * 16)}.ui\:pt-20{padding-top:calc(var(--ui-spacing) * 20)}.ui\:pr-1{padding-right:calc(var(--ui-spacing) * 1)}.ui\:pr-2{padding-right:calc(var(--ui-spacing) * 2)}.ui\:pr-4{padding-right:calc(var(--ui-spacing) * 4)}.ui\:pr-8{padding-right:calc(var(--ui-spacing) * 8)}.ui\:pr-9{padding-right:calc(var(--ui-spacing) * 9)}.ui\:pr-18{padding-right:calc(var(--ui-spacing) * 18)}.ui\:pb-0{padding-bottom:calc(var(--ui-spacing) * 0)}.ui\:pb-2{padding-bottom:calc(var(--ui-spacing) * 2)}.ui\:pb-3{padding-bottom:calc(var(--ui-spacing) * 3)}.ui\:pb-4{padding-bottom:calc(var(--ui-spacing) * 4)}.ui\:pb-5{padding-bottom:calc(var(--ui-spacing) * 5)}.ui\:pb-6{padding-bottom:calc(var(--ui-spacing) * 6)}.ui\:pb-10{padding-bottom:calc(var(--ui-spacing) * 10)}.ui\:pb-12{padding-bottom:calc(var(--ui-spacing) * 12)}.ui\:pb-16{padding-bottom:calc(var(--ui-spacing) * 16)}.ui\:pb-20{padding-bottom:calc(var(--ui-spacing) * 20)}.ui\:pb-24{padding-bottom:calc(var(--ui-spacing) * 24)}.ui\:pb-\[max\(env\(safe-area-inset-bottom\)\,1rem\)\]{padding-bottom:max(env(safe-area-inset-bottom), 1rem)}.ui\:pl-2{padding-left:calc(var(--ui-spacing) * 2)}.ui\:pl-3{padding-left:calc(var(--ui-spacing) * 3)}.ui\:pl-4{padding-left:calc(var(--ui-spacing) * 4)}.ui\:pl-5{padding-left:calc(var(--ui-spacing) * 5)}.ui\:pl-8{padding-left:calc(var(--ui-spacing) * 8)}.ui\:text-center{text-align:center}.ui\:text-left{text-align:left}.ui\:text-right{text-align:right}.ui\:align-middle{vertical-align:middle}.ui\:font-mono{font-family:var(--ui-font-mono)}.ui\:font-sans{font-family:var(--ui-font-sans)}.ui\:font-serif{font-family:var(--ui-font-serif)}.ui\:text-2xl{font-size:var(--ui-text-2xl);line-height:var(--tw-leading,var(--ui-text-2xl--line-height))}.ui\:text-3xl{font-size:var(--ui-text-3xl);line-height:var(--tw-leading,var(--ui-text-3xl--line-height))}.ui\:text-4xl{font-size:var(--ui-text-4xl);line-height:var(--tw-leading,var(--ui-text-4xl--line-height))}.ui\:text-5xl{font-size:var(--ui-text-5xl);line-height:var(--tw-leading,var(--ui-text-5xl--line-height))}.ui\:text-6xl{font-size:var(--ui-text-6xl);line-height:var(--tw-leading,var(--ui-text-6xl--line-height))}.ui\:text-base{font-size:var(--ui-text-base);line-height:var(--tw-leading,var(--ui-text-base--line-height))}.ui\:text-base\!{font-size:var(--ui-text-base)!important;line-height:var(--tw-leading,var(--ui-text-base--line-height))!important}.ui\:text-lg{font-size:var(--ui-text-lg);line-height:var(--tw-leading,var(--ui-text-lg--line-height))}.ui\:text-sm{font-size:var(--ui-text-sm);line-height:var(--tw-leading,var(--ui-text-sm--line-height))}.ui\:text-sm\/relaxed{font-size:var(--ui-text-sm);line-height:var(--ui-leading-relaxed)}.ui\:text-xl{font-size:var(--ui-text-xl);line-height:var(--tw-leading,var(--ui-text-xl--line-height))}.ui\:text-xs{font-size:var(--ui-text-xs);line-height:var(--tw-leading,var(--ui-text-xs--line-height))}.ui\:text-\[0\.7rem\]{font-size:.7rem}.ui\:text-\[10px\]{font-size:10px}.ui\:text-\[11\.5px\]{font-size:11.5px}.ui\:text-\[11px\]{font-size:11px}.ui\:text-\[12\.5px\]{font-size:12.5px}.ui\:text-\[12px\]{font-size:12px}.ui\:text-\[13\.5px\]{font-size:13.5px}.ui\:text-\[13px\]{font-size:13px}.ui\:text-\[14\.5px\]{font-size:14.5px}.ui\:text-\[14px\]{font-size:14px}.ui\:text-\[15px\]{font-size:15px}.ui\:text-\[16px\]{font-size:16px}.ui\:text-\[17px\]{font-size:17px}.ui\:text-\[19px\]{font-size:19px}.ui\:text-\[22px\]{font-size:22px}.ui\:text-\[36px\]{font-size:36px}.ui\:text-\[40px\]{font-size:40px}.ui\:text-\[44px\]{font-size:44px}.ui\:text-\[64px\]{font-size:64px}.ui\:leading-7{--tw-leading:calc(var(--ui-spacing) * 7);line-height:calc(var(--ui-spacing) * 7)}.ui\:leading-8{--tw-leading:calc(var(--ui-spacing) * 8);line-height:calc(var(--ui-spacing) * 8)}.ui\:leading-\[0\.95\]{--tw-leading:.95;line-height:.95}.ui\:leading-\[1\.1\]{--tw-leading:1.1;line-height:1.1}.ui\:leading-\[1\.02\]{--tw-leading:1.02;line-height:1.02}.ui\:leading-\[1\.05\]{--tw-leading:1.05;line-height:1.05}.ui\:leading-\[1\.5\]{--tw-leading:1.5;line-height:1.5}.ui\:leading-\[1\.08\]{--tw-leading:1.08;line-height:1.08}.ui\:leading-\[1\.25\]{--tw-leading:1.25;line-height:1.25}.ui\:leading-\[1\.35\]{--tw-leading:1.35;line-height:1.35}.ui\:leading-none{--tw-leading:1;line-height:1}.ui\:leading-normal{--tw-leading:var(--ui-leading-normal);line-height:var(--ui-leading-normal)}.ui\:leading-relaxed{--tw-leading:var(--ui-leading-relaxed);line-height:var(--ui-leading-relaxed)}.ui\:leading-snug{--tw-leading:var(--ui-leading-snug);line-height:var(--ui-leading-snug)}.ui\:leading-tight{--tw-leading:var(--ui-leading-tight);line-height:var(--ui-leading-tight)}.ui\:font-black{--tw-font-weight:var(--ui-font-weight-black);font-weight:var(--ui-font-weight-black)}.ui\:font-bold{--tw-font-weight:var(--ui-font-weight-bold);font-weight:var(--ui-font-weight-bold)}.ui\:font-extrabold{--tw-font-weight:var(--ui-font-weight-extrabold);font-weight:var(--ui-font-weight-extrabold)}.ui\:font-light{--tw-font-weight:var(--ui-font-weight-light);font-weight:var(--ui-font-weight-light)}.ui\:font-medium{--tw-font-weight:var(--ui-font-weight-medium);font-weight:var(--ui-font-weight-medium)}.ui\:font-normal{--tw-font-weight:var(--ui-font-weight-normal);font-weight:var(--ui-font-weight-normal)}.ui\:font-semibold{--tw-font-weight:var(--ui-font-weight-semibold);font-weight:var(--ui-font-weight-semibold)}.ui\:\[font-weight\:var\(--landing-heading-weight\)\]{font-weight:var(--landing-heading-weight)}.ui\:tracking-\[-0\.02em\]{--tw-tracking:-.02em;letter-spacing:-.02em}.ui\:tracking-\[0\.2em\]{--tw-tracking:.2em;letter-spacing:.2em}.ui\:tracking-\[0\.04em\]{--tw-tracking:.04em;letter-spacing:.04em}.ui\:tracking-\[0\.08em\]{--tw-tracking:.08em;letter-spacing:.08em}.ui\:tracking-\[0\.12em\]{--tw-tracking:.12em;letter-spacing:.12em}.ui\:tracking-\[0\.18em\]{--tw-tracking:.18em;letter-spacing:.18em}.ui\:tracking-tight{--tw-tracking:var(--ui-tracking-tight);letter-spacing:var(--ui-tracking-tight)}.ui\:tracking-tighter{--tw-tracking:var(--ui-tracking-tighter);letter-spacing:var(--ui-tracking-tighter)}.ui\:tracking-wide{--tw-tracking:var(--ui-tracking-wide);letter-spacing:var(--ui-tracking-wide)}.ui\:tracking-wider{--tw-tracking:var(--ui-tracking-wider);letter-spacing:var(--ui-tracking-wider)}.ui\:tracking-widest{--tw-tracking:var(--ui-tracking-widest);letter-spacing:var(--ui-tracking-widest)}.ui\:\[letter-spacing\:var\(--landing-eyebrow-tracking\)\]{letter-spacing:var(--landing-eyebrow-tracking)}.ui\:\[letter-spacing\:var\(--landing-heading-tracking\)\]{letter-spacing:var(--landing-heading-tracking)}.ui\:text-balance{text-wrap:balance}.ui\:text-wrap{text-wrap:wrap}.ui\:break-words{overflow-wrap:break-word}.ui\:break-all{word-break:break-all}.ui\:text-ellipsis{text-overflow:ellipsis}.ui\:whitespace-nowrap{white-space:nowrap}.ui\:text-\[\#0a0b0e\]{color:#0a0b0e}.ui\:text-\[\#1a1a1a\]{color:#1a1a1a}.ui\:text-\[\#2c2b29\]{color:#2c2b29}.ui\:text-\[\#9da1ab\]{color:#9da1ab}.ui\:text-\[\#61656f\]{color:#61656f}.ui\:text-\[\#76746c\]{color:#76746c}.ui\:text-\[\#c25237\]{color:#c25237}.ui\:text-\[\#e9eaed\]{color:#e9eaed}.ui\:text-\[\#fafaf5\]{color:#fafaf5}.ui\:text-\[var\(--landing-accent\)\]{color:var(--landing-accent)}.ui\:text-\[var\(--landing-accent-fg\)\],.ui\:text-\[var\(--landing-accent-fg\)\]\/70{color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-accent-fg\)\]\/70{color:color-mix(in oklab, var(--landing-accent-fg) 70%, transparent)}}.ui\:text-\[var\(--landing-accent-fg\)\]\/80{color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-accent-fg\)\]\/80{color:color-mix(in oklab, var(--landing-accent-fg) 80%, transparent)}}.ui\:text-\[var\(--landing-accent-fg\)\]\/85{color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-accent-fg\)\]\/85{color:color-mix(in oklab, var(--landing-accent-fg) 85%, transparent)}}.ui\:text-\[var\(--landing-bg\)\],.ui\:text-\[var\(--landing-bg\)\]\/50{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/50{color:color-mix(in oklab, var(--landing-bg) 50%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/55{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/55{color:color-mix(in oklab, var(--landing-bg) 55%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/60{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/60{color:color-mix(in oklab, var(--landing-bg) 60%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/65{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/65{color:color-mix(in oklab, var(--landing-bg) 65%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/70{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/70{color:color-mix(in oklab, var(--landing-bg) 70%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/75{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/75{color:color-mix(in oklab, var(--landing-bg) 75%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/80{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/80{color:color-mix(in oklab, var(--landing-bg) 80%, transparent)}}.ui\:text-\[var\(--landing-bg\)\]\/90{color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-bg\)\]\/90{color:color-mix(in oklab, var(--landing-bg) 90%, transparent)}}.ui\:text-\[var\(--landing-button-primary-fg\)\]{color:var(--landing-button-primary-fg)}.ui\:text-\[var\(--landing-button-secondary-fg\)\]{color:var(--landing-button-secondary-fg)}.ui\:text-\[var\(--landing-button-tertiary-fg\)\]{color:var(--landing-button-tertiary-fg)}.ui\:text-\[var\(--landing-fg\)\],.ui\:text-\[var\(--landing-fg\)\]\/70{color:var(--landing-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-fg\)\]\/70{color:color-mix(in oklab, var(--landing-fg) 70%, transparent)}}.ui\:text-\[var\(--landing-fg\)\]\/72{color:var(--landing-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-fg\)\]\/72{color:color-mix(in oklab, var(--landing-fg) 72%, transparent)}}.ui\:text-\[var\(--landing-fg\)\]\/80{color:var(--landing-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:text-\[var\(--landing-fg\)\]\/80{color:color-mix(in oklab, var(--landing-fg) 80%, transparent)}}.ui\:text-\[var\(--landing-fg-faint\)\]{color:var(--landing-fg-faint)}.ui\:text-\[var\(--landing-fg-muted\)\]{color:var(--landing-fg-muted)}.ui\:text-accent-foreground{color:var(--accent-foreground)}.ui\:text-amber-200{color:var(--ui-color-amber-200)}.ui\:text-amber-500{color:var(--ui-color-amber-500)}.ui\:text-amber-600{color:var(--ui-color-amber-600)}.ui\:text-amber-900{color:var(--ui-color-amber-900)}.ui\:text-black{color:var(--ui-color-black)}.ui\:text-card-foreground{color:var(--card-foreground)}.ui\:text-current{color:currentColor}.ui\:text-destructive{color:var(--destructive)}.ui\:text-emerald-600{color:var(--ui-color-emerald-600)}.ui\:text-emerald-700{color:var(--ui-color-emerald-700)}.ui\:text-foreground,.ui\:text-foreground\/70{color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-foreground\/70{color:color-mix(in oklab, var(--foreground) 70%, transparent)}}.ui\:text-gray-200{color:var(--ui-color-gray-200)}.ui\:text-green-500{color:var(--ui-color-green-500)}.ui\:text-green-600{color:var(--ui-color-green-600)}.ui\:text-muted-foreground,.ui\:text-muted-foreground\/60{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-muted-foreground\/60{color:color-mix(in oklab, var(--muted-foreground) 60%, transparent)}}.ui\:text-muted-foreground\/75{color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-muted-foreground\/75{color:color-mix(in oklab, var(--muted-foreground) 75%, transparent)}}.ui\:text-neutral-600\/50{color:var(--ui-color-neutral-600)}@supports (color:color-mix(in lab, red, red)){.ui\:text-neutral-600\/50{color:color-mix(in oklab, var(--ui-color-neutral-600) 50%, transparent)}}.ui\:text-popover-foreground{color:var(--popover-foreground)}.ui\:text-primary{color:var(--primary)}.ui\:text-primary\!{color:var(--primary)!important}.ui\:text-primary-foreground{color:var(--primary-foreground)}.ui\:text-red-500{color:var(--ui-color-red-500)}.ui\:text-red-600{color:var(--ui-color-red-600)}.ui\:text-red-700{color:var(--ui-color-red-700)}.ui\:text-secondary-foreground{color:var(--secondary-foreground)}.ui\:text-sidebar-foreground,.ui\:text-sidebar-foreground\/70{color:var(--sidebar-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-sidebar-foreground\/70{color:color-mix(in oklab, var(--sidebar-foreground) 70%, transparent)}}.ui\:text-sidebar-foreground\/75{color:var(--sidebar-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-sidebar-foreground\/75{color:color-mix(in oklab, var(--sidebar-foreground) 75%, transparent)}}.ui\:text-sidebar-foreground\/80{color:var(--sidebar-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:text-sidebar-foreground\/80{color:color-mix(in oklab, var(--sidebar-foreground) 80%, transparent)}}.ui\:text-sky-900{color:var(--ui-color-sky-900)}.ui\:text-transparent{color:#0000}.ui\:text-white{color:var(--ui-color-white)}.ui\:text-white\!{color:var(--ui-color-white)!important}.ui\:\[text-transform\:var\(--landing-eyebrow-case\)\]{text-transform:var(--landing-eyebrow-case)}.ui\:\[text-transform\:var\(--landing-heading-case\)\]{text-transform:var(--landing-heading-case)}.ui\:capitalize{text-transform:capitalize}.ui\:uppercase{text-transform:uppercase}.ui\:italic{font-style:italic}.ui\:tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.ui\:line-through{text-decoration-line:line-through}.ui\:no-underline{text-decoration-line:none}.ui\:underline{text-decoration-line:underline}.ui\:underline-offset-2{text-underline-offset:2px}.ui\:underline-offset-4{text-underline-offset:4px}.ui\:opacity-0{opacity:0}.ui\:opacity-10{opacity:.1}.ui\:opacity-30{opacity:.3}.ui\:opacity-40{opacity:.4}.ui\:opacity-50{opacity:.5}.ui\:opacity-60{opacity:.6}.ui\:opacity-70{opacity:.7}.ui\:opacity-85{opacity:.85}.ui\:opacity-90{opacity:.9}.ui\:opacity-95{opacity:.95}.ui\:opacity-100{opacity:1}.ui\:opacity-\[0\.06\]{opacity:.06}.ui\:opacity-\[0\.08\]{opacity:.08}.ui\:opacity-\[0\.10\]{opacity:.1}.ui\:opacity-\[0\.15\]{opacity:.15}.ui\:shadow-\[var\(--landing-accent\)\]\/20{--tw-shadow-alpha:20%;--tw-shadow:var(--landing-accent);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[var\(--landing-accent\)\]\/25{--tw-shadow-alpha:25%;--tw-shadow:var(--landing-accent);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-2xs{--tw-shadow:0 1px var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_0_0_1px_\#ffffff10\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,#ffffff10);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_0_0_1px_var\(--sidebar-border\)\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,var(--sidebar-border));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_4px_16px_rgba\(0\,0\,0\,0\.10\)\]{--tw-shadow:0 4px 16px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_4px_24px_-8px_rgba\(14\,14\,16\,0\.08\)\]{--tw-shadow:0 4px 24px -8px var(--tw-shadow-color,#0e0e1014);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_18px_40px_rgba\(0\,0\,0\,0\.18\)\,0_6px_12px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 18px 40px var(--tw-shadow-color,#0000002e), 0 6px 12px var(--tw-shadow-color,#0000001f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_20px_60px_-30px_rgba\(14\,14\,16\,0\.25\)\]{--tw-shadow:0 20px 60px -30px var(--tw-shadow-color,#0e0e1040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[0_40px_90px_-30px_rgba\(0\,0\,0\,0\.35\)\]{--tw-shadow:0 40px 90px -30px var(--tw-shadow-color,#00000059);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-\[inset_0_-8px_10px_\#ffffff1f\]{--tw-shadow:inset 0 -8px 10px var(--tw-shadow-color,#ffffff1f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:ring-0{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + 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)}.ui\:ring-1{--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)}.ui\:ring-2{--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)}.ui\:ring-3{--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)}.ui\:ring-4{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(4px + 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)}.ui\:\[box-shadow\:var\(--landing-glow\)\]{box-shadow:var(--landing-glow)}.ui\:\[box-shadow\:var\(--landing-shadow-card\)\]{box-shadow:var(--landing-shadow-card)}.ui\:ring-\[var\(--landing-accent\)\]{--tw-ring-color:var(--landing-accent)}.ui\:ring-accent{--tw-ring-color:var(--accent)}.ui\:ring-background{--tw-ring-color:var(--background)}.ui\:ring-border,.ui\:ring-border\/50{--tw-ring-color:var(--border)}@supports (color:color-mix(in lab, red, red)){.ui\:ring-border\/50{--tw-ring-color:color-mix(in oklab, var(--border) 50%, transparent)}}.ui\:ring-primary{--tw-ring-color:var(--primary)}.ui\:ring-sidebar-ring{--tw-ring-color:var(--sidebar-ring)}.ui\:ring-offset-2{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ui\:ring-offset-background{--tw-ring-offset-color:var(--background)}.ui\:outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.ui\:outline-hidden{outline-offset:2px;outline:2px solid #0000}}.ui\:blur-3xl{--tw-blur:blur(var(--ui-blur-3xl));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,)}.ui\:blur-\[2px\]{--tw-blur:blur(2px);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,)}.ui\:brightness-200{--tw-brightness:brightness(200%);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,)}.ui\:drop-shadow-sm{--tw-drop-shadow-size:drop-shadow(0 1px 2px var(--tw-drop-shadow-color,#00000026));--tw-drop-shadow:drop-shadow(var(--ui-drop-shadow-sm));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,)}.ui\:drop-shadow-none{--tw-drop-shadow: ;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,)}.ui\:grayscale{--tw-grayscale:grayscale(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.ui\:backdrop-blur{--tw-backdrop-blur:blur(8px);-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,)}.ui\:backdrop-blur-2xl{--tw-backdrop-blur:blur(var(--ui-blur-2xl));-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,)}.ui\:backdrop-blur-md{--tw-backdrop-blur:blur(var(--ui-blur-md));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.ui\:backdrop-blur-sm{--tw-backdrop-blur:blur(var(--ui-blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.ui\:backdrop-blur-xl{--tw-backdrop-blur:blur(var(--ui-blur-xl));-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,)}.ui\:transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[color\,box-shadow\]{transition-property:color,box-shadow;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[left\,right\,width\]{transition-property:left,right,width;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[margin\,opacity\]{transition-property:margin,opacity;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[stroke-dashoffset\]{transition-property:stroke-dashoffset;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[width\,height\,padding\]{transition-property:width,height,padding;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-\[width\]{transition-property:width;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}.ui\:transition-none{transition-property:none}.ui\:duration-100{--tw-duration:.1s;transition-duration:.1s}.ui\:duration-200{--tw-duration:.2s;transition-duration:.2s}.ui\:duration-300{--tw-duration:.3s;transition-duration:.3s}.ui\:duration-500{--tw-duration:.5s;transition-duration:.5s}.ui\:duration-700{--tw-duration:.7s;transition-duration:.7s}.ui\:ease-in-out{--tw-ease:var(--ui-ease-in-out);transition-timing-function:var(--ui-ease-in-out)}.ui\:ease-linear{--tw-ease:linear;transition-timing-function:linear}.ui\:ease-out{--tw-ease:var(--ui-ease-out);transition-timing-function:var(--ui-ease-out)}.ui\:fade-in-0{--tw-enter-opacity:0}.ui\:outline-none{--tw-outline-style:none;outline-style:none}.ui\:select-none{-webkit-user-select:none;user-select:none}.ui\:zoom-in-95{--tw-enter-scale:.95}.ui\:\[--dot-field-glow\:\#fff\]{--dot-field-glow:#fff}.ui\:\[background\:conic-gradient\(from_calc\(270deg-\(var\(--spread\)\*0\.5\)\)\,transparent_0\,var\(--shimmer-color\)_var\(--spread\)\,transparent_var\(--spread\)\)\]{background:conic-gradient(from calc(270deg - (var(--spread) * .5)),transparent 0,var(--shimmer-color) var(--spread),transparent var(--spread))}.ui\:\[background\:linear-gradient\(180deg\,var\(--landing-card\)_0\%\,var\(--landing-bg-section\)_100\%\)\]{background:linear-gradient(180deg,var(--landing-card) 0%,var(--landing-bg-section) 100%)}.ui\:\[background\:var\(--bg\)\]{background:var(--bg)}.ui\:\[border-top\:1px_dashed_var\(--landing-border-soft\)\]{border-top:1px dashed var(--landing-border-soft)}.ui\:\[mask\:none\]{-webkit-mask:none;mask:none}.ui\:ring-inset{--tw-ring-inset:inset}:is(.ui\:\*\:w-full>*){width:100%}.ui\:group-focus-within\/menu-item\:opacity-100:is(:where(.ui\:group\/menu-item):focus-within *){opacity:1}@media (hover:hover){.ui\:group-hover\:translate-x-0\.5:is(:where(.ui\:group):hover *){--tw-translate-x:calc(var(--ui-spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:group-hover\:scale-\[1\.02\]:is(:where(.ui\:group):hover *){scale:1.02}.ui\:group-hover\:bg-\[var\(--landing-accent\)\]:is(:where(.ui\:group):hover *){background-color:var(--landing-accent)}.ui\:group-hover\:bg-muted-foreground\/15:is(:where(.ui\:group):hover *){background-color:var(--muted-foreground)}@supports (color:color-mix(in lab, red, red)){.ui\:group-hover\:bg-muted-foreground\/15:is(:where(.ui\:group):hover *){background-color:color-mix(in oklab, var(--muted-foreground) 15%, transparent)}}.ui\:group-hover\:bg-secondary\/80:is(:where(.ui\:group):hover *){background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.ui\:group-hover\:bg-secondary\/80:is(:where(.ui\:group):hover *){background-color:color-mix(in oklab, var(--secondary) 80%, transparent)}}.ui\:group-hover\:text-\[var\(--landing-accent\)\]:is(:where(.ui\:group):hover *){color:var(--landing-accent)}.ui\:group-hover\:text-\[var\(--landing-accent-fg\)\]:is(:where(.ui\:group):hover *){color:var(--landing-accent-fg)}.ui\:group-hover\:text-foreground:is(:where(.ui\:group):hover *){color:var(--foreground)}.ui\:group-hover\:text-primary:is(:where(.ui\:group):hover *){color:var(--primary)}.ui\:group-hover\:opacity-100:is(:where(.ui\:group):hover *){opacity:1}.ui\:group-hover\:shadow-\[inset_0_-6px_10px_\#ffffff3f\]:is(:where(.ui\:group):hover *){--tw-shadow:inset 0 -6px 10px var(--tw-shadow-color,#ffffff3f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:group-hover\/menu-item\:opacity-100:is(:where(.ui\:group\/menu-item):hover *){opacity:1}}.ui\:group-focus-visible\:opacity-100:is(:where(.ui\:group):focus-visible *){opacity:1}.ui\:group-active\:shadow-\[inset_0_-10px_10px_\#ffffff3f\]:is(:where(.ui\:group):active *){--tw-shadow:inset 0 -10px 10px var(--tw-shadow-color,#ffffff3f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:group-has-data-\[orientation\=horizontal\]\/field\:text-balance:is(:where(.ui\:group\/field):has([data-orientation=horizontal]) *){text-wrap:balance}.ui\:group-has-data-\[sidebar\=menu-action\]\/menu-item\:pr-8:is(:where(.ui\:group\/menu-item):has([data-sidebar=menu-action]) *){padding-right:calc(var(--ui-spacing) * 8)}.ui\:group-has-\[\[data-slot\=item-description\]\]\/item\:translate-y-0\.5:is(:where(.ui\:group\/item):has([data-slot=item-description]) *){--tw-translate-y:calc(var(--ui-spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:group-has-\[\[data-slot\=item-description\]\]\/item\:self-start:is(:where(.ui\:group\/item):has([data-slot=item-description]) *){align-self:flex-start}.ui\:group-has-\[\>input\]\/input-group\:pt-2\.5:is(:where(.ui\:group\/input-group):has(>input) *){padding-top:calc(var(--ui-spacing) * 2.5)}.ui\:group-has-\[\>input\]\/input-group\:pb-2\.5:is(:where(.ui\:group\/input-group):has(>input) *){padding-bottom:calc(var(--ui-spacing) * 2.5)}.ui\:group-aria-disabled\/file-drop-zone-trigger\:opacity-50:is(:where(.ui\:group\/file-drop-zone-trigger)[aria-disabled=true] *){opacity:.5}.ui\:group-data-\[collapsible\=icon\]\:pointer-events-none:is(:where(.ui\:group)[data-collapsible=icon] *){pointer-events:none}.ui\:group-data-\[collapsible\=icon\]\:-mt-8:is(:where(.ui\:group)[data-collapsible=icon] *){margin-top:calc(var(--ui-spacing) * -8)}.ui\:group-data-\[collapsible\=icon\]\:hidden:is(:where(.ui\:group)[data-collapsible=icon] *){display:none}.ui\:group-data-\[collapsible\=icon\]\:size-8\!:is(:where(.ui\:group)[data-collapsible=icon] *){width:calc(var(--ui-spacing) * 8)!important;height:calc(var(--ui-spacing) * 8)!important}.ui\:group-data-\[collapsible\=icon\]\:w-\(--sidebar-width-icon\):is(:where(.ui\:group)[data-collapsible=icon] *){width:var(--sidebar-width-icon)}.ui\:group-data-\[collapsible\=icon\]\:w-\[calc\(var\(--sidebar-width-icon\)\+\(--spacing\(4\)\)\+2px\)\]:is(:where(.ui\:group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--ui-spacing) * 4)) + 2px)}.ui\:group-data-\[collapsible\=icon\]\:overflow-hidden:is(:where(.ui\:group)[data-collapsible=icon] *){overflow:hidden}.ui\:group-data-\[collapsible\=icon\]\:p-0\!:is(:where(.ui\:group)[data-collapsible=icon] *){padding:calc(var(--ui-spacing) * 0)!important}.ui\:group-data-\[collapsible\=icon\]\:p-2\!:is(:where(.ui\:group)[data-collapsible=icon] *){padding:calc(var(--ui-spacing) * 2)!important}.ui\:group-data-\[collapsible\=icon\]\:opacity-0:is(:where(.ui\:group)[data-collapsible=icon] *){opacity:0}.ui\:group-data-\[collapsible\=offcanvas\]\:right-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.ui\:group)[data-collapsible=offcanvas] *){right:calc(var(--sidebar-width) * -1)}.ui\:group-data-\[collapsible\=offcanvas\]\:left-\[calc\(var\(--sidebar-width\)\*-1\)\]:is(:where(.ui\:group)[data-collapsible=offcanvas] *){left:calc(var(--sidebar-width) * -1)}.ui\:group-data-\[collapsible\=offcanvas\]\:w-0:is(:where(.ui\:group)[data-collapsible=offcanvas] *){width:calc(var(--ui-spacing) * 0)}.ui\:group-data-\[collapsible\=offcanvas\]\:translate-x-0:is(:where(.ui\:group)[data-collapsible=offcanvas] *){--tw-translate-x:calc(var(--ui-spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:group-data-\[disabled\=true\]\:pointer-events-none:is(:where(.ui\:group)[data-disabled=true] *){pointer-events:none}.ui\:group-data-\[disabled\=true\]\:opacity-50:is(:where(.ui\:group)[data-disabled=true] *),.ui\:group-data-\[disabled\=true\]\/field\:opacity-50:is(:where(.ui\:group\/field)[data-disabled=true] *),.ui\:group-data-\[disabled\=true\]\/input-group\:opacity-50:is(:where(.ui\:group\/input-group)[data-disabled=true] *){opacity:.5}.ui\:group-data-\[side\=left\]\:-right-4:is(:where(.ui\:group)[data-side=left] *){right:calc(var(--ui-spacing) * -4)}.ui\:group-data-\[side\=left\]\:border-r:is(:where(.ui\:group)[data-side=left] *){border-right-style:var(--tw-border-style);border-right-width:1px}.ui\:group-data-\[side\=right\]\:left-0:is(:where(.ui\:group)[data-side=right] *){left:calc(var(--ui-spacing) * 0)}.ui\:group-data-\[side\=right\]\:rotate-180:is(:where(.ui\:group)[data-side=right] *){rotate:180deg}.ui\:group-data-\[side\=right\]\:border-l:is(:where(.ui\:group)[data-side=right] *){border-left-style:var(--tw-border-style);border-left-width:1px}.ui\:group-data-\[state\=open\]\:rotate-180:is(:where(.ui\:group)[data-state=open] *){rotate:180deg}.ui\:group-data-\[variant\=floating\]\:rounded-lg:is(:where(.ui\:group)[data-variant=floating] *){border-radius:var(--radius)}.ui\:group-data-\[variant\=floating\]\:border:is(:where(.ui\:group)[data-variant=floating] *){border-style:var(--tw-border-style);border-width:1px}.ui\:group-data-\[variant\=floating\]\:border-sidebar-border:is(:where(.ui\:group)[data-variant=floating] *){border-color:var(--sidebar-border)}.ui\:group-data-\[variant\=floating\]\:shadow-sm:is(:where(.ui\:group)[data-variant=floating] *){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:group-data-\[variant\=outline\]\/field-group\:-mb-2:is(:where(.ui\:group\/field-group)[data-variant=outline] *){margin-bottom:calc(var(--ui-spacing) * -2)}.ui\:group-data-\[vaul-drawer-direction\=bottom\]\/drawer-content\:block:is(:where(.ui\:group\/drawer-content)[data-vaul-drawer-direction=bottom] *){display:block}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:top-full:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){top:100%}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:mt-1\.5:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){margin-top:calc(var(--ui-spacing) * 1.5)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:overflow-hidden:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){overflow:hidden}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:rounded-md:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){border-radius:calc(var(--radius) - 2px)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:border:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){border-style:var(--tw-border-style);border-width:1px}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:bg-popover:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){background-color:var(--popover)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:text-popover-foreground:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){color:var(--popover-foreground)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:shadow:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:duration-200:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *){--tw-duration:.2s;transition-duration:.2s}@media (hover:hover){.ui\:peer-hover\/menu-button\:text-sidebar-accent-foreground:is(:where(.ui\:peer\/menu-button):hover~*){color:var(--sidebar-accent-foreground)}}.ui\:peer-focus-visible\:opacity-100:is(:where(.ui\:peer):focus-visible~*){opacity:1}.ui\:peer-disabled\:cursor-not-allowed:is(:where(.ui\:peer):disabled~*){cursor:not-allowed}.ui\:peer-disabled\:opacity-50:is(:where(.ui\:peer):disabled~*){opacity:.5}.ui\:peer-data-\[active\=true\]\/menu-button\:text-sidebar-accent-foreground:is(:where(.ui\:peer\/menu-button)[data-active=true]~*){color:var(--sidebar-accent-foreground)}.ui\:peer-data-\[size\=default\]\/menu-button\:top-1\.5:is(:where(.ui\:peer\/menu-button)[data-size=default]~*){top:calc(var(--ui-spacing) * 1.5)}.ui\:peer-data-\[size\=lg\]\/menu-button\:top-2\.5:is(:where(.ui\:peer\/menu-button)[data-size=lg]~*){top:calc(var(--ui-spacing) * 2.5)}.ui\:peer-data-\[size\=sm\]\/menu-button\:top-1:is(:where(.ui\:peer\/menu-button)[data-size=sm]~*){top:calc(var(--ui-spacing) * 1)}.ui\:first-letter\:float-left:first-letter{float:left}.ui\:first-letter\:mr-2:first-letter{margin-right:calc(var(--ui-spacing) * 2)}.ui\:first-letter\:text-5xl:first-letter{font-size:var(--ui-text-5xl);line-height:var(--tw-leading,var(--ui-text-5xl--line-height))}.ui\:first-letter\:leading-none:first-letter{--tw-leading:1;line-height:1}.ui\:first-letter\:\[font-weight\:var\(--landing-heading-weight\)\]:first-letter{font-weight:var(--landing-heading-weight)}.ui\:first-letter\:text-\[var\(--landing-accent\)\]:first-letter{color:var(--landing-accent)}.ui\:selection\:bg-primary ::selection{background-color:var(--primary)}.ui\:selection\:bg-primary::selection{background-color:var(--primary)}.ui\:selection\:text-primary-foreground ::selection{color:var(--primary-foreground)}.ui\:selection\:text-primary-foreground::selection{color:var(--primary-foreground)}.ui\:placeholder\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.ui\:before\:mr-1:before{content:var(--tw-content);margin-right:calc(var(--ui-spacing) * 1)}.ui\:before\:size-1\.5:before{content:var(--tw-content);width:calc(var(--ui-spacing) * 1.5);height:calc(var(--ui-spacing) * 1.5)}.ui\:before\:rounded-full:before{content:var(--tw-content);border-radius:3.40282e38px}.ui\:before\:bg-\[var\(--landing-accent\)\]:before{content:var(--tw-content);background-color:var(--landing-accent)}.ui\:before\:text-2xl:before{content:var(--tw-content);font-size:var(--ui-text-2xl);line-height:var(--tw-leading,var(--ui-text-2xl--line-height))}.ui\:before\:text-\[var\(--landing-accent\)\]:before{content:var(--tw-content);color:var(--landing-accent)}.ui\:before\:content-\[\"\"\]:before{--tw-content:"";content:var(--tw-content)}.ui\:before\:content-\[\"“\"\]:before{--tw-content:"“";content:var(--tw-content)}.ui\:after\:absolute:after{content:var(--tw-content);position:absolute}.ui\:after\:-inset-2:after{content:var(--tw-content);inset:calc(var(--ui-spacing) * -2)}.ui\:after\:inset-y-0:after{content:var(--tw-content);inset-block:calc(var(--ui-spacing) * 0)}.ui\:after\:left-\[calc\(1\/2\*100\%-1px\)\]:after{content:var(--tw-content);left:calc(50% - 1px)}.ui\:after\:w-\[2px\]:after{content:var(--tw-content);width:2px}.ui\:group-data-\[collapsible\=offcanvas\]\:after\:left-full:is(:where(.ui\:group)[data-collapsible=offcanvas] *):after{content:var(--tw-content);left:100%}.ui\:first\:border-t-0:first-child{border-top-style:var(--tw-border-style);border-top-width:0}.ui\:last\:mt-0:last-child{margin-top:calc(var(--ui-spacing) * 0)}.ui\:last\:border-b:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.ui\:last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.ui\:focus-within\:border-ring:focus-within{border-color:var(--ring)}.ui\:focus-within\:ring-\[3px\]:focus-within{--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)}.ui\:focus-within\:ring-ring\/50:focus-within{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.ui\:focus-within\:ring-ring\/50:focus-within{--tw-ring-color:color-mix(in oklab, var(--ring) 50%, transparent)}}@media (hover:hover){.ui\:hover\:-translate-y-0\.5:hover{--tw-translate-y:calc(var(--ui-spacing) * -.5);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:hover\:-translate-y-1:hover{--tw-translate-y:calc(var(--ui-spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:hover\:cursor-pointer:hover{cursor:pointer}.ui\:hover\:border:hover{border-style:var(--tw-border-style);border-width:1px}.ui\:hover\:border-\[var\(--landing-accent\)\]:hover{border-color:var(--landing-accent)}.ui\:hover\:border-\[var\(--landing-accent-fg\)\]\/30:hover{border-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:border-\[var\(--landing-accent-fg\)\]\/30:hover{border-color:color-mix(in oklab, var(--landing-accent-fg) 30%, transparent)}}.ui\:hover\:border-\[var\(--landing-bg\)\]\/60:hover{border-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:border-\[var\(--landing-bg\)\]\/60:hover{border-color:color-mix(in oklab, var(--landing-bg) 60%, transparent)}}.ui\:hover\:border-\[var\(--landing-border\)\]:hover{border-color:var(--landing-border)}.ui\:hover\:border-\[var\(--landing-fg\)\]\/30:hover{border-color:var(--landing-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:border-\[var\(--landing-fg\)\]\/30:hover{border-color:color-mix(in oklab, var(--landing-fg) 30%, transparent)}}.ui\:hover\:border-primary\/40:hover{border-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:border-primary\/40:hover{border-color:color-mix(in oklab, var(--primary) 40%, transparent)}}.ui\:hover\:bg-\[\#2c2b29\]:hover{background-color:#2c2b29}.ui\:hover\:bg-\[\#14171f\]:hover{background-color:#14171f}.ui\:hover\:bg-\[\#e2e1d9\]:hover{background-color:#e2e1d9}.ui\:hover\:bg-\[\#ebeae3\]:hover{background-color:#ebeae3}.ui\:hover\:bg-\[var\(--landing-accent\)\]:hover,.ui\:hover\:bg-\[var\(--landing-accent\)\]\/90:hover{background-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-accent\)\]\/90:hover{background-color:color-mix(in oklab, var(--landing-accent) 90%, transparent)}}.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/5:hover{background-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/5:hover{background-color:color-mix(in oklab, var(--landing-accent-fg) 5%, transparent)}}.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/10:hover{background-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/10:hover{background-color:color-mix(in oklab, var(--landing-accent-fg) 10%, transparent)}}.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/90:hover{background-color:var(--landing-accent-fg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-accent-fg\)\]\/90:hover{background-color:color-mix(in oklab, var(--landing-accent-fg) 90%, transparent)}}.ui\:hover\:bg-\[var\(--landing-bg\)\]\/10:hover{background-color:var(--landing-bg)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-bg\)\]\/10:hover{background-color:color-mix(in oklab, var(--landing-bg) 10%, transparent)}}.ui\:hover\:bg-\[var\(--landing-bg-section\)\]:hover{background-color:var(--landing-bg-section)}.ui\:hover\:bg-\[var\(--landing-button-primary-bg-hover\)\]:hover{background-color:var(--landing-button-primary-bg-hover)}.ui\:hover\:bg-\[var\(--landing-button-secondary-bg-hover\)\]:hover{background-color:var(--landing-button-secondary-bg-hover)}.ui\:hover\:bg-\[var\(--landing-button-tertiary-bg-hover\)\]:hover{background-color:var(--landing-button-tertiary-bg-hover)}.ui\:hover\:bg-\[var\(--landing-card\)\]:hover{background-color:var(--landing-card)}.ui\:hover\:bg-\[var\(--landing-card-soft\)\]:hover,.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/30:hover{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/30:hover{background-color:color-mix(in oklab, var(--landing-card-soft) 30%, transparent)}}.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/40:hover{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/40:hover{background-color:color-mix(in oklab, var(--landing-card-soft) 40%, transparent)}}.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/60:hover{background-color:var(--landing-card-soft)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-\[var\(--landing-card-soft\)\]\/60:hover{background-color:color-mix(in oklab, var(--landing-card-soft) 60%, transparent)}}.ui\:hover\:bg-\[var\(--landing-fg\)\]:hover{background-color:var(--landing-fg)}.ui\:hover\:bg-accent:hover,.ui\:hover\:bg-accent\/25:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-accent\/25:hover{background-color:color-mix(in oklab, var(--accent) 25%, transparent)}}.ui\:hover\:bg-accent\/50:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-accent\/50:hover{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}.ui\:hover\:bg-amber-500\/10:hover{background-color:var(--ui-color-amber-500)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-amber-500\/10:hover{background-color:color-mix(in oklab, var(--ui-color-amber-500) 10%, transparent)}}.ui\:hover\:bg-black\/20:hover{background-color:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-black\/20:hover{background-color:color-mix(in oklab, var(--ui-color-black) 20%, transparent)}}.ui\:hover\:bg-black\/80:hover{background-color:var(--ui-color-black)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-black\/80:hover{background-color:color-mix(in oklab, var(--ui-color-black) 80%, transparent)}}.ui\:hover\:bg-muted:hover,.ui\:hover\:bg-muted\/40:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-muted\/40:hover{background-color:color-mix(in oklab, var(--muted) 40%, transparent)}}.ui\:hover\:bg-muted\/50:hover{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-muted\/50:hover{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}.ui\:hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--primary) 90%, transparent)}}.ui\:hover\:bg-sidebar-accent:hover{background-color:var(--sidebar-accent)}.ui\:hover\:bg-transparent\!:hover{background-color:#0000!important}.ui\:hover\:bg-white:hover,.ui\:hover\:bg-white\/5:hover{background-color:var(--ui-color-white)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-white\/5:hover{background-color:color-mix(in oklab, var(--ui-color-white) 5%, transparent)}}.ui\:hover\:bg-white\/10:hover{background-color:var(--ui-color-white)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:bg-white\/10:hover{background-color:color-mix(in oklab, var(--ui-color-white) 10%, transparent)}}.ui\:hover\:text-\[\#1a1a1a\]:hover{color:#1a1a1a}.ui\:hover\:text-\[\#e9eaed\]:hover{color:#e9eaed}.ui\:hover\:text-\[var\(--landing-accent\)\]:hover{color:var(--landing-accent)}.ui\:hover\:text-\[var\(--landing-accent-fg\)\]:hover{color:var(--landing-accent-fg)}.ui\:hover\:text-\[var\(--landing-bg\)\]:hover{color:var(--landing-bg)}.ui\:hover\:text-\[var\(--landing-fg\)\]:hover{color:var(--landing-fg)}.ui\:hover\:text-\[var\(--landing-fg-muted\)\]:hover{color:var(--landing-fg-muted)}.ui\:hover\:text-accent-foreground:hover{color:var(--accent-foreground)}.ui\:hover\:text-foreground:hover{color:var(--foreground)}.ui\:hover\:text-muted-foreground:hover{color:var(--muted-foreground)}.ui\:hover\:text-primary:hover{color:var(--primary)}.ui\:hover\:text-sidebar-accent-foreground:hover{color:var(--sidebar-accent-foreground)}.ui\:hover\:underline:hover{text-decoration-line:underline}.ui\:hover\:opacity-90:hover{opacity:.9}.ui\:hover\:opacity-100:hover{opacity:1}.ui\:hover\:shadow-2xs:hover{--tw-shadow:0 1px var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:hover\:shadow-\[0_0_0_1px_var\(--sidebar-accent\)\]:hover{--tw-shadow:0 0 0 1px var(--tw-shadow-color,var(--sidebar-accent));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:hover\:shadow-xl:hover{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:hover\:ring-2:hover{--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)}.ui\:hover\:shadow-primary\/5:hover{--tw-shadow-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:shadow-primary\/5:hover{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--primary) 5%, transparent) var(--tw-shadow-alpha), transparent)}}.ui\:hover\:ring-primary\/40:hover{--tw-ring-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:hover\:ring-primary\/40:hover{--tw-ring-color:color-mix(in oklab, var(--primary) 40%, transparent)}}.ui\:hover\:ring-inset:hover{--tw-ring-inset:inset}.ui\:group-aria-disabled\/file-drop-zone-trigger\:hover\:cursor-not-allowed:is(:where(.ui\:group\/file-drop-zone-trigger)[aria-disabled=true] *):hover{cursor:not-allowed}.ui\:hover\:group-data-\[collapsible\=offcanvas\]\:bg-sidebar:hover:is(:where(.ui\:group)[data-collapsible=offcanvas] *){background-color:var(--sidebar)}.ui\:hover\:after\:bg-sidebar-border:hover:after{content:var(--tw-content);background-color:var(--sidebar-border)}}.ui\:focus\:bg-accent:focus{background-color:var(--accent)}.ui\:focus\:text-accent-foreground:focus{color:var(--accent-foreground)}.ui\: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)}.ui\:focus\:ring-ring:focus{--tw-ring-color:var(--ring)}.ui\:focus\:ring-offset-2:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ui\:focus\:outline-hidden:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.ui\:focus\:outline-hidden:focus{outline-offset:2px;outline:2px solid #0000}}.ui\:focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.ui\:focus-visible\:border-ring:focus-visible{border-color:var(--ring)}.ui\:focus-visible\:ring-0:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + 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)}.ui\:focus-visible\:ring-0\!:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor)!important;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)!important}.ui\:focus-visible\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:focus-visible\:ring-\[3px\]:focus-visible{--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)}.ui\:focus-visible\:ring-\[var\(--landing-accent\)\]\/50:focus-visible{--tw-ring-color:var(--landing-accent)}@supports (color:color-mix(in lab, red, red)){.ui\:focus-visible\:ring-\[var\(--landing-accent\)\]\/50:focus-visible{--tw-ring-color:color-mix(in oklab, var(--landing-accent) 50%, transparent)}}.ui\:focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:focus-visible\:ring-destructive\/20:focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.ui\:focus-visible\:ring-ring:focus-visible,.ui\:focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.ui\:focus-visible\:ring-ring\/50:focus-visible{--tw-ring-color:color-mix(in oklab, var(--ring) 50%, transparent)}}.ui\:focus-visible\:ring-offset-0\!:focus-visible{--tw-ring-offset-width:0px!important;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)!important}.ui\:focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ui\:focus-visible\:outline-hidden:focus-visible{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.ui\:focus-visible\:outline-hidden:focus-visible{outline-offset:2px;outline:2px solid #0000}}.ui\:focus-visible\:outline-1:focus-visible{outline-style:var(--tw-outline-style);outline-width:1px}.ui\:focus-visible\:outline-ring:focus-visible{outline-color:var(--ring)}.ui\:focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.ui\:active\:translate-y-px:active{--tw-translate-y:1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:active\:bg-sidebar-accent:active{background-color:var(--sidebar-accent)}.ui\:active\:text-sidebar-accent-foreground:active{color:var(--sidebar-accent-foreground)}.ui\:disabled\:pointer-events-none:disabled{pointer-events:none}.ui\:disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.ui\:disabled\:opacity-30:disabled{opacity:.3}.ui\:disabled\:opacity-40:disabled{opacity:.4}.ui\:disabled\:opacity-50:disabled{opacity:.5}:where([data-side=left]) .ui\:in-data-\[side\=left\]\:cursor-w-resize{cursor:w-resize}:where([data-side=right]) .ui\:in-data-\[side\=right\]\:cursor-e-resize{cursor:e-resize}:where([data-slot=tooltip-content]) .ui\:in-data-\[slot\=tooltip-content\]\:bg-background\/20{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){:where([data-slot=tooltip-content]) .ui\:in-data-\[slot\=tooltip-content\]\:bg-background\/20{background-color:color-mix(in oklab, var(--background) 20%, transparent)}}:where([data-slot=tooltip-content]) .ui\:in-data-\[slot\=tooltip-content\]\:text-background{color:var(--background)}.ui\:has-data-\[slot\=card-action\]\:grid-cols-\[1fr_auto\]:has([data-slot=card-action]){grid-template-columns:1fr auto}.ui\:has-data-\[state\=checked\]\:border-primary:has([data-state=checked]){border-color:var(--primary)}.ui\:has-data-\[state\=checked\]\:bg-primary\/5:has([data-state=checked]){background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:has-data-\[state\=checked\]\:bg-primary\/5:has([data-state=checked]){background-color:color-mix(in oklab, var(--primary) 5%, transparent)}}.ui\:has-data-\[variant\=inset\]\:bg-sidebar:has([data-variant=inset]){background-color:var(--sidebar)}.ui\:has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:border-ring:has([data-slot=input-group-control]:focus-visible){border-color:var(--ring)}.ui\:has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-\[3px\]:has([data-slot=input-group-control]:focus-visible){--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)}.ui\:has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-ring\/50:has([data-slot=input-group-control]:focus-visible){--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.ui\:has-\[\[data-slot\=input-group-control\]\:focus-visible\]\:ring-ring\/50:has([data-slot=input-group-control]:focus-visible){--tw-ring-color:color-mix(in oklab, var(--ring) 50%, transparent)}}.ui\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:border-destructive:has([data-slot][aria-invalid=true]){border-color:var(--destructive)}.ui\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/20:has([data-slot][aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/20:has([data-slot][aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.ui\:has-\[\>\[data-align\=block-end\]\]\:h-auto:has(>[data-align=block-end]){height:auto}.ui\:has-\[\>\[data-align\=block-end\]\]\:flex-col:has(>[data-align=block-end]){flex-direction:column}.ui\:has-\[\>\[data-align\=block-start\]\]\:h-auto:has(>[data-align=block-start]){height:auto}.ui\:has-\[\>\[data-align\=block-start\]\]\:flex-col:has(>[data-align=block-start]){flex-direction:column}.ui\:has-\[\>\[data-slot\=button-group\]\]\:gap-2:has(>[data-slot=button-group]){gap:calc(var(--ui-spacing) * 2)}.ui\:has-\[\>\[data-slot\=checkbox-group\]\]\:gap-3:has(>[data-slot=checkbox-group]){gap:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>\[data-slot\=field-content\]\]\:items-start:has(>[data-slot=field-content]){align-items:flex-start}.ui\:has-\[\>\[data-slot\=field\]\]\:w-full:has(>[data-slot=field]){width:100%}.ui\:has-\[\>\[data-slot\=field\]\]\:cursor-pointer:has(>[data-slot=field]){cursor:pointer}.ui\:has-\[\>\[data-slot\=field\]\]\:flex-col:has(>[data-slot=field]){flex-direction:column}.ui\:has-\[\>\[data-slot\=field\]\]\:rounded-md:has(>[data-slot=field]){border-radius:calc(var(--radius) - 2px)}.ui\:has-\[\>\[data-slot\=field\]\]\:border:has(>[data-slot=field]){border-style:var(--tw-border-style);border-width:1px}@media (hover:hover){.ui\:has-\[\>\[data-slot\=field\]\]\:hover\:bg-primary\/5:has(>[data-slot=field]):hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:has-\[\>\[data-slot\=field\]\]\:hover\:bg-primary\/5:has(>[data-slot=field]):hover{background-color:color-mix(in oklab, var(--primary) 5%, transparent)}}}.ui\:has-\[\>\[data-slot\=radio-group\]\]\:gap-3:has(>[data-slot=radio-group]){gap:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>button\]\:ms-\[-0\.45rem\]:has(>button){margin-inline-start:-.45rem}.ui\:has-\[\>button\]\:me-\[-0\.45rem\]:has(>button){margin-inline-end:-.45rem}.ui\:has-\[\>kbd\]\:ms-\[-0\.35rem\]:has(>kbd){margin-inline-start:-.35rem}.ui\:has-\[\>kbd\]\:me-\[-0\.35rem\]:has(>kbd){margin-inline-end:-.35rem}.ui\:has-\[\>svg\]\:grid-cols-\[calc\(var\(--spacing\)\*4\)_1fr\]:has(>svg){grid-template-columns:calc(var(--spacing) * 4) 1fr}.ui\:has-\[\>svg\]\:gap-x-3:has(>svg){column-gap:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>svg\]\:p-0:has(>svg){padding:calc(var(--ui-spacing) * 0)}.ui\:has-\[\>svg\]\:px-2:has(>svg){padding-inline:calc(var(--ui-spacing) * 2)}.ui\:has-\[\>svg\]\:px-2\.5:has(>svg){padding-inline:calc(var(--ui-spacing) * 2.5)}.ui\:has-\[\>svg\]\:px-3:has(>svg){padding-inline:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>svg\]\:px-4:has(>svg){padding-inline:calc(var(--ui-spacing) * 4)}.ui\:has-\[\>textarea\]\:h-auto:has(>textarea){height:auto}.ui\:aria-disabled\:pointer-events-none[aria-disabled=true]{pointer-events:none}.ui\:aria-disabled\:opacity-50[aria-disabled=true]{opacity:.5}.ui\:aria-invalid\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.ui\:aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:aria-invalid\:ring-destructive\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.ui\:aria-selected\:bg-accent[aria-selected=true]{background-color:var(--accent)}.ui\:aria-selected\:text-accent-foreground[aria-selected=true]{color:var(--accent-foreground)}:is(.ui\:\*\*\:data-command-group\:px-2 *)[data-command-group]{padding-inline:calc(var(--ui-spacing) * 2)}:is(.ui\:\*\*\:data-command-input\:h-12 *)[data-command-input]{height:calc(var(--ui-spacing) * 12)}:is(.ui\:\*\*\:data-command-item\:px-2 *)[data-command-item]{padding-inline:calc(var(--ui-spacing) * 2)}:is(.ui\:\*\*\:data-command-item\:py-3 *)[data-command-item]{padding-block:calc(var(--ui-spacing) * 3)}.ui\:data-disabled\:pointer-events-none[data-disabled]{pointer-events:none}.ui\:data-disabled\:cursor-not-allowed[data-disabled]{cursor:not-allowed}.ui\:data-disabled\:opacity-50[data-disabled]{opacity:.5}.ui\:data-highlighted\:bg-accent[data-highlighted]{background-color:var(--accent)}.ui\:data-highlighted\:text-accent-foreground[data-highlighted]{color:var(--accent-foreground)}.ui\:data-inset\:pl-8[data-inset]{padding-left:calc(var(--ui-spacing) * 8)}.ui\:data-placeholder\:text-muted-foreground[data-placeholder]{color:var(--muted-foreground)}.ui\:data-\[active\=true\]\:bg-accent\/50[data-active=true]{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui\:data-\[active\=true\]\:bg-accent\/50[data-active=true]{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}.ui\:data-\[active\=true\]\:bg-primary\/10[data-active=true]{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:data-\[active\=true\]\:bg-primary\/10[data-active=true]{background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.ui\:data-\[active\=true\]\:text-accent-foreground[data-active=true]{color:var(--accent-foreground)}.ui\:data-\[active\=true\]\:text-primary[data-active=true]{color:var(--primary)}@media (hover:hover){.ui\:data-\[active\=true\]\:hover\:bg-accent[data-active=true]:hover{background-color:var(--accent)}}.ui\:data-\[active\=true\]\:focus\:bg-accent[data-active=true]:focus{background-color:var(--accent)}.ui\:data-\[collapsed\=true\]\:max-h-\[300px\][data-collapsed=true]{max-height:300px}.ui\:data-\[current\=true\]\:bg-muted[data-current=true]{background-color:var(--muted)}.ui\:data-\[disabled\=true\]\:pointer-events-none[data-disabled=true]{pointer-events:none}.ui\:data-\[disabled\=true\]\:opacity-50[data-disabled=true]{opacity:.5}.ui\:data-\[inset\]\:pl-8[data-inset]{padding-left:calc(var(--ui-spacing) * 8)}.ui\:data-\[invalid\=true\]\:text-destructive[data-invalid=true]{color:var(--destructive)}.ui\:data-\[motion\=from-end\]\:slide-in-from-end-52[data-motion=from-end]:where(:dir(ltr),[dir=ltr]){--tw-enter-translate-x:calc(52*var(--spacing))}.ui\:data-\[motion\=from-end\]\:slide-in-from-end-52[data-motion=from-end]:where(:dir(rtl),[dir=rtl]),.ui\:data-\[motion\=from-start\]\:slide-in-from-start-52[data-motion=from-start]:where(:dir(ltr),[dir=ltr]){--tw-enter-translate-x:calc(52*var(--spacing)*-1)}.ui\:data-\[motion\=from-start\]\:slide-in-from-start-52[data-motion=from-start]:where(:dir(rtl),[dir=rtl]){--tw-enter-translate-x:calc(52*var(--spacing))}.ui\:data-\[motion\=to-end\]\:slide-out-to-end-52[data-motion=to-end]:where(:dir(ltr),[dir=ltr]){--tw-exit-translate-x:calc(52*var(--spacing))}.ui\:data-\[motion\=to-end\]\:slide-out-to-end-52[data-motion=to-end]:where(:dir(rtl),[dir=rtl]),.ui\:data-\[motion\=to-start\]\:slide-out-to-start-52[data-motion=to-start]:where(:dir(ltr),[dir=ltr]){--tw-exit-translate-x:calc(52*var(--spacing)*-1)}.ui\:data-\[motion\=to-start\]\:slide-out-to-start-52[data-motion=to-start]:where(:dir(rtl),[dir=rtl]){--tw-exit-translate-x:calc(52*var(--spacing))}.ui\:data-\[motion\^\=from-\]\:animate-in[data-motion^=from-]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[motion\^\=from-\]\:fade-in[data-motion^=from-]{--tw-enter-opacity:0}.ui\:data-\[motion\^\=to-\]\:animate-out[data-motion^=to-]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[motion\^\=to-\]\:fade-out[data-motion^=to-]{--tw-exit-opacity:0}.ui\:data-\[orientation\=horizontal\]\:h-px[data-orientation=horizontal]{height:1px}.ui\:data-\[orientation\=horizontal\]\:w-full[data-orientation=horizontal]{width:100%}.ui\:data-\[orientation\=vertical\]\:h-auto[data-orientation=vertical]{height:auto}.ui\:data-\[orientation\=vertical\]\:h-full[data-orientation=vertical]{height:100%}.ui\:data-\[orientation\=vertical\]\:w-px[data-orientation=vertical]{width:1px}.ui\:data-\[side\=bottom\]\:-translate-x-1\/2[data-side=bottom]{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=bottom\]\:-translate-y-\[calc\(-50\%\+1px\)\][data-side=bottom]{--tw-translate-y:calc(calc(-50% + 1px) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y:calc(var(--ui-spacing) * 1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=bottom\]\:slide-in-from-top-2[data-side=bottom]{--tw-enter-translate-y:calc(2*var(--spacing)*-1)}.ui\:data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x:calc(var(--ui-spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=left\]\:-translate-y-\[calc\(50\%-3px\)\][data-side=left]{--tw-translate-y:calc(calc(50% - 3px) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=left\]\:slide-in-from-end-2[data-side=left]:where(:dir(ltr),[dir=ltr]){--tw-enter-translate-x:calc(2*var(--spacing))}.ui\:data-\[side\=left\]\:slide-in-from-end-2[data-side=left]:where(:dir(rtl),[dir=rtl]){--tw-enter-translate-x:calc(2*var(--spacing)*-1)}.ui\:data-\[side\=left\]\:slide-in-from-right-2[data-side=left]{--tw-enter-translate-x:calc(2*var(--spacing))}.ui\:data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x:calc(var(--ui-spacing) * 1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=right\]\:translate-x-\[calc\(50\%\+2px\)\][data-side=right]{--tw-translate-x:calc(50% + 2px);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=right\]\:translate-y-1\/2[data-side=right]{--tw-translate-y:calc(1 / 2 * 100%);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=right\]\:slide-in-from-start-2[data-side=right]:where(:dir(ltr),[dir=ltr]){--tw-enter-translate-x:calc(2*var(--spacing)*-1)}.ui\:data-\[side\=right\]\:slide-in-from-start-2[data-side=right]:where(:dir(rtl),[dir=rtl]){--tw-enter-translate-x:calc(2*var(--spacing))}.ui\:data-\[side\=right\]\:slide-in-from-left-2[data-side=right]{--tw-enter-translate-x:calc(2*var(--spacing)*-1)}.ui\:data-\[side\=top\]\:translate-x-1\/2[data-side=top]{--tw-translate-x:calc(1 / 2 * 100%);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y:calc(var(--ui-spacing) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=top\]\:translate-y-\[calc\(-50\%\+2px\)\][data-side=top]{--tw-translate-y:calc(-50% + 2px);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[side\=top\]\:slide-in-from-bottom-2[data-side=top]{--tw-enter-translate-y:calc(2*var(--spacing))}.ui\:data-\[size\=default\]\:h-9[data-size=default]{height:calc(var(--ui-spacing) * 9)}.ui\:data-\[size\=sm\]\:h-8[data-size=sm]{height:calc(var(--ui-spacing) * 8)}.ui\:data-\[slot\=checkbox-group\]\:gap-3[data-slot=checkbox-group]{gap:calc(var(--ui-spacing) * 3)}:is(.ui\:\*\:data-\[slot\=field\]\:p-4>*)[data-slot=field]{padding:calc(var(--ui-spacing) * 4)}:is(.ui\:\*\:data-\[slot\=field-group\]\:gap-4>*)[data-slot=field-group]{gap:calc(var(--ui-spacing) * 4)}:is(.ui\:\*\*\:data-\[slot\=navigation-menu-link\]\:focus\:ring-0 *)[data-slot=navigation-menu-link]:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + 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)}:is(.ui\:\*\*\:data-\[slot\=navigation-menu-link\]\:focus\:outline-none *)[data-slot=navigation-menu-link]:focus{--tw-outline-style:none;outline-style:none}:is(.ui\:\*\*\:data-\[slot\=select-value\]\:line-clamp-1 *)[data-slot=select-value]{-webkit-line-clamp:1;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}:is(.ui\:\*\*\:data-\[slot\=select-value\]\:flex *)[data-slot=select-value]{display:flex}:is(.ui\:\*\*\:data-\[slot\=select-value\]\:items-center *)[data-slot=select-value]{align-items:center}:is(.ui\:\*\*\:data-\[slot\=select-value\]\:gap-2 *)[data-slot=select-value]{gap:calc(var(--ui-spacing) * 2)}.ui\:data-\[state\=active\]\:bg-background[data-state=active]{background-color:var(--background)}.ui\:data-\[state\=active\]\:text-foreground[data-state=active]{color:var(--foreground)}.ui\:data-\[state\=active\]\:shadow-sm[data-state=active]{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:data-\[state\=checked\]\:translate-x-\[calc\(100\%-2px\)\][data-state=checked]{--tw-translate-x:calc(100% - 2px);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[state\=checked\]\:border-primary[data-state=checked]{border-color:var(--primary)}.ui\:data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:var(--primary)}.ui\:data-\[state\=checked\]\:text-primary-foreground[data-state=checked]{color:var(--primary-foreground)}.ui\:data-\[state\=closed\]\:animate-accordion-up[data-state=closed]{animation:accordion-up var(--tw-animation-duration,var(--tw-duration,.2s))var(--tw-ease,ease-out)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=closed\]\:animate-out[data-state=closed]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=closed\]\:duration-300[data-state=closed]{--tw-duration:.3s;transition-duration:.3s}.ui\:data-\[state\=closed\]\:fade-out-0[data-state=closed]{--tw-exit-opacity:0}.ui\:data-\[state\=closed\]\:zoom-out-95[data-state=closed]{--tw-exit-scale:.95}.ui\:data-\[state\=closed\]\:slide-out-to-bottom[data-state=closed]{--tw-exit-translate-y:100%}.ui\:data-\[state\=closed\]\:slide-out-to-left[data-state=closed]{--tw-exit-translate-x:-100%}.ui\:data-\[state\=closed\]\:slide-out-to-right[data-state=closed]{--tw-exit-translate-x:100%}.ui\:data-\[state\=closed\]\:slide-out-to-top[data-state=closed]{--tw-exit-translate-y:-100%}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=closed\]\:animate-out:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=closed]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=closed\]\:fade-out-0:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=closed]{--tw-exit-opacity:0}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=closed\]\:zoom-out-95:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=closed]{--tw-exit-scale:.95}.ui\:data-\[state\=hidden\]\:animate-out[data-state=hidden]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=hidden\]\:fade-out[data-state=hidden]{--tw-exit-opacity:0}.ui\:data-\[state\=off\]\:text-muted-foreground[data-state=off]{color:var(--muted-foreground)}@media (hover:hover){.ui\:hover\:data-\[state\=off\]\:text-accent-foreground:hover[data-state=off]{color:var(--accent-foreground)}}.ui\:data-\[state\=on\]\:bg-accent[data-state=on]{background-color:var(--accent)}.ui\:data-\[state\=on\]\:bg-primary[data-state=on]{background-color:var(--primary)}.ui\:data-\[state\=on\]\:bg-transparent[data-state=on]{background-color:#0000}.ui\:data-\[state\=on\]\:text-accent-foreground[data-state=on]{color:var(--accent-foreground)}.ui\:data-\[state\=on\]\:text-muted-foreground[data-state=on]{color:var(--muted-foreground)}.ui\:data-\[state\=on\]\:text-primary-foreground[data-state=on]{color:var(--primary-foreground)}@media (hover:hover){.ui\:hover\:data-\[state\=on\]\:text-accent-foreground:hover[data-state=on]{color:var(--accent-foreground)}}.ui\:data-\[state\=open\]\:animate-accordion-down[data-state=open]{animation:accordion-down var(--tw-animation-duration,var(--tw-duration,.2s))var(--tw-ease,ease-out)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=open\]\:animate-in[data-state=open]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=open\]\:bg-accent[data-state=open],.ui\:data-\[state\=open\]\:bg-accent\/50[data-state=open]{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui\:data-\[state\=open\]\:bg-accent\/50[data-state=open]{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}.ui\:data-\[state\=open\]\:text-accent-foreground[data-state=open]{color:var(--accent-foreground)}.ui\:data-\[state\=open\]\:opacity-100[data-state=open]{opacity:1}.ui\:data-\[state\=open\]\:duration-500[data-state=open]{--tw-duration:.5s;transition-duration:.5s}.ui\:data-\[state\=open\]\:fade-in-0[data-state=open]{--tw-enter-opacity:0}.ui\:data-\[state\=open\]\:zoom-in-90[data-state=open]{--tw-enter-scale:.9}.ui\:data-\[state\=open\]\:zoom-in-95[data-state=open]{--tw-enter-scale:.95}.ui\:data-\[state\=open\]\:slide-in-from-bottom[data-state=open]{--tw-enter-translate-y:100%}.ui\:data-\[state\=open\]\:slide-in-from-left[data-state=open]{--tw-enter-translate-x:-100%}.ui\:data-\[state\=open\]\:slide-in-from-right[data-state=open]{--tw-enter-translate-x:100%}.ui\:data-\[state\=open\]\:slide-in-from-top[data-state=open]{--tw-enter-translate-y:-100%}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=open\]\:animate-in:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=open]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=open\]\:fade-in-0:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=open]{--tw-enter-opacity:0}.ui\:group-data-\[viewport\=false\]\/navigation-menu\:data-\[state\=open\]\:zoom-in-95:is(:where(.ui\:group\/navigation-menu)[data-viewport=false] *)[data-state=open]{--tw-enter-scale:.95}@media (hover:hover){.ui\:data-\[state\=open\]\:hover\:bg-accent[data-state=open]:hover{background-color:var(--accent)}.ui\:data-\[state\=open\]\:hover\:bg-sidebar-accent[data-state=open]:hover{background-color:var(--sidebar-accent)}.ui\:data-\[state\=open\]\:hover\:text-sidebar-accent-foreground[data-state=open]:hover{color:var(--sidebar-accent-foreground)}}.ui\:data-\[state\=open\]\:focus\:bg-accent[data-state=open]:focus{background-color:var(--accent)}.ui\:data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:var(--muted)}.ui\:data-\[state\=unchecked\]\:translate-x-0[data-state=unchecked]{--tw-translate-x:calc(var(--ui-spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:data-\[state\=unchecked\]\:bg-input[data-state=unchecked]{background-color:var(--input)}.ui\:data-\[state\=visible\]\:animate-in[data-state=visible]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.ui\:data-\[state\=visible\]\:fade-in[data-state=visible]{--tw-enter-opacity:0}.ui\:data-\[variant\=destructive\]\:text-destructive[data-variant=destructive]{color:var(--destructive)}.ui\:data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:data-\[variant\=destructive\]\:focus\:bg-destructive\/10[data-variant=destructive]:focus{background-color:color-mix(in oklab, var(--destructive) 10%, transparent)}}.ui\:data-\[variant\=destructive\]\:focus\:text-destructive[data-variant=destructive]:focus{color:var(--destructive)}.ui\:data-\[variant\=destructive\]\:data-highlighted\:bg-destructive\/10[data-variant=destructive][data-highlighted]{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:data-\[variant\=destructive\]\:data-highlighted\:bg-destructive\/10[data-variant=destructive][data-highlighted]{background-color:color-mix(in oklab, var(--destructive) 10%, transparent)}}.ui\:data-\[variant\=destructive\]\:data-highlighted\:text-destructive[data-variant=destructive][data-highlighted]{color:var(--destructive)}.ui\:data-\[variant\=label\]\:text-sm[data-variant=label]{font-size:var(--ui-text-sm);line-height:var(--tw-leading,var(--ui-text-sm--line-height))}.ui\:data-\[variant\=legend\]\:text-base[data-variant=legend]{font-size:var(--ui-text-base);line-height:var(--tw-leading,var(--ui-text-base--line-height))}.ui\:data-\[vaul-drawer-direction\=bottom\]\:inset-x-0[data-vaul-drawer-direction=bottom]{inset-inline:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=bottom\]\:bottom-0[data-vaul-drawer-direction=bottom]{bottom:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=bottom\]\:mt-24[data-vaul-drawer-direction=bottom]{margin-top:calc(var(--ui-spacing) * 24)}.ui\:data-\[vaul-drawer-direction\=bottom\]\:max-h-\[80vh\][data-vaul-drawer-direction=bottom]{max-height:80vh}.ui\:data-\[vaul-drawer-direction\=bottom\]\:rounded-t-lg[data-vaul-drawer-direction=bottom]{border-top-left-radius:var(--radius);border-top-right-radius:var(--radius)}.ui\:data-\[vaul-drawer-direction\=bottom\]\:border-t[data-vaul-drawer-direction=bottom]{border-top-style:var(--tw-border-style);border-top-width:1px}.ui\:data-\[vaul-drawer-direction\=left\]\:inset-y-0[data-vaul-drawer-direction=left]{inset-block:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=left\]\:start-0[data-vaul-drawer-direction=left]{inset-inline-start:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=left\]\:w-3\/4[data-vaul-drawer-direction=left]{width:75%}.ui\:data-\[vaul-drawer-direction\=left\]\:border-e[data-vaul-drawer-direction=left]{border-inline-end-style:var(--tw-border-style);border-inline-end-width:1px}.ui\:data-\[vaul-drawer-direction\=right\]\:inset-y-0[data-vaul-drawer-direction=right]{inset-block:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=right\]\:end-0[data-vaul-drawer-direction=right]{inset-inline-end:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=right\]\:w-3\/4[data-vaul-drawer-direction=right]{width:75%}.ui\:data-\[vaul-drawer-direction\=right\]\:border-s[data-vaul-drawer-direction=right]{border-inline-start-style:var(--tw-border-style);border-inline-start-width:1px}.ui\:data-\[vaul-drawer-direction\=top\]\:inset-x-0[data-vaul-drawer-direction=top]{inset-inline:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=top\]\:top-0[data-vaul-drawer-direction=top]{top:calc(var(--ui-spacing) * 0)}.ui\:data-\[vaul-drawer-direction\=top\]\:mb-24[data-vaul-drawer-direction=top]{margin-bottom:calc(var(--ui-spacing) * 24)}.ui\:data-\[vaul-drawer-direction\=top\]\:max-h-\[80vh\][data-vaul-drawer-direction=top]{max-height:80vh}.ui\:data-\[vaul-drawer-direction\=top\]\:rounded-b-lg[data-vaul-drawer-direction=top]{border-bottom-right-radius:var(--radius);border-bottom-left-radius:var(--radius)}.ui\:data-\[vaul-drawer-direction\=top\]\:border-b[data-vaul-drawer-direction=top]{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.ui\:nth-last-2\:-mt-1:nth-last-child(2){margin-top:calc(var(--ui-spacing) * -1)}@supports ((-webkit-backdrop-filter:var(--tw)) or (backdrop-filter:var(--tw))){.ui\:supports-\[backdrop-filter\]\:bg-background\/80{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.ui\:supports-\[backdrop-filter\]\:bg-background\/80{background-color:color-mix(in oklab, var(--background) 80%, transparent)}}}@media (min-width:40rem){.ui\:sm\:top-6{top:calc(var(--ui-spacing) * 6)}.ui\:sm\:bottom-6{bottom:calc(var(--ui-spacing) * 6)}.ui\:sm\:col-span-2{grid-column:span 2/span 2}.ui\:sm\:flex{display:flex}.ui\:sm\:inline-flex{display:inline-flex}.ui\:sm\:w-64{width:calc(var(--ui-spacing) * 64)}.ui\:sm\:max-w-lg{max-width:var(--ui-container-lg)}.ui\:sm\:max-w-sm{max-width:var(--ui-container-sm)}.ui\:sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ui\:sm\:flex-row{flex-direction:row}.ui\:sm\:items-center{align-items:center}.ui\:sm\:items-end{align-items:flex-end}.ui\:sm\:justify-between{justify-content:space-between}.ui\:sm\:justify-end{justify-content:flex-end}.ui\:sm\:gap-2\.5{gap:calc(var(--ui-spacing) * 2.5)}.ui\:sm\:gap-3{gap:calc(var(--ui-spacing) * 3)}.ui\:sm\:rounded-lg{border-radius:var(--radius)}.ui\:sm\:border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.ui\:sm\:p-6{padding:calc(var(--ui-spacing) * 6)}.ui\:sm\:px-6{padding-inline:calc(var(--ui-spacing) * 6)}.ui\:sm\:py-32{padding-block:calc(var(--ui-spacing) * 32)}.ui\:sm\:pr-2\.5{padding-right:calc(var(--ui-spacing) * 2.5)}.ui\:sm\:pl-2\.5{padding-left:calc(var(--ui-spacing) * 2.5)}.ui\:sm\:text-3xl{font-size:var(--ui-text-3xl);line-height:var(--tw-leading,var(--ui-text-3xl--line-height))}.ui\:sm\:text-5xl{font-size:var(--ui-text-5xl);line-height:var(--tw-leading,var(--ui-text-5xl--line-height))}.ui\:sm\:text-xl{font-size:var(--ui-text-xl);line-height:var(--tw-leading,var(--ui-text-xl--line-height))}.ui\:data-\[vaul-drawer-direction\=left\]\:sm\:max-w-sm[data-vaul-drawer-direction=left],.ui\:data-\[vaul-drawer-direction\=right\]\:sm\:max-w-sm[data-vaul-drawer-direction=right]{max-width:var(--ui-container-sm)}}@media (min-width:48rem){.ui\:md\:absolute{position:absolute}.ui\:md\:top-8{top:calc(var(--ui-spacing) * 8)}.ui\:md\:bottom-8{bottom:calc(var(--ui-spacing) * 8)}.ui\:md\:col-span-1{grid-column:span 1/span 1}.ui\:md\:col-span-4{grid-column:span 4/span 4}.ui\:md\:col-span-7{grid-column:span 7/span 7}.ui\:md\:col-start-9{grid-column-start:9}.ui\:md\:mx-0{margin-inline:calc(var(--ui-spacing) * 0)}.ui\:md\:mt-12{margin-top:calc(var(--ui-spacing) * 12)}.ui\:md\:mb-12{margin-bottom:calc(var(--ui-spacing) * 12)}.ui\:md\:block{display:block}.ui\:md\:flex{display:flex}.ui\:md\:size-\[1\.125rem\]{width:1.125rem;height:1.125rem}.ui\:md\:h-7{height:calc(var(--ui-spacing) * 7)}.ui\:md\:h-8{height:calc(var(--ui-spacing) * 8)}.ui\:md\:h-14{height:calc(var(--ui-spacing) * 14)}.ui\:md\:h-\[220px\]{height:220px}.ui\:md\:h-\[480px\]{height:480px}.ui\:md\:w-24{width:calc(var(--ui-spacing) * 24)}.ui\:md\:w-52{width:calc(var(--ui-spacing) * 52)}.ui\:md\:w-\[var\(--bits-navigation-menu-viewport-width\)\]{width:var(--bits-navigation-menu-viewport-width)}.ui\:md\:w-auto{width:auto}.ui\:md\:w-full{width:100%}.ui\:md\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ui\:md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ui\:md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.ui\:md\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.ui\:md\:grid-cols-\[1fr_2fr\]{grid-template-columns:1fr 2fr}.ui\:md\:grid-cols-\[180px_1fr\]{grid-template-columns:180px 1fr}.ui\:md\:grid-cols-\[260px_1fr\]{grid-template-columns:260px 1fr}.ui\:md\:grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.ui\:md\:grid-cols-\[minmax\(0\,1\.4fr\)_repeat\(auto-fit\,minmax\(140px\,1fr\)\)\]{grid-template-columns:minmax(0,1.4fr) repeat(auto-fit,minmax(140px,1fr))}.ui\:md\:grid-cols-\[minmax\(0\,220px\)_1fr\]{grid-template-columns:minmax(0,220px) 1fr}.ui\:md\:flex-col{flex-direction:column}.ui\:md\:flex-row{flex-direction:row}.ui\:md\:items-baseline{align-items:baseline}.ui\:md\:items-center{align-items:center}.ui\:md\:items-end{align-items:flex-end}.ui\:md\:items-start{align-items:flex-start}.ui\:md\:justify-between{justify-content:space-between}.ui\:md\:justify-center{justify-content:center}.ui\:md\:justify-end{justify-content:flex-end}.ui\:md\:gap-4{gap:calc(var(--ui-spacing) * 4)}.ui\:md\:gap-8{gap:calc(var(--ui-spacing) * 8)}.ui\:md\:gap-10{gap:calc(var(--ui-spacing) * 10)}.ui\:md\:gap-x-12{column-gap:calc(var(--ui-spacing) * 12)}.ui\:md\:gap-y-12{row-gap:calc(var(--ui-spacing) * 12)}.ui\:md\:self-auto{align-self:auto}.ui\:md\:overflow-x-auto{overflow-x:auto}.ui\:md\:overflow-x-visible{overflow-x:visible}.ui\:md\:overflow-y-visible{overflow-y:visible}.ui\:md\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.ui\:md\:border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.ui\:md\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.ui\:md\:border-border{border-color:var(--border)}.ui\:md\:p-6{padding:calc(var(--ui-spacing) * 6)}.ui\:md\:p-8{padding:calc(var(--ui-spacing) * 8)}.ui\:md\:p-12{padding:calc(var(--ui-spacing) * 12)}.ui\:md\:px-6{padding-inline:calc(var(--ui-spacing) * 6)}.ui\:md\:px-8{padding-inline:calc(var(--ui-spacing) * 8)}.ui\:md\:py-0{padding-block:calc(var(--ui-spacing) * 0)}.ui\:md\:py-1{padding-block:calc(var(--ui-spacing) * 1)}.ui\:md\:py-14{padding-block:calc(var(--ui-spacing) * 14)}.ui\:md\:py-16{padding-block:calc(var(--ui-spacing) * 16)}.ui\:md\:py-20{padding-block:calc(var(--ui-spacing) * 20)}.ui\:md\:py-24{padding-block:calc(var(--ui-spacing) * 24)}.ui\:md\:py-28{padding-block:calc(var(--ui-spacing) * 28)}.ui\:md\:py-32{padding-block:calc(var(--ui-spacing) * 32)}.ui\:md\:py-40{padding-block:calc(var(--ui-spacing) * 40)}.ui\:md\:pt-16{padding-top:calc(var(--ui-spacing) * 16)}.ui\:md\:pt-20{padding-top:calc(var(--ui-spacing) * 20)}.ui\:md\:pt-24{padding-top:calc(var(--ui-spacing) * 24)}.ui\:md\:pb-20{padding-bottom:calc(var(--ui-spacing) * 20)}.ui\:md\:pb-24{padding-bottom:calc(var(--ui-spacing) * 24)}.ui\:md\:pb-28{padding-bottom:calc(var(--ui-spacing) * 28)}.ui\:md\:pl-8{padding-left:calc(var(--ui-spacing) * 8)}.ui\:md\:text-right{text-align:right}.ui\:md\:text-2xl{font-size:var(--ui-text-2xl);line-height:var(--tw-leading,var(--ui-text-2xl--line-height))}.ui\:md\:text-3xl{font-size:var(--ui-text-3xl);line-height:var(--tw-leading,var(--ui-text-3xl--line-height))}.ui\:md\:text-4xl{font-size:var(--ui-text-4xl);line-height:var(--tw-leading,var(--ui-text-4xl--line-height))}.ui\:md\:text-5xl{font-size:var(--ui-text-5xl);line-height:var(--tw-leading,var(--ui-text-5xl--line-height))}.ui\:md\:text-6xl{font-size:var(--ui-text-6xl);line-height:var(--tw-leading,var(--ui-text-6xl--line-height))}.ui\:md\:text-7xl{font-size:var(--ui-text-7xl);line-height:var(--tw-leading,var(--ui-text-7xl--line-height))}.ui\:md\:text-lg{font-size:var(--ui-text-lg);line-height:var(--tw-leading,var(--ui-text-lg--line-height))}.ui\:md\:text-sm{font-size:var(--ui-text-sm);line-height:var(--tw-leading,var(--ui-text-sm--line-height))}.ui\:md\:text-xl{font-size:var(--ui-text-xl);line-height:var(--tw-leading,var(--ui-text-xl--line-height))}.ui\:md\:text-\[38px\]{font-size:38px}.ui\:md\:text-\[40px\]{font-size:40px}.ui\:md\:text-\[56px\]{font-size:56px}.ui\:md\:text-\[88px\]{font-size:88px}.ui\:md\:leading-20{--tw-leading:calc(var(--ui-spacing) * 20);line-height:calc(var(--ui-spacing) * 20)}.ui\:md\:opacity-0{opacity:0}.ui\:md\:peer-data-\[variant\=inset\]\:m-2:is(:where(.ui\:peer)[data-variant=inset]~*){margin:calc(var(--ui-spacing) * 2)}.ui\:md\:peer-data-\[variant\=inset\]\:ml-0:is(:where(.ui\:peer)[data-variant=inset]~*){margin-left:calc(var(--ui-spacing) * 0)}.ui\:md\:peer-data-\[variant\=inset\]\:rounded-xl:is(:where(.ui\:peer)[data-variant=inset]~*){border-radius:calc(var(--radius) + 4px)}.ui\:md\:peer-data-\[variant\=inset\]\:shadow-sm:is(:where(.ui\:peer)[data-variant=inset]~*){--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ui\:md\:peer-data-\[variant\=inset\]\:peer-data-\[state\=collapsed\]\:ml-2:is(:where(.ui\:peer)[data-variant=inset]~*):is(:where(.ui\:peer)[data-state=collapsed]~*){margin-left:calc(var(--ui-spacing) * 2)}.ui\:md\:after\:hidden:after{content:var(--tw-content);display:none}}@media (min-width:64rem){.ui\:lg\:block{display:block}.ui\:lg\:hidden{display:none}.ui\:lg\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.ui\:lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ui\:lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.ui\:lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.ui\:lg\:grid-cols-\[1\.15fr_1fr\]{grid-template-columns:1.15fr 1fr}.ui\:lg\:grid-cols-\[1fr_1\.05fr\]{grid-template-columns:1fr 1.05fr}.ui\:lg\:gap-14{gap:calc(var(--ui-spacing) * 14)}.ui\:lg\:gap-20{gap:calc(var(--ui-spacing) * 20)}.ui\:lg\:px-6{padding-inline:calc(var(--ui-spacing) * 6)}.ui\:lg\:px-8{padding-inline:calc(var(--ui-spacing) * 8)}.ui\:lg\:py-10{padding-block:calc(var(--ui-spacing) * 10)}.ui\:lg\:py-24{padding-block:calc(var(--ui-spacing) * 24)}.ui\:lg\:pb-12{padding-bottom:calc(var(--ui-spacing) * 12)}.ui\:lg\:text-4xl{font-size:var(--ui-text-4xl);line-height:var(--tw-leading,var(--ui-text-4xl--line-height))}.ui\:lg\:text-5xl{font-size:var(--ui-text-5xl);line-height:var(--tw-leading,var(--ui-text-5xl--line-height))}.ui\:lg\:text-6xl{font-size:var(--ui-text-6xl);line-height:var(--tw-leading,var(--ui-text-6xl--line-height))}.ui\:lg\:text-7xl{font-size:var(--ui-text-7xl);line-height:var(--tw-leading,var(--ui-text-7xl--line-height))}.ui\:lg\:text-xl{font-size:var(--ui-text-xl);line-height:var(--tw-leading,var(--ui-text-xl--line-height))}.ui\:lg\:text-\[22px\]{font-size:22px}.ui\:lg\:text-\[40px\]{font-size:40px}.ui\:lg\:text-\[56px\]{font-size:56px}.ui\:lg\:text-\[64px\]{font-size:64px}.ui\:lg\:text-\[80px\]{font-size:80px}.ui\:lg\:text-\[110px\]{font-size:110px}}@container field-group (min-width:28rem){.ui\:\@md\/field-group\:flex-row{flex-direction:row}.ui\:\@md\/field-group\:items-center{align-items:center}.ui\:\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:items-start:has(>[data-slot=field-content]){align-items:flex-start}}@container (min-width:32rem){.ui\:\@lg\:w-48{width:calc(var(--ui-spacing) * 48)}.ui\:\@lg\:shrink-0{flex-shrink:0}.ui\:\@lg\:flex-row{flex-direction:row}}@container (min-width:36rem){.ui\:\@xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@container (min-width:42rem){.ui\:\@2xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@container (min-width:56rem){.ui\:\@4xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}.ui\:dark\:scale-0:where(.dark,.dark *){--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x) var(--tw-scale-y)}.ui\:dark\:scale-100:where(.dark,.dark *){--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}.ui\:dark\:-rotate-90:where(.dark,.dark *){rotate:-90deg}.ui\:dark\:rotate-0:where(.dark,.dark *){rotate:none}.ui\:dark\:border-amber-900:where(.dark,.dark *){border-color:var(--ui-color-amber-900)}.ui\:dark\:border-input:where(.dark,.dark *){border-color:var(--input)}.ui\:dark\:border-sky-900:where(.dark,.dark *){border-color:var(--ui-color-sky-900)}.ui\:dark\:border-slate-800:where(.dark,.dark *){border-color:var(--ui-color-slate-800)}.ui\:dark\:border-zinc-700:where(.dark,.dark *){border-color:var(--ui-color-zinc-700)}.ui\:dark\:border-zinc-800:where(.dark,.dark *){border-color:var(--ui-color-zinc-800)}.ui\:dark\:bg-\[\#09090B\]:where(.dark,.dark *){background-color:#09090b}.ui\:dark\:bg-amber-500:where(.dark,.dark *){background-color:var(--ui-color-amber-500)}.ui\:dark\:bg-amber-950:where(.dark,.dark *){background-color:var(--ui-color-amber-950)}.ui\:dark\:bg-card\!:where(.dark,.dark *){background-color:var(--card)!important}.ui\:dark\:bg-destructive\/60:where(.dark,.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-destructive\/60:where(.dark,.dark *){background-color:color-mix(in oklab, var(--destructive) 60%, transparent)}}.ui\:dark\:bg-destructive\/70:where(.dark,.dark *){background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-destructive\/70:where(.dark,.dark *){background-color:color-mix(in oklab, var(--destructive) 70%, transparent)}}.ui\:dark\:bg-emerald-500:where(.dark,.dark *){background-color:var(--ui-color-emerald-500)}.ui\:dark\:bg-emerald-950\/20:where(.dark,.dark *){background-color:var(--ui-color-emerald-950)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-emerald-950\/20:where(.dark,.dark *){background-color:color-mix(in oklab, var(--ui-color-emerald-950) 20%, transparent)}}.ui\:dark\:bg-emerald-950\/30:where(.dark,.dark *){background-color:var(--ui-color-emerald-950)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-emerald-950\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--ui-color-emerald-950) 30%, transparent)}}.ui\:dark\:bg-input\/30:where(.dark,.dark *){background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-input\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--input) 30%, transparent)}}.ui\:dark\:bg-neutral-900:where(.dark,.dark *){background-color:var(--ui-color-neutral-900)}.ui\:dark\:bg-red-950\/30:where(.dark,.dark *){background-color:var(--ui-color-red-950)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:bg-red-950\/30:where(.dark,.dark *){background-color:color-mix(in oklab, var(--ui-color-red-950) 30%, transparent)}}.ui\:dark\:bg-sky-950:where(.dark,.dark *){background-color:var(--ui-color-sky-950)}.ui\:dark\:bg-slate-950:where(.dark,.dark *){background-color:var(--ui-color-slate-950)}.ui\:dark\:bg-transparent:where(.dark,.dark *){background-color:#0000}.ui\:dark\:bg-zinc-700:where(.dark,.dark *){background-color:var(--ui-color-zinc-700)}.ui\:dark\:via-white\/80:where(.dark,.dark *){--tw-gradient-via:var(--ui-color-white)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:via-white\/80:where(.dark,.dark *){--tw-gradient-via:color-mix(in oklab, var(--ui-color-white) 80%, transparent)}}.ui\:dark\:via-white\/80:where(.dark,.dark *){--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.ui\:dark\:fill-amber-400:where(.dark,.dark *){fill:var(--ui-color-amber-400)}.ui\:dark\:text-amber-50:where(.dark,.dark *){color:var(--ui-color-amber-50)}.ui\:dark\:text-amber-300:where(.dark,.dark *){color:var(--ui-color-amber-300)}.ui\:dark\:text-amber-400:where(.dark,.dark *){color:var(--ui-color-amber-400)}.ui\:dark\:text-amber-500\/40:where(.dark,.dark *){color:var(--ui-color-amber-500)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:text-amber-500\/40:where(.dark,.dark *){color:color-mix(in oklab, var(--ui-color-amber-500) 40%, transparent)}}.ui\:dark\:text-amber-950:where(.dark,.dark *){color:var(--ui-color-amber-950)}.ui\:dark\:text-emerald-950:where(.dark,.dark *){color:var(--ui-color-emerald-950)}.ui\:dark\:text-gray-700:where(.dark,.dark *){color:var(--ui-color-gray-700)}.ui\:dark\:text-muted-foreground:where(.dark,.dark *){color:var(--muted-foreground)}.ui\:dark\:text-neutral-400\/50:where(.dark,.dark *){color:var(--ui-color-neutral-400)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:text-neutral-400\/50:where(.dark,.dark *){color:color-mix(in oklab, var(--ui-color-neutral-400) 50%, transparent)}}.ui\:dark\:text-sky-50:where(.dark,.dark *){color:var(--ui-color-sky-50)}.ui\:dark\:text-white:where(.dark,.dark *){color:var(--ui-color-white)}.ui\:dark\:\[--dot-field-glow\:\#0a0a0a\]:where(.dark,.dark *){--dot-field-glow:#0a0a0a}@media (hover:hover){.ui\:dark\:hover\:border-input:where(.dark,.dark *):hover{border-color:var(--input)}.ui\:dark\:hover\:bg-input\/50:where(.dark,.dark *):hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:hover\:bg-input\/50:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--input) 50%, transparent)}}}.ui\:dark\:focus-visible\:ring-destructive\/40:where(.dark,.dark *):focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:focus-visible\:ring-destructive\/40:where(.dark,.dark *):focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}:where([data-slot=tooltip-content]) .ui\:dark\:in-data-\[slot\=tooltip-content\]\:bg-background\/10:where(.dark,.dark *){background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){:where([data-slot=tooltip-content]) .ui\:dark\:in-data-\[slot\=tooltip-content\]\:bg-background\/10:where(.dark,.dark *){background-color:color-mix(in oklab, var(--background) 10%, transparent)}}.ui\:dark\:has-data-\[state\=checked\]\:bg-primary\/10:where(.dark,.dark *):has([data-state=checked]){background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:has-data-\[state\=checked\]\:bg-primary\/10:where(.dark,.dark *):has([data-state=checked]){background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.ui\:dark\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/40:where(.dark,.dark *):has([data-slot][aria-invalid=true]){--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:has-\[\[data-slot\]\[aria-invalid\=true\]\]\:ring-destructive\/40:where(.dark,.dark *):has([data-slot][aria-invalid=true]){--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.ui\:dark\:aria-invalid\:ring-destructive\/40:where(.dark,.dark *)[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:aria-invalid\:ring-destructive\/40:where(.dark,.dark *)[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.ui\:dark\:data-\[active\=true\]\:bg-primary\/20:where(.dark,.dark *)[data-active=true]{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:data-\[active\=true\]\:bg-primary\/20:where(.dark,.dark *)[data-active=true]{background-color:color-mix(in oklab, var(--primary) 20%, transparent)}}.ui\:dark\:data-\[state\=active\]\:border-input:where(.dark,.dark *)[data-state=active]{border-color:var(--input)}.ui\:dark\:data-\[state\=active\]\:bg-input\/30:where(.dark,.dark *)[data-state=active]{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:data-\[state\=active\]\:bg-input\/30:where(.dark,.dark *)[data-state=active]{background-color:color-mix(in oklab, var(--input) 30%, transparent)}}.ui\:dark\:data-\[state\=active\]\:text-foreground:where(.dark,.dark *)[data-state=active]{color:var(--foreground)}.ui\:dark\:data-\[state\=checked\]\:bg-primary:where(.dark,.dark *)[data-state=checked]{background-color:var(--primary)}.ui\:dark\:data-\[state\=checked\]\:bg-primary-foreground:where(.dark,.dark *)[data-state=checked]{background-color:var(--primary-foreground)}.ui\:dark\:data-\[state\=unchecked\]\:bg-foreground:where(.dark,.dark *)[data-state=unchecked]{background-color:var(--foreground)}.ui\:dark\:data-\[state\=unchecked\]\:bg-input\/80:where(.dark,.dark *)[data-state=unchecked]{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:data-\[state\=unchecked\]\:bg-input\/80:where(.dark,.dark *)[data-state=unchecked]{background-color:color-mix(in oklab, var(--input) 80%, transparent)}}.ui\:dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive]:focus{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:data-\[variant\=destructive\]\:focus\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive]:focus{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.ui\:dark\:data-\[variant\=destructive\]\:data-highlighted\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive][data-highlighted]{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.ui\:dark\:data-\[variant\=destructive\]\:data-highlighted\:bg-destructive\/20:where(.dark,.dark *)[data-variant=destructive][data-highlighted]{background-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.ui\:\[\&_\.lc-area-path\]\:opacity-100 .lc-area-path{opacity:1}.ui\:\[\&_\.lc-axis-tick\]\:stroke-0 .lc-axis-tick{stroke-width:0}.ui\:\[\&_\.lc-axis-tick-label\]\:fill-muted-foreground .lc-axis-tick-label{fill:var(--muted-foreground)}.ui\:\[\&_\.lc-axis-tick-label\]\:font-normal .lc-axis-tick-label{--tw-font-weight:var(--ui-font-weight-normal);font-weight:var(--ui-font-weight-normal)}.ui\:\[\&_\.lc-grid-x-radial-circle\]\:stroke-border .lc-grid-x-radial-circle,.ui\:\[\&_\.lc-grid-x-radial-line\]\:stroke-border .lc-grid-x-radial-line,.ui\:\[\&_\.lc-grid-y-radial-circle\]\:stroke-border .lc-grid-y-radial-circle,.ui\:\[\&_\.lc-grid-y-radial-line\]\:stroke-border .lc-grid-y-radial-line{stroke:var(--border)}.ui\:\[\&_\.lc-highlight-line\]\:stroke-0 .lc-highlight-line{stroke-width:0}.ui\:\[\&_\.lc-highlight-line\]\:opacity-100 .lc-highlight-line,.ui\:\[\&_\.lc-highlight-point\]\:opacity-100 .lc-highlight-point{opacity:1}.ui\:\[\&_\.lc-labels-text\:not\(\[fill\]\)\]\:fill-foreground .lc-labels-text:not([fill]){fill:var(--foreground)}.ui\:\[\&_\.lc-layout-svg-g\]\:fill-transparent .lc-layout-svg-g{fill:#0000}.ui\:\[\&_\.lc-legend-swatch\]\:size-2\.5 .lc-legend-swatch{width:calc(var(--ui-spacing) * 2.5);height:calc(var(--ui-spacing) * 2.5)}.ui\:\[\&_\.lc-legend-swatch\]\:rounded-\[2px\] .lc-legend-swatch{border-radius:2px}.ui\:\[\&_\.lc-legend-swatch-button\]\:items-center .lc-legend-swatch-button{align-items:center}.ui\:\[\&_\.lc-legend-swatch-button\]\:gap-1\.5 .lc-legend-swatch-button{gap:calc(var(--ui-spacing) * 1.5)}.ui\:\[\&_\.lc-legend-swatch-group\]\:items-center .lc-legend-swatch-group{align-items:center}.ui\:\[\&_\.lc-legend-swatch-group\]\:gap-4 .lc-legend-swatch-group{gap:calc(var(--ui-spacing) * 4)}.ui\:\[\&_\.lc-line\]\:stroke-border\/50 .lc-line{stroke:var(--border)}@supports (color:color-mix(in lab, red, red)){.ui\:\[\&_\.lc-line\]\:stroke-border\/50 .lc-line{stroke:color-mix(in oklab, var(--border) 50%, transparent)}}.ui\:\[\&_\.lc-root-container\]\:w-full .lc-root-container{width:100%}.ui\:\[\&_\.lc-rule-x-line\:not\(\.lc-grid-x-rule\)\]\:stroke-0 .lc-rule-x-line:not(.lc-grid-x-rule),.ui\:\[\&_\.lc-rule-y-line\:not\(\.lc-grid-y-rule\)\]\:stroke-0 .lc-rule-y-line:not(.lc-grid-y-rule){stroke-width:0}.ui\:\[\&_\.lc-spline-path\]\:opacity-100 .lc-spline-path{opacity:1}.ui\:\[\&_\.lc-text\]\:text-xs .lc-text{font-size:var(--ui-text-xs);line-height:var(--tw-leading,var(--ui-text-xs--line-height))}.ui\:\[\&_\.lc-text-svg\]\:overflow-visible .lc-text-svg{overflow:visible}.ui\:\[\&_\.lc-tooltip-rects-g\]\:fill-transparent .lc-tooltip-rects-g{fill:#0000}.ui\:\[\&_\.stroke-white\]\:stroke-transparent .stroke-white{stroke:#0000}.ui\:\[\&_\[data-command-group\]\:not\(\[hidden\]\)_\~\[data-command-group\]\]\:pt-0 [data-command-group]:not([hidden])~[data-command-group]{padding-top:calc(var(--ui-spacing) * 0)}.ui\:\[\&_\[data-command-input-wrapper\]_svg\]\:h-5 [data-command-input-wrapper] svg{height:calc(var(--ui-spacing) * 5)}.ui\:\[\&_\[data-command-input-wrapper\]_svg\]\:w-5 [data-command-input-wrapper] svg{width:calc(var(--ui-spacing) * 5)}.ui\:\[\&_\[data-command-item\]_svg\]\:h-5 [data-command-item] svg{height:calc(var(--ui-spacing) * 5)}.ui\:\[\&_\[data-command-item\]_svg\]\:w-5 [data-command-item] svg{width:calc(var(--ui-spacing) * 5)}.ui\:\[\&_img\]\:size-full img{width:100%;height:100%}.ui\:\[\&_img\]\:object-cover img{object-fit:cover}.ui\:\[\&_li\]\:mb-1 li{margin-bottom:calc(var(--ui-spacing) * 1)}.ui\:\[\&_p\]\:mb-2 p{margin-bottom:calc(var(--ui-spacing) * 2)}.ui\:\[\&_p\]\:leading-relaxed p{--tw-leading:var(--ui-leading-relaxed);line-height:var(--ui-leading-relaxed)}.ui\:\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.ui\:\[\&_svg\]\:size-8\! svg{width:calc(var(--ui-spacing) * 8)!important;height:calc(var(--ui-spacing) * 8)!important}.ui\:\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.ui\:\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-3 svg:not([class*=size-]){width:calc(var(--ui-spacing) * 3);height:calc(var(--ui-spacing) * 3)}.ui\:\[\&_svg\:not\(\[class\*\=\'size-\'\]\)\]\:size-4 svg:not([class*=size-]){width:calc(var(--ui-spacing) * 4);height:calc(var(--ui-spacing) * 4)}.ui\:\[\&_svg\:not\(\[class\*\=\'text-\'\]\)\]\:text-muted-foreground svg:not([class*=text-]){color:var(--muted-foreground)}.ui\:\[\&_svg\:not\(\[class\*\=\'ui\:size-\'\]\)\]\:size-4 svg:not([class*=ui\:size-]){width:calc(var(--ui-spacing) * 4);height:calc(var(--ui-spacing) * 4)}.ui\:\[\&_svg\:not\(\[class\*\=\'ui\:size-\'\]\)\]\:size-6 svg:not([class*=ui\:size-]){width:calc(var(--ui-spacing) * 6);height:calc(var(--ui-spacing) * 6)}.ui\:\[\&_text\]\:stroke-transparent text{stroke:#0000}.ui\:\[\&_tr\]\:border-b tr{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.ui\:\[\&_tr\:last-child\]\:border-0 tr:last-child{border-style:var(--tw-border-style);border-width:0}.ui\:\[\&_ul\]\:list-disc ul{list-style-type:disc}.ui\:\[\&_ul\]\:pl-5 ul{padding-left:calc(var(--ui-spacing) * 5)}.ui\:\[\&\+\[data-slot\=item-content\]\]\:flex-none+[data-slot=item-content]{flex:none}.ui\:\[\&\:has\(\[data-slot\=dialog-footer\]\[data-sticky\=true\]\)\]\:pb-0:has([data-slot=dialog-footer][data-sticky=true]){padding-bottom:calc(var(--ui-spacing) * 0)}.ui\:\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:calc(var(--ui-spacing) * 0)}.ui\:\[\.border-b\]\:pb-3.border-b{padding-bottom:calc(var(--ui-spacing) * 3)}.ui\:\[\.border-b\]\:pb-6.border-b{padding-bottom:calc(var(--ui-spacing) * 6)}.ui\:\[\.border-t\]\:pt-3.border-t{padding-top:calc(var(--ui-spacing) * 3)}.ui\:\[\.border-t\]\:pt-6.border-t{padding-top:calc(var(--ui-spacing) * 6)}.ui\:\[a\]\:transition-colors:is(a){transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--ui-default-transition-timing-function));transition-duration:var(--tw-duration,var(--ui-default-transition-duration))}@media (hover:hover){.ui\:\[a\]\:hover\:bg-accent\/50:is(a):hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.ui\:\[a\]\:hover\:bg-accent\/50:is(a):hover{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}}:is(.ui\:\*\:\[span\]\:last\:flex>*):is(span):last-child{display:flex}:is(.ui\:\*\:\[span\]\:last\:items-center>*):is(span):last-child{align-items:center}:is(.ui\:\*\:\[span\]\:last\:gap-2>*):is(span):last-child{gap:calc(var(--ui-spacing) * 2)}:is(.ui\:data-\[variant\=destructive\]\:\*\:\[svg\]\:text-destructive\![data-variant=destructive]>*):is(svg){color:var(--destructive)!important}.ui\:\[\&\>\*\]\:focus-visible\:relative>:focus-visible{position:relative}.ui\:\[\&\>\*\]\:focus-visible\:z-10>:focus-visible{z-index:10}@container field-group (min-width:28rem){.ui\:\@md\/field-group\:\[\&\>\*\]\:w-auto>*{width:auto}}.ui\:\[\&\>\*\:not\(\:first-child\)\]\:rounded-s-none>:not(:first-child){border-start-start-radius:0;border-end-start-radius:0}.ui\:\[\&\>\*\:not\(\:first-child\)\]\:rounded-t-none>:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.ui\:\[\&\>\*\:not\(\:first-child\)\]\:border-s-0>:not(:first-child){border-inline-start-style:var(--tw-border-style);border-inline-start-width:0}.ui\:\[\&\>\*\:not\(\:first-child\)\]\:border-t-0>:not(:first-child){border-top-style:var(--tw-border-style);border-top-width:0}.ui\:\[\&\>\*\:not\(\:last-child\)\]\:rounded-e-none>:not(:last-child){border-start-end-radius:0;border-end-end-radius:0}.ui\:\[\&\>\*\:not\(\:last-child\)\]\:rounded-b-none>:not(:last-child){border-bottom-right-radius:0;border-bottom-left-radius:0}.ui\:\[\&\>\[data-slot\=field-label\]\]\:flex-auto>[data-slot=field-label]{flex:auto}@container field-group (min-width:28rem){.ui\:\@md\/field-group\:\[\&\>\[data-slot\=field-label\]\]\:flex-auto>[data-slot=field-label]{flex:auto}}.ui\:has-\[select\[aria-hidden\=true\]\:last-child\]\:\[\&\>\[data-slot\=select-trigger\]\:last-of-type\]\:rounded-e-md:has(:is(select[aria-hidden=true]:last-child))>[data-slot=select-trigger]:last-of-type{border-start-end-radius:calc(var(--radius) - 2px);border-end-end-radius:calc(var(--radius) - 2px)}.ui\:\[\&\>\[data-slot\=select-trigger\]\:not\(\[class\*\=\'ui\:w-\'\]\)\]\:w-fit>[data-slot=select-trigger]:not([class*=ui\:w-]){width:fit-content}.ui\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content])>[role=checkbox],.ui\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content]) [role=radio]{margin-top:1px}@container field-group (min-width:28rem){.ui\:\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content])>[role=checkbox],.ui\:\@md\/field-group\:has-\[\>\[data-slot\=field-content\]\]\:\[\&\>\[role\=checkbox\]\,\[role\=radio\]\]\:mt-px:has(>[data-slot=field-content]) [role=radio]{margin-top:1px}}.ui\:\[\&\>a\]\:underline>a{text-decoration-line:underline}.ui\:\[\&\>a\]\:underline-offset-4>a{text-underline-offset:4px}.ui\:\[\&\>a\:hover\]\:text-primary>a:hover{color:var(--primary)}.ui\:\[\&\>button\]\:hidden>button{display:none}.ui\:\[\&\>input\]\:flex-1>input{flex:1}.ui\:has-\[\>\[data-align\=block-end\]\]\:\[\&\>input\]\:pt-3:has(>[data-align=block-end])>input{padding-top:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>\[data-align\=block-start\]\]\:\[\&\>input\]\:pb-3:has(>[data-align=block-start])>input{padding-bottom:calc(var(--ui-spacing) * 3)}.ui\:has-\[\>\[data-align\=inline-end\]\]\:\[\&\>input\]\:pe-2:has(>[data-align=inline-end])>input{padding-inline-end:calc(var(--ui-spacing) * 2)}.ui\:has-\[\>\[data-align\=inline-start\]\]\:\[\&\>input\]\:ps-2:has(>[data-align=inline-start])>input{padding-inline-start:calc(var(--ui-spacing) * 2)}.ui\:\[\&\>kbd\]\:rounded-\[calc\(var\(--radius\)-5px\)\]>kbd{border-radius:calc(var(--radius) - 5px)}.ui\:\[\&\>span\:last-child\]\:truncate>span:last-child{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ui\:\[\&\>svg\]\:pointer-events-none>svg{pointer-events:none}.ui\:\[\&\>svg\]\:size-2\.5>svg{width:calc(var(--ui-spacing) * 2.5);height:calc(var(--ui-spacing) * 2.5)}.ui\:\[\&\>svg\]\:size-3>svg{width:calc(var(--ui-spacing) * 3);height:calc(var(--ui-spacing) * 3)}.ui\:\[\&\>svg\]\:size-3\.5>svg{width:calc(var(--ui-spacing) * 3.5);height:calc(var(--ui-spacing) * 3.5)}.ui\:\[\&\>svg\]\:size-4>svg{width:calc(var(--ui-spacing) * 4);height:calc(var(--ui-spacing) * 4)}.ui\:\[\&\>svg\]\:shrink-0>svg{flex-shrink:0}.ui\:\[\&\>svg\]\:translate-y-0\.5>svg{--tw-translate-y:calc(var(--ui-spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.ui\:\[\&\>svg\]\:text-current>svg{color:currentColor}.ui\:\[\&\>svg\]\:text-muted-foreground>svg{color:var(--muted-foreground)}.ui\:\[\&\>svg\]\:text-sidebar-accent-foreground>svg{color:var(--sidebar-accent-foreground)}.ui\:data-\[active\=true\]\:\[\&\>svg\]\:text-primary[data-active=true]>svg{color:var(--primary)}.ui\:\[\&\>svg\:not\(\[class\*\=\'ui\:size-\'\]\)\]\:size-3\.5>svg:not([class*=ui\:size-]){width:calc(var(--ui-spacing) * 3.5);height:calc(var(--ui-spacing) * 3.5)}.ui\:\[\&\>svg\:not\(\[class\*\=\'ui\:size-\'\]\)\]\:size-4>svg:not([class*=ui\:size-]){width:calc(var(--ui-spacing) * 4);height:calc(var(--ui-spacing) * 4)}@media (hover:hover){:is(.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover,.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover>svelte-css-wrapper)>th,:is(.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover,.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover>svelte-css-wrapper) td{background-color:var(--muted)}@supports (color:color-mix(in lab, red, red)){:is(.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover,.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover>svelte-css-wrapper)>th,:is(.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover,.ui\:hover\:\[\&\,\&\>svelte-css-wrapper\]\:\[\&\>th\,td\]\:bg-muted\/50:hover>svelte-css-wrapper) td{background-color:color-mix(in oklab, var(--muted) 50%, transparent)}}}.ui\:\[\&\>tr\]\:last\:border-b-0>tr:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.ui\:\[\&\[data-state\=open\]\>svg\]\:rotate-180[data-state=open]>svg{rotate:180deg}.ui\:\[\&\[for\]\]\:cursor-pointer[for]{cursor:pointer}[data-side=left][data-collapsible=offcanvas] .ui\:\[\[data-side\=left\]\[data-collapsible\=offcanvas\]_\&\]\:-right-2{right:calc(var(--ui-spacing) * -2)}[data-side=left][data-state=collapsed] .ui\:\[\[data-side\=left\]\[data-state\=collapsed\]_\&\]\:cursor-e-resize{cursor:e-resize}[data-side=right][data-collapsible=offcanvas] .ui\:\[\[data-side\=right\]\[data-collapsible\=offcanvas\]_\&\]\:-left-2{left:calc(var(--ui-spacing) * -2)}[data-side=right][data-state=collapsed] .ui\:\[\[data-side\=right\]\[data-state\=collapsed\]_\&\]\:cursor-w-resize{cursor:w-resize}[data-variant=legend]+.ui\:\[\[data-variant\=legend\]\+\&\]\:-mt-1\.5{margin-top:calc(var(--ui-spacing) * -1.5)}@media (hover:hover){a.ui\:\[a\&\]\:hover\:bg-accent:hover{background-color:var(--accent)}a.ui\:\[a\&\]\:hover\:bg-amber-600\/90:hover{background-color:var(--ui-color-amber-600)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-amber-600\/90:hover{background-color:color-mix(in oklab, var(--ui-color-amber-600) 90%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-destructive\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-destructive\/90:hover{background-color:color-mix(in oklab, var(--destructive) 90%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-emerald-600\/90:hover{background-color:var(--ui-color-emerald-600)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-emerald-600\/90:hover{background-color:color-mix(in oklab, var(--ui-color-emerald-600) 90%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-primary\/30:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-primary\/30:hover{background-color:color-mix(in oklab, var(--primary) 30%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-primary\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-primary\/90:hover{background-color:color-mix(in oklab, var(--primary) 90%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-secondary\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-secondary\/80:hover{background-color:color-mix(in oklab, var(--secondary) 80%, transparent)}}a.ui\:\[a\&\]\:hover\:bg-secondary\/90:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){a.ui\:\[a\&\]\:hover\:bg-secondary\/90:hover{background-color:color-mix(in oklab, var(--secondary) 90%, transparent)}}a.ui\:\[a\&\]\:hover\:text-accent-foreground:hover{color:var(--accent-foreground)}a.ui\:\[a\&\]\:hover\:text-primary:hover{color:var(--primary)}a.ui\:\[a\&\]\:hover\:underline:hover{text-decoration-line:underline}a.ui\:dark\:\[a\&\]\:hover\:bg-accent\/50:where(.dark,.dark *):hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){a.ui\:dark\:\[a\&\]\:hover\:bg-accent\/50:where(.dark,.dark *):hover{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}}}@property --tw-animation-delay{syntax:"*";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:"*";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:"*";inherits:false}@property --tw-animation-fill-mode{syntax:"*";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-blur{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:"*";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:"*";inherits:false;initial-value:0}@keyframes border-beam{to{offset-distance:100%}}@keyframes meteor{0%{opacity:1;transform:rotate(215deg)translate(0)}70%{opacity:1}to{opacity:0;transform:rotate(215deg)translate(-500px)}}@keyframes shimmer-marketing{0%,90%,to{background-position:calc(-100% - var(--shimmer-width)) 0}30%,60%{background-position:calc(100% + var(--shimmer-width)) 0}}@keyframes spin-around{0%{transform:translateZ(0)rotate(0)}15%,35%{transform:translateZ(0)rotate(90deg)}65%,85%{transform:translateZ(0)rotate(270deg)}to{transform:translateZ(0)rotate(360deg)}}@keyframes magicslide{to{transform:translate(calc(100cqw - 100%))}}:root{--background:oklch(100% 0 0);--foreground:oklch(14.5% 0 0);--card:oklch(100% 0 0);--card-foreground:oklch(14.5% 0 0);--popover:oklch(100% 0 0);--popover-foreground:oklch(14.5% 0 0);--primary:oklch(48.8% .243 264.376);--primary-foreground:oklch(97% .014 254.604);--secondary:oklch(96.7% .001 286.375);--secondary-foreground:oklch(21% .006 285.885);--muted:oklch(97% 0 0);--muted-foreground:oklch(55.6% 0 0);--accent:oklch(97% 0 0);--accent-foreground:oklch(20.5% 0 0);--destructive:oklch(57.7% .245 27.325);--border:oklch(92.2% 0 0);--input:oklch(92.2% 0 0);--ring:oklch(70.8% 0 0);--chart-1:oklch(80.9% .105 251.813);--chart-2:oklch(62.3% .214 259.815);--chart-3:oklch(54.6% .245 262.881);--chart-4:oklch(48.8% .243 264.376);--chart-5:oklch(42.4% .199 265.638);--radius:.625rem;--sidebar:oklch(98.5% 0 0);--sidebar-foreground:oklch(14.5% 0 0);--sidebar-primary:oklch(54.6% .245 262.881);--sidebar-primary-foreground:oklch(97% .014 254.604);--sidebar-accent:oklch(97% 0 0);--sidebar-accent-foreground:oklch(20.5% 0 0);--sidebar-border:oklch(92.2% 0 0);--sidebar-ring:oklch(70.8% 0 0)}.dark{--background:oklch(14.5% 0 0);--foreground:oklch(98.5% 0 0);--card:oklch(20.5% 0 0);--card-foreground:oklch(98.5% 0 0);--popover:oklch(20.5% 0 0);--popover-foreground:oklch(98.5% 0 0);--primary:oklch(42.4% .199 265.638);--primary-foreground:oklch(97% .014 254.604);--secondary:oklch(27.4% .006 286.033);--secondary-foreground:oklch(98.5% 0 0);--muted:oklch(26.9% 0 0);--muted-foreground:oklch(70.8% 0 0);--accent:oklch(26.9% 0 0);--accent-foreground:oklch(98.5% 0 0);--destructive:oklch(70.4% .191 22.216);--border:oklch(100% 0 0/.1);--input:oklch(100% 0 0/.15);--ring:oklch(55.6% 0 0);--chart-1:oklch(80.9% .105 251.813);--chart-2:oklch(62.3% .214 259.815);--chart-3:oklch(54.6% .245 262.881);--chart-4:oklch(48.8% .243 264.376);--chart-5:oklch(42.4% .199 265.638);--sidebar:oklch(20.5% 0 0);--sidebar-foreground:oklch(98.5% 0 0);--sidebar-primary:oklch(62.3% .214 259.815);--sidebar-primary-foreground:oklch(97% .014 254.604);--sidebar-accent:oklch(26.9% 0 0);--sidebar-accent-foreground:oklch(98.5% 0 0);--sidebar-border:oklch(100% 0 0/.1);--sidebar-ring:oklch(55.6% 0 0)}@property --border-angle{syntax:"";inherits:false;initial-value:0deg}@keyframes border{to{--border-angle:360deg}}@keyframes flip{to{transform:rotate(360deg)}}@keyframes kitrotate{to{transform:rotate(90deg)}}@keyframes shine{0%{background-position:0 0}to{background-position:-200% 0}}.animate-gradient-border{background:linear-gradient(45deg, white, white) padding-box, conic-gradient(from var(--border-angle), #94a3b84d 75%, var(--primary,#1d4ee2) 82%, var(--primary-foreground,white) 88%, var(--primary,#1d4ee2) 92%, #94a3b84d 100%) border-box;border:1px solid #0000;transition:--border-angle 3s ease-in-out}.animate-gradient-border:hover{animation:4s ease-in-out infinite border}.dark.animate-gradient-border{background:linear-gradient(45deg, #000, #000) padding-box, conic-gradient(from var(--border-angle), #4755697a 75%, var(--primary,#1d4ee2) 82%, var(--primary-foreground,black) 88%, var(--primary,#1d4ee2) 92%, #4755697a 100%) border-box}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";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-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0)scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1))rotate(var(--tw-enter-rotate,0));filter:blur(var(--tw-enter-blur,0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity,1);transform:translate3d(var(--tw-exit-translate-x,0),var(--tw-exit-translate-y,0),0)scale3d(var(--tw-exit-scale,1),var(--tw-exit-scale,1),var(--tw-exit-scale,1))rotate(var(--tw-exit-rotate,0));filter:blur(var(--tw-exit-blur,0))}}@keyframes accordion-down{0%{height:0}to{height:var(--radix-accordion-content-height,var(--bits-accordion-content-height,var(--reka-accordion-content-height,var(--kb-accordion-content-height,var(--ngp-accordion-content-height,auto)))))}}@keyframes accordion-up{0%{height:var(--radix-accordion-content-height,var(--bits-accordion-content-height,var(--reka-accordion-content-height,var(--kb-accordion-content-height,var(--ngp-accordion-content-height,auto)))))}to{height:0}} \ No newline at end of file diff --git a/packages/utils/src/validation/course/course.ts b/packages/utils/src/validation/course/course.ts index 822c771d..73831da6 100644 --- a/packages/utils/src/validation/course/course.ts +++ b/packages/utils/src/validation/course/course.ts @@ -364,6 +364,8 @@ const ZCourseMetadataFields = z.object({ grading: z.boolean().optional(), lessonDownload: z.boolean().optional(), allowNewStudent: z.boolean(), + welcomeEmailMessage: z.string().max(20000).nullish(), + sessionTimezone: z.string().max(64).nullish(), sectionDisplay: z.record(z.string(), z.boolean()).optional(), isContentGroupingEnabled: z.boolean().optional(), progressionMode: z.enum(['free', 'sequential']).optional() diff --git a/packages/utils/src/validation/mail/mail.ts b/packages/utils/src/validation/mail/mail.ts index db087f23..be037d95 100644 --- a/packages/utils/src/validation/mail/mail.ts +++ b/packages/utils/src/validation/mail/mail.ts @@ -5,7 +5,9 @@ export const ZEmailData = z.object({ to: z.email(), subject: z.string().min(1), content: z.string().min(1), - replyTo: z.string().optional() + replyTo: z.string().optional(), + /** Optional iCalendar (.ics) body attached as a text/calendar part. */ + ics: z.string().optional() }); export type TEmailData = z.infer; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index edcb50ab..585e8d83 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4099,155 +4099,183 @@ packages: resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm64@1.2.4': resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} @@ -4792,48 +4820,56 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-arm64-musl@0.112.0': resolution: {integrity: sha512-3R0iqjM3xYOZCnwgcxOQXH7hrz64/USDIuLbNTM1kZqQzRqaR4w7SwoWKU934zABo8d0op2oSwOp+CV3hZnM7A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-ppc64-gnu@0.112.0': resolution: {integrity: sha512-lAQf8PQxfgy7h0bmcfSVE3hg3qMueshPYULFsCrHM+8KefGZ9W+ZMvRyU33gLrB4w1O3Fz1orR0hmKMCRxXNrQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-riscv64-gnu@0.112.0': resolution: {integrity: sha512-2QlvQBUhHuAE3ezD4X3CAEKMXdfgInggQ5Bj/7gb5NcYP3GyfLTj7c+mMu+BRwfC9B3AXBNyqHWbqEuuUvZyRQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-riscv64-musl@0.112.0': resolution: {integrity: sha512-v06iu0osHszgqJ1dLQRb6leWFU1sjG/UQk4MoVBtE6ZPewgfTkby6G9II1SpEAf2onnAuQceVYxQH9iuU3NJqw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-s390x-gnu@0.112.0': resolution: {integrity: sha512-+5HhNHtxsdcd7+ljXFnn9FOoCNXJX3UPgIfIE6vdwS1HqdGNH6eAcVobuqGOp54l8pvcxDQA6F4cPswCgLrQfQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-gnu@0.112.0': resolution: {integrity: sha512-jKwO7ZLNkjxwg7FoCLw+fJszooL9yXRZsDN0AQ1AQUTWq1l8GH/2e44k68N3fcP19jl8O8jGpqLAZcQTYk6skA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-musl@0.112.0': resolution: {integrity: sha512-TYqnuKV/p3eOc+N61E0961nA7DC+gaCeJ3+V2LcjJdTwFMdikqWL6uVk1jlrpUCBrozHDATVUKDZYH7r4FQYjQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-parser/binding-openharmony-arm64@0.112.0': resolution: {integrity: sha512-ZhrVmWFifVEFQX4XPwLoVFDHw9tAWH9p9vHsHFH+5uCKdfVR+jje4WxVo6YrokWCboGckoOzHq5KKMOcPZfkRg==} @@ -4896,36 +4932,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.1': resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.1': resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.1': resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.1': resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.1': resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-win32-arm64@2.5.1': resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} @@ -5562,56 +5604,67 @@ packages: resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.54.0': resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.54.0': resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.54.0': resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.54.0': resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.54.0': resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.54.0': resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.54.0': resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.54.0': resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.54.0': resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.54.0': resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openharmony-arm64@4.54.0': resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} @@ -6631,72 +6684,84 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-gnu@4.2.1': resolution: {integrity: sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.18': resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-arm64-musl@4.2.1': resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-arm64-musl@4.2.2': resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.18': resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-gnu@4.2.1': resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-gnu@4.2.2': resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.18': resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-musl@4.2.1': resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-musl@4.2.2': resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.18': resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} @@ -10802,72 +10867,84 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-gnu@1.31.1: resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-gnu@1.32.0: resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-arm64-musl@1.31.1: resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-gnu@1.31.1: resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-linux-x64-musl@1.31.1: resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 2056cddf..77576d55 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,5 +1,6 @@ packages: - apps/* + - '!apps/db-agent' - packages/* - packages/course-app/src/* onlyBuiltDependencies: diff --git a/prd/embed-link-platforms.md b/prd/embed-link-platforms.md new file mode 100644 index 00000000..f6d06e88 --- /dev/null +++ b/prd/embed-link-platforms.md @@ -0,0 +1,341 @@ +# Embed Link Platforms (Twitter/X + Vimeo) + +## Purpose + +Extend the lesson "Embed Link" video source to support platform-specific embeds (Twitter/X videos, Vimeo, and future platforms) instead of treating every URL as a raw HTML5 video source. The user selects the target platform from a dropdown; the system validates the URL, fetches metadata, and renders the appropriate embed player. + +## Goals + +- Redesign the Embed Link tab with a platform source dropdown + URL input. +- Support Twitter/X video/post embedding via oEmbed + widgets.js. +- Support Vimeo embedding via iframe player URL. +- Keep the `generic` video type for raw HTML5 video URLs (Mp4, WebM). +- Lay a pattern for adding future platforms (Loom, Wistia, etc.) without schema changes per platform. +- Rename the tab from "Embed Link" to "Embed" to reflect the broader scope. + +## Non-Goals + +- Adding a dedicated tab per platform in the add-video modal. +- Implementing watch enforcement or transcript support for embed platforms (they render as iframes, not HTML5 video). +- Supporting Twitter/X as a downloadable video source. + +## Constraints + +- Existing `generic` type behavior must be preserved (HTML5 `