Directory structure:
└── koellabs-koellabs.com/
    ├── README.md
    ├── ACKNOWLEDGEMENTS.md
    ├── components.json
    ├── CONTRIBUTING.md
    ├── DEVELOPMENT.md
    ├── drizzle.config.ts
    ├── jsconfig.json
    ├── LICENSE
    ├── middleware.ts
    ├── next-env.d.ts
    ├── next.config.mjs
    ├── package.json
    ├── postcss.config.mjs
    ├── tsconfig.json
    ├── .editorconfig
    ├── .env.example
    ├── .eslintrc.json
    ├── .gitleaksignore
    ├── .prettierignore
    ├── .prettierrc
    ├── app/
    │   ├── globals.css
    │   ├── layout.js
    │   ├── not-found.js
    │   ├── page.js
    │   ├── about/
    │   │   └── page.tsx
    │   ├── api/
    │   │   ├── auth/
    │   │   │   ├── [...all]/
    │   │   │   │   └── route.ts
    │   │   │   └── update-user/
    │   │   │       └── route.ts
    │   │   └── user/
    │   │       └── preferences/
    │   │           └── route.ts
    │   ├── blog/
    │   │   ├── bloglist.tsx
    │   │   ├── page.tsx
    │   │   ├── posts.ts
    │   │   ├── [slug]/
    │   │   │   └── page.tsx
    │   │   ├── blog-components/
    │   │   │   ├── body.tsx
    │   │   │   ├── code.tsx
    │   │   │   ├── decorations.tsx
    │   │   │   ├── heading.tsx
    │   │   │   ├── hero-image.tsx
    │   │   │   ├── image.tsx
    │   │   │   ├── subheading.tsx
    │   │   │   └── utils.ts
    │   │   └── posts/
    │   │       ├── building-open-source-leaderboards.tsx
    │   │       ├── dialect-sensitivity.tsx
    │   │       ├── feature-extraction-deep-dive.tsx
    │   │       ├── new-look-for-koel-labs.tsx
    │   │       ├── open-source-announcement.tsx
    │   │       ├── phonemic-transcription-metrics.tsx
    │   │       └── transformer-deep-dive.tsx
    │   ├── contact/
    │   │   └── page.tsx
    │   ├── dashboard/
    │   │   ├── customTimeline.tsx
    │   │   ├── layout.js
    │   │   ├── microphone.tsx
    │   │   ├── page.jsx
    │   │   ├── practiceMode.tsx
    │   │   ├── videoPlayer.tsx
    │   │   └── settings/
    │   │       └── page.jsx
    │   ├── onboarding/
    │   │   ├── layout.js
    │   │   ├── page.jsx
    │   │   ├── getting-to-know-you/
    │   │   │   └── page.jsx
    │   │   ├── language-goals/
    │   │   │   └── page.jsx
    │   │   ├── speech-assessment/
    │   │   │   └── page.jsx
    │   │   └── welcome/
    │   │       └── page.jsx
    │   ├── previews/
    │   │   ├── page.tsx
    │   │   └── sections-previews/
    │   │       ├── leaderboard.tsx
    │   │       ├── previews-hero.tsx
    │   │       └── previews-models.tsx
    │   ├── pricing/
    │   │   └── page.tsx
    │   ├── research/
    │   │   ├── page.tsx
    │   │   └── [slug]/
    │   │       └── page.tsx
    │   ├── reset-password/
    │   │   └── page.js
    │   ├── sign-in/
    │   │   └── page.tsx
    │   └── sign-up/
    │       └── page.tsx
    ├── components/
    │   ├── comp-331.jsx
    │   ├── comp-433.jsx
    │   ├── magic-highlighter.tsx
    │   ├── react-scan.tsx
    │   ├── actions/
    │   │   └── youtube-video-validate.ts
    │   ├── forms/
    │   │   ├── challenging-words-selector.jsx
    │   │   ├── city-selector.jsx
    │   │   ├── country-selector.jsx
    │   │   ├── experience-level-selector.jsx
    │   │   ├── language-selector.jsx
    │   │   └── target-language-selector.jsx
    │   ├── sections/
    │   │   ├── 1 - Hero.jsx
    │   │   ├── 2 - Bento.jsx
    │   │   ├── 3 - CTA.tsx
    │   │   ├── 4 - Footer.tsx
    │   │   ├── bento.tsx
    │   │   ├── cta.tsx
    │   │   ├── footer.tsx
    │   │   ├── hero.tsx
    │   │   ├── models.tsx
    │   │   ├── previews.tsx
    │   │   └── research.tsx
    │   ├── sidebar/
    │   │   ├── app-sidebar.jsx
    │   │   ├── beta-card.jsx
    │   │   ├── nav-main.jsx
    │   │   ├── nav-secondary.jsx
    │   │   ├── nav-user.jsx
    │   │   ├── nav-videos.jsx
    │   │   └── streak-card.jsx
    │   └── ui/
    │       ├── audio-playback.tsx
    │       ├── calendar-rac.tsx
    │       ├── code-block.tsx
    │       ├── dashboard-stat-chart.jsx
    │       ├── dashboard.jsx
    │       ├── datefield-rac.tsx
    │       ├── header.jsx
    │       ├── koellabs-onboarding.tsx
    │       ├── sidebar.jsx
    │       ├── toast.jsx
    │       ├── toaster.jsx
    │       ├── base/
    │       │   ├── avatar.jsx
    │       │   ├── badge.jsx
    │       │   ├── button.tsx
    │       │   ├── card.tsx
    │       │   ├── carousel.tsx
    │       │   ├── chart.tsx
    │       │   ├── checkbox.tsx
    │       │   ├── collapsible.jsx
    │       │   ├── command.tsx
    │       │   ├── context-menu.jsx
    │       │   ├── date.tsx
    │       │   ├── dialog.tsx
    │       │   ├── drawer.tsx
    │       │   ├── dropdown-menu.jsx
    │       │   ├── info-card.jsx
    │       │   ├── input.tsx
    │       │   ├── koel-bird-rounded.jsx
    │       │   ├── koel-labs-bird.jsx
    │       │   ├── label.tsx
    │       │   ├── model-svg.tsx
    │       │   ├── popover.jsx
    │       │   ├── progress.jsx
    │       │   ├── radio-group.jsx
    │       │   ├── scroll-area.jsx
    │       │   ├── select.tsx
    │       │   ├── separator.jsx
    │       │   ├── sheet.jsx
    │       │   ├── skeleton.jsx
    │       │   ├── slider.jsx
    │       │   ├── tabs.jsx
    │       │   ├── textarea.tsx
    │       │   ├── theme-provider.tsx
    │       │   └── tooltip.tsx
    │       ├── dashboard/
    │       │   ├── ClipsList.tsx
    │       │   ├── ImportVideos.tsx
    │       │   ├── SearchCenter.tsx
    │       │   └── outdated/
    │       │       ├── RecommendedClips.tsx
    │       │       └── RevisitClips.tsx
    │       ├── magicui/
    │       │   ├── animated-beam.jsx
    │       │   ├── bento-grid.jsx
    │       │   └── hero-video-dialog.tsx
    │       └── onboarding/
    │           ├── gradient-logo.jsx
    │           ├── grid-background.jsx
    │           └── onboarding-provider.jsx
    ├── db/
    │   └── schema.ts
    ├── hooks/
    │   ├── use-character-limit.js
    │   ├── use-image-upload.js
    │   ├── use-mobile.jsx
    │   ├── use-sidebar.jsx
    │   ├── use-toast.js
    │   └── use-user-videos.ts
    ├── lib/
    │   ├── auth-client.ts
    │   ├── auth.ts
    │   ├── styles.js
    │   ├── use-character-limit.tsx
    │   ├── videos.ts
    │   └── hooks/
    │       └── use-scroll.js
    ├── migrations/
    │   ├── 0000_married_dark_beast.sql
    │   ├── 0001_zippy_snowbird.sql
    │   ├── 0002_orange_klaw.sql
    │   ├── 0003_bouncy_betty_brant.sql
    │   ├── 0004_late_patriot.sql
    │   ├── 0005_sticky_phil_sheldon.sql
    │   └── meta/
    │       ├── 0000_snapshot.json
    │       ├── 0001_snapshot.json
    │       ├── 0002_snapshot.json
    │       ├── 0003_snapshot.json
    │       ├── 0004_snapshot.json
    │       ├── 0005_snapshot.json
    │       └── _journal.json
    ├── pages/
    │   └── api/
    │       └── submitGoogleFormWithReCaptcha.ts
    ├── public/
    │   ├── news-sitemap.xml
    │   ├── sitemap.xml
    │   ├── WavWorklet.js
    │   ├── images/
    │   │   └── models.webp
    │   ├── videos/
    │   │   ├── jumanji-next-level.vtt
    │   │   ├── the-office-michael-pyramid-scheme.captions.vtt
    │   │   ├── the-office-michael-pyramid-scheme.VTT
    │   │   └── the-office-michael-secret-keeper-full-res.VTT
    │   └── .well-known/
    │       └── microsoft-identity-association.json
    ├── scripts/
    │   ├── docker-compose.dev.yaml
    │   ├── docker-run-dev-cmd.sh
    │   ├── docker-run-dev.sh
    │   ├── docker-stop-dev.sh
    │   └── Dockerfile.dev
    ├── styles/
    │   └── animations.css
    └── .github/
        ├── pull_request_template.md
        ├── ISSUE_TEMPLATE/
        │   ├── bug_report.md
        │   └── feature_request.md
        └── workflows/
            ├── azure-static-web-apps-salmon-sky-0a6b6c10f.yml
            ├── gitleaks.yml
            └── zizmor.yml

================================================
FILE: README.md
================================================
<img width="100%" alt="Koel Lab's Logomark" src="https://github.com/user-attachments/assets/0e7cf381-3c44-402e-a58d-4af419037a1e" />

[![Mozilla Builders](https://img.shields.io/badge/Mozilla-000000.svg?style=for-the-badge&logo=Mozilla&logoColor=white)](https://future.mozilla.org/builders/)
![Patreon](https://img.shields.io/badge/Patreon-F96854?style=for-the-badge&logo=patreon&logoColor=white)
![PayPal](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white)

# Koel Labs - Web Application

![Zizmor](https://github.com/KoelLabs/webapp/actions/workflows/zizmor.yml/badge.svg)
![Gitleaks Secret Scanning](https://github.com/KoelLabs/webapp/actions/workflows/gitleaks.yml/badge.svg)
[![Automatic Deploys](https://github.com/KoelLabs/webapp/actions/workflows/azure-static-web-apps-salmon-sky-0a6b6c10f.yml/badge.svg)](https://koellabs.com)

Contains the website for Koel Labs and the web interface for the pronunciation learning application.

Read about all our repositories [here](https://github.com/KoelLabs).

## Setup

See [DEVELOPMENT.md](DEVELOPMENT.md) for how to setup your local development environment. If you just want to run the application locally not for development purposes, follow the instructions below.

0. `git clone --recurse-submodules https://github.com/KoelLabs/webapp.git`
1. Install [Docker and Docker Compose](https://www.docker.com/get-started/)
2. Duplicate the `.env.example` file and rename it to `.env.local` with `cp .env.example .env.local`.
3. Duplicate the `server/.env.example` file and rename it to `server/.env` with `cp server/.env.example server/.env`.
4. Run the application `. ./scripts/docker-run-dev.sh`

## Contributing

Check out [CONTRIBUTING.md](CONTRIBUTING.md) for specific guidelines on contributing to this repository.

We are grateful for all of [our contributors](ACKNOWLEDGEMENTS.md). If you contribute to this repository and wish to be acknowledged, please add your name to the list in your pull request.

## License

Application code in this repository is open-sourced under the [FSL-1.1-Apache-2.0](https://fsl.software/).

We retain all rights to the Koel Labs brand, logos, blog posts, and website content.



================================================
FILE: ACKNOWLEDGEMENTS.md
================================================
# Individual Contributors

If you wish to be acknowledged for your contributions, please list your name
with a short description of your contribution(s) below. For example:

- Jane Smith: Added the `foo` and `bar` ops.

The Koel Labs Web Application was developed with contributions from the following individuals:

- [Ruslan Mukhamedvaleev](https://www.ruslan.in/): Koel Labs co-founder and CPO — lead web-developer and designer.
- [Alexander Metzger](https://www.linkedin.com/in/alexander-le-metzger): Koel Labs co-founder and CEO — lead backend+infrastructure+devops+ML engineer.

<a href="https://github.com/KoelLabs/webapp/graphs/contributors">
  <img class="dark-light" src="https://contrib.rocks/image?repo=KoelLabs/webapp&anon=0&columns=20&max=100&r=true" />
</a>

# Third-Party Software

| Name                                | License period | License type | Link                                                                           | Author                                                                |
| :---------------------------------- | :------------- | :----------- | :----------------------------------------------------------------------------- | :-------------------------------------------------------------------- |
| @custom-react-hooks/use-media-query | perpetual      | MIT          | git+https://github.com/djkepa/custom-react-hooks.git                           | Bane Grozdanovic <banegrozdanovic@gmail.com>                          |
| @headlessui/react                   | perpetual      | MIT          | git+https://github.com/tailwindlabs/headlessui.git                             | n/a                                                                   |
| @radix-ui/react-avatar              | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-checkbox            | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-collapsible         | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-context-menu        | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-dialog              | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-dropdown-menu       | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-icons               | perpetual      | MIT          | https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz       | n/a                                                                   |
| @radix-ui/react-label               | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-popover             | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-progress            | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-select              | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-separator           | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-slider              | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-slot                | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-tabs                | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-toast               | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @radix-ui/react-tooltip             | perpetual      | MIT          | git+https://github.com/radix-ui/primitives.git                                 | n/a                                                                   |
| @vidstack/react                     | perpetual      | MIT          | https://github.com/vidstack/player.git                                         | n/a                                                                   |
| class-variance-authority            | perpetual      | Apache-2.0   | git+https://github.com/joe-bell/cva.git                                        | Joe Bell (https://joebell.co.uk)                                      |
| clsx                                | perpetual      | MIT          | git+https://github.com/lukeed/clsx.git                                         | Luke Edwards luke.edwards05@gmail.com https://lukeed.com              |
| drizzle-orm                         | perpetual      | Apache-2.0   | git+https://github.com/drizzle-team/drizzle-orm.git                            | Drizzle Team                                                          |
| embla-carousel-react                | perpetual      | MIT          | git+https://github.com/davidjerleke/embla-carousel                             | David Jerleke                                                         |
| firebase                            | perpetual      | Apache-2.0   | git+https://github.com/firebase/firebase-js-sdk.git                            | Firebase <firebase-support@google.com> (https://firebase.google.com/) |
| firebase-admin                      | perpetual      | Apache-2.0   | git+https://github.com/firebase/firebase-admin-node.git                        | Firebase <firebase-support@google.com> (https://firebase.google.com/) |
| formidable                          | perpetual      | MIT          | git+https://github.com/node-formidable/formidable.git                          | n/a                                                                   |
| framer-motion                       | perpetual      | MIT          | git+https://github.com/motiondivision/motion.git                               | Framer                                                                |
| lucide-react                        | perpetual      | ISC          | git+https://github.com/lucide-icons/lucide.git                                 | Eric Fennis                                                           |
| media-chrome                        | perpetual      | MIT          | git+https://github.com/muxinc/media-chrome.git                                 | @muxinc                                                               |
| next                                | perpetual      | MIT          | git+https://github.com/vercel/next.js.git                                      | n/a                                                                   |
| next-themes                         | perpetual      | MIT          | git+https://github.com/pacocoursey/next-themes.git                             | n/a                                                                   |
| pg                                  | perpetual      | MIT          | git://github.com/brianc/node-postgres.git                                      | Brian Carlson <brian.m.carlson@gmail.com>                             |
| postcss                             | perpetual      | MIT          | git+https://github.com/postcss/postcss.git                                     | Andrey Sitnik <andrey@sitnik.ru>                                      |
| react                               | perpetual      | MIT          | git+https://github.com/facebook/react.git                                      | n/a                                                                   |
| react-dom                           | perpetual      | MIT          | git+https://github.com/facebook/react.git                                      | n/a                                                                   |
| react-google-recaptcha-v3           | perpetual      | MIT          | git+https://github.com/t49tran/react-google-recaptcha-v3.git                   | Duong Tran                                                            |
| recharts                            | perpetual      | MIT          | git+https://github.com/recharts/recharts.git                                   | recharts group                                                        |
| tailwind-merge                      | perpetual      | MIT          | git+https://github.com/dcastil/tailwind-merge.git                              | Dany Castillo                                                         |
| tailwind-scrollbar-hide             | perpetual      | MIT          | git+https://github.com/reslear/tailwind-scrollbar-hide.git                     | reslear                                                               |
| tailwindcss                         | perpetual      | MIT          | git+https://github.com/tailwindlabs/tailwindcss.git                            | n/a                                                                   |
| tailwindcss-animate                 | perpetual      | MIT          | https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz | Jamie Kyle <me@thejameskyle.com>                                      |
| vaul                                | perpetual      | MIT          | git+https://github.com/emilkowalski/vaul.git                                   | Emil Kowalski <e@emilkowal.ski>                                       |
| zod                                 | perpetual      | MIT          | git+https://github.com/colinhacks/zod.git                                      | Colin McDonnell <colin@colinhacks.com>                                |
| @types/node                         | perpetual      | MIT          | https://github.com/DefinitelyTyped/DefinitelyTyped.git                         | n/a                                                                   |
| @types/react                        | perpetual      | MIT          | https://github.com/DefinitelyTyped/DefinitelyTyped.git                         | n/a                                                                   |
| css-minimizer-webpack-plugin        | perpetual      | MIT          | git+https://github.com/webpack-contrib/css-minimizer-webpack-plugin.git        | Loann Neveu                                                           |
| dotenv                              | perpetual      | BSD-2-Clause | git://github.com/motdotla/dotenv.git                                           | n/a                                                                   |
| drizzle-kit                         | perpetual      | MIT          | git+https://github.com/drizzle-team/drizzle-orm.git                            | Drizzle Team                                                          |
| eslint                              | perpetual      | MIT          | git+https://github.com/eslint/eslint.git                                       | Nicholas C. Zakas <nicholas+npm@nczconsulting.com>                    |
| eslint-config-next                  | perpetual      | MIT          | git+https://github.com/vercel/next.js.git                                      | n/a                                                                   |
| eslint-config-prettier              | perpetual      | MIT          | git+https://github.com/prettier/eslint-config-prettier.git                     | Simon Lydell                                                          |
| fixpack                             | perpetual      | MIT          | git://github.com/henrikjoreteg/fixpack.git                                     | Henrik Joreteg <henrik@andyet.net>                                    |
| prettier                            | perpetual      | MIT          | git+https://github.com/prettier/prettier.git                                   | James Long                                                            |



================================================
FILE: components.json
================================================
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "default",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.js",
    "css": "app/globals.css",
    "baseColor": "neutral",
    "cssVariables": true,
    "prefix": ""
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks",
    "magicui": "@/components/magicui"
  }
}



================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Koel Labs - Web Application

👍🎉 First off, thanks for taking the time to contribute! 🎉👍

If you have great ideas for improving UI/UX, conveying pronunciation feedback more clearly, or making the application more accessible (including translations), this is the repo for you.

Checkout our [general contributing guidelines here](https://github.com/KoelLabs/.github/blob/main/CONTRIBUTING.md).

## Where to Start

1. Read the [README.md](README.md) file to understand the purpose of this repository.
2. Read the [DEVELOPMENT.md](DEVELOPMENT.md) file to understand how to set up your local development environment. Important design decisions will also be documented here.
3. Read the [Code of Conduct](https://github.com/KoelLabs/.github/blob/main/CONTRIBUTING.md#code-of-conduct) to understand expectations while contributing to this project and take a look at the [FAQ](https://github.com/KoelLabs/.github/blob/main/CONTRIBUTING.md#faq) if you have any questions.
4. Read through the [issues](https://github.com/KoelLabs/webapp/issues) to understand the current development priorities.
5. All contributions start with an issue to discuss the change. See [how to file a bug report](https://github.com/KoelLabs/.github/blob/main/CONTRIBUTING.md#reporting-bugs), [suggest a new feature](https://github.com/KoelLabs/.github/blob/main/CONTRIBUTING.md#suggesting-enhancements), or [make your first code contribution](https://github.com/KoelLabs/.github/blob/main/CONTRIBUTING.md#your-first-code-contribution).
   - Look for the [issues](https://github.com/KoelLabs/webapp/issues) tagged `good first issue` and `help wanted` for things to work on.
   - Make sure to check the [existing issues](https://github.com/KoelLabs/webapp/issues) before creating a new one.
6. Maintainers with write access to the repository will assign willing contributors to issues they request. Once assigned, fork the repository and create a branch for your work.
7. When you are ready, submit a pull request to the `main` branch. The [pull request template](.github/pull_request_template.md) contains a checklist to go through.

## Point of Contact

If you have any questions, feel free to reach out to alex@koellabs.com or ruslan@koellabs.com or open an issue. Security vulnerabilities should be reported to info@koellabs.com.

## Legal Boilerplate

By making contributions to the Koel Labs project, you agree to retain all rights, title and interest in and to your contributions and confirm that Koel Labs can use, modify, copy, and redistribute said contributions, under its choice of terms.



================================================
FILE: DEVELOPMENT.md
================================================
# Development

## Setup

### Run with Docker (Recommended)

0. `git clone --recurse-submodules https://github.com/KoelLabs/webapp.git`
1. Install Docker and Docker Compose
   - [Docker Desktop for Mac](https://docs.docker.com/docker-for-mac/install/) or `brew install --cask docker` with [Homebrew](https://brew.sh/)
     - If it repeatedly complains about the daemon not running, make sure Docker Desktop is running and add `export DOCKER_HOST=unix:///Users/$USER/Library/Containers/com.docker.docker/Data/docker.raw.sock` to your shell profile (e.g. `~/.zshrc`)
   - [Docker Desktop for Windows](https://docs.docker.com/docker-for-windows/install/) or `choco install docker-desktop` with [Chocolatey](https://chocolatey.org/)
   - [Docker Engine for Linux](https://docs.docker.com/engine/install/) or `sudo apt install docker.io` with APT on Ubuntu
2. Duplicate the `.env.example` file and rename it to `.env.local` with `cp .env.example .env.local`.
3. Duplicate the `server/.env.example` file and rename it to `server/.env` with `cp server/.env.example server/.env`.
   - You can find your `HF_TOKEN` on your [Settings Page](https://huggingface.co/settings/tokens). It just needs read access to `gated repos`.
4. Run the application
   - `. ./scripts/docker-run-dev.sh` to start the development server (or `npm run docker` if you have Node.js installed)
   - `ctrl+c` to stop the server or `. ./scripts/docker-stop-dev.sh` if you've closed the terminal

Run commands inside the docker container with `. scripts/docker-run-dev-cmd.sh <command>`, e.g., `. scripts/docker-run-dev-cmd.sh npm install react`.
The docker container will also automatically `npm ci` from the package-lock.json and apply migrations when it starts.

### Run directly on your machine

0. `git clone https://github.com/KoelLabs/webapp.git`
1. Install Node.js
   - [Node.js for Mac](https://nodejs.org/en/download/) or `brew install node` with [Homebrew](https://brew.sh/)
   - [Node.js for Windows](https://nodejs.org/en/download/) or `choco install nodejs` with [Chocolatey](https://chocolatey.org/)
   - [Node.js for Linux](https://nodejs.org/en/download/) or `sudo apt install nodejs` with APT on Ubuntu
2. Install PostgreSQL
   - [PostgreSQL for Mac](https://www.postgresql.org/download/macosx/) or `brew install postgresql` with [Homebrew](https://brew.sh/)
   - [PostgreSQL for Windows](https://www.postgresql.org/download/windows/) or `choco install postgresql` with [Chocolatey](https://chocolatey.org/)
   - [PostgreSQL for Linux](https://www.postgresql.org/download/linux/) or `sudo apt install postgresql` with APT on Ubuntu
3. Make sure PostgreSQL is running
   - `brew services start postgresql` with [Homebrew](https://brew.sh/)
   - `sudo service postgresql start` with APT on Ubuntu
4. Create a new database named `postgres` with a user named `postgres` with the password `postgres`
5. Install dependencies
   - `npm install` or `npm ci` for a clean install from the package-lock.json
6. Duplicate the `.env.example` file and rename it to `.env.local` with `cp .env.example .env.local`.
7. [optional] Follow [the instructions](https://github.com/KoelLabs/server) to set up the inference server if you want to run the speech models.
8. Run the application
   - `npm run dev` to start the development server
   - `ctrl+c` to stop it

### Formatting, Linting, Automated Tests and Secret Scanning

All will run automatically via GitHub Actions on every push to the repository. You can also run them locally:

- `npm run format` or `. scripts/docker-run-dev-cmd.sh npm run format` to format the code with Prettier, ESLint and Fixpack
- `npm run lint` or `. scripts/docker-run-dev-cmd.sh npm run lint` to lint the code with Next.js ESLint and Prettier
- `npm run test` or `. scripts/docker-run-dev-cmd.sh npm run test` to run the automated tests with Node Test Runner
- `npm run scan` or `. scripts/docker-run-dev-cmd.sh npm run scan` to scan the code for secrets with GitLeaks and action security vulnerabilities with Zizmor

Formatting can be set to happen automatically on save in your editor. For VS Code, install the [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) extension and add `"editor.formatOnSave": true` to your settings.

### Migrations

When you have made changes to the schema in `db/schema.sql`, you will need to make new migration files with `npm run makemigrations` or `. scripts/docker-run-dev-cmd.sh npm run makemigrations`. Everyone will need to apply them with `npm run migrate` to update their local database (applied automatically if running with docker-compose). The production database will be updated automatically when the migration files are deployed. Migration files are immutable and should not be edited once created.

### Directory Structure

```
webapp/
├── .github                 # GitHub Actions and issue templates
├── app/                    # Application files
├── components/             # React components
├── data/                   # Postgres database files when running with Docker
├── db/                     # Database schema and utilities
├── migrations/             # Database migration files
├── hooks/                  # React hooks
├── pages/                  # Next.js pages
│   └── api/                # API routes
├── public/                 # Static assets to be served
├── scripts/                # Shell scripts
├── utils/                  # Utility functions
├── editorconfig            # Editor configuration
├── .env.example            # Example environment variables
├── .eslintrc.json          # ESLint configuration
├── .gitignore              # Git ignore rules
├── .prettierignore         # Prettier ignore rules
├── .prettierrc             # Prettier configuration
├── components.json         # Component metadata
├── CONTRIBUTING.md         # Contribution guidelines
├── DEVELOPMENT.md          # Development setup
├── drizzle.config.ts       # Drizzle configuration
├── jsconfig.json           # JavaScript configuration
├── LICENSE                 # License information
├── middleware.ts           # Middleware functions (auth)
├── next-env.d.ts           # Next.js environment types
├── next.config.mjs         # Next.js configuration
├── package-lock.json       # Lock file
├── package.json            # NPM configuration
├── postcss.config.mjs      # PostCSS configuration
├── README.md               # Readme
├── tailwind.config.js      # Tailwind CSS configuration
└── tsconfig.json           # TypeScript configuration
```

## Deployment

The pushes and merged pull requests to the `main` branch will automatically deploy to the production server. Pull requests will automatically be assigned a preview URL hosted via the test server.



================================================
FILE: drizzle.config.ts
================================================
import { config } from 'dotenv';
import { defineConfig } from 'drizzle-kit';

config({
  path: './.env.local',
});

export default defineConfig({
  schema: './db/schema.ts',
  out: './migrations',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
  verbose: true,
  strict: true,
});



================================================
FILE: jsconfig.json
================================================
{
  "compilerOptions": {
    "jsx": "react",
    "paths": {
      "@/*": ["./*"]
    }
  }
}



================================================
FILE: LICENSE
================================================
# Functional Source License, Version 1.1, Apache 2.0 Future License

## Abbreviation

FSL-1.1-Apache-2.0

## Notice

Copyright 2024 Koel Labs

## Terms and Conditions

### Licensor ("We")

The party offering the Software under these Terms and Conditions.

### The Software

The "Software" is each version of the software that we make available under
these Terms and Conditions, as indicated by our inclusion of these Terms and
Conditions with the Software.

### License Grant

Subject to your compliance with this License Grant and the Patents,
Redistribution and Trademark clauses below, we hereby grant you the right to
use, copy, modify, create derivative works, publicly perform, publicly display
and redistribute the Software for any Permitted Purpose identified below.

### Permitted Purpose

A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
means making the Software available to others in a commercial product or
service that:

1. substitutes for the Software;

2. substitutes for any other product or service we offer using the Software
   that exists as of the date we make the Software available; or

3. offers the same or substantially similar functionality as the Software.

Permitted Purposes specifically include using the Software:

1. for your internal use and access;

2. for non-commercial education;

3. for non-commercial research; and

4. in connection with professional services that you provide to a licensee
   using the Software in accordance with these Terms and Conditions.

### Patents

To the extent your use for a Permitted Purpose would necessarily infringe our
patents, the license grant above includes a license under our patents. If you
make a claim against any party that the Software infringes or contributes to
the infringement of any patent, then your patent license to the Software ends
immediately.

### Redistribution

The Terms and Conditions apply to all copies, modifications and derivatives of
the Software.

If you redistribute any copies, modifications or derivatives of the Software,
you must include a copy of or a link to these Terms and Conditions and not
remove any copyright notices provided in or with the Software.

### Disclaimer

THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.

IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.

### Trademarks

Except for displaying the License Details and identifying us as the origin of
the Software, you have no right under these Terms and Conditions to use our
trademarks, trade names, service marks or product names.

## Grant of Future License

We hereby irrevocably grant you an additional license to use the Software under
the Apache License, Version 2.0 that is effective on the second anniversary of
the date we make the Software available. On or after that date, you may use the
Software under the Apache License, Version 2.0, in which case the following
will apply:

Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.



================================================
FILE: middleware.ts
================================================
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { getSessionCookie, setSessionCookie } from 'better-auth/cookies';

const PUBLIC_URLS = [
  new RegExp('^/$'),
  new RegExp('^/blog$'),
  new RegExp('^/blog/.*$'),
  new RegExp('^/pricing$'),
  new RegExp('^/about$'),
  new RegExp('^/contact$'),
  new RegExp('^/previews$'),
  new RegExp('^/research$'),
  new RegExp('^/research/.*$'),
];

export async function middleware(request: NextRequest) {
  if (PUBLIC_URLS.some(regex => regex.test(request.nextUrl.pathname))) {
    return NextResponse.next(); // trying to access public page -> continue
  }

  const sessionCookie = getSessionCookie(request);

  // THIS IS NOT SECURE!
  // This is the recommended approach to optimistically redirect users
  // Auth checks should be handled in each page/route
  if (!sessionCookie) {
    // Logged out
    if (request.nextUrl.pathname === '/sign-in' || request.nextUrl.pathname === '/sign-up') {
      // trying to access sign-in or sign-up -> continue
      return NextResponse.next();
    } else {
      // trying to access private page -> redirect to sign-in (disabled for now)

      return NextResponse.redirect(new URL('/sign-in', request.url));
    }
  } else {
    // Logged in
    if (request.nextUrl.pathname === '/sign-in' || request.nextUrl.pathname === '/sign-up') {
      // trying to access sign-in or sign-up -> redirect to /dashboard
      return NextResponse.redirect(new URL('/dashboard', request.url));
    } else {
      // not trying to access sign-in or sign-up -> continue
      return NextResponse.next();
    }
  }
}

export const config = {
  matcher: [
    /*
     * Match all request paths except for:
     * - .swa (Azure Static Web Apps)
     * - _next (Next.js internal paths)
     * - api (API routes)
     * - paths with file extensions (e.g., .css, .js, .png, etc.)
     */
    '/((?!_next|api|.*\\.|.swa).*)',
    '/',
  ],
};



================================================
FILE: next-env.d.ts
================================================
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />
/// <reference path="./.next/types/routes.d.ts" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.



================================================
FILE: next.config.mjs
================================================
import path from 'path';
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';

const __dirname = new URL('.', import.meta.url).pathname;

const nextConfig = {
  output: 'standalone',
  reactStrictMode: false,
  compiler: {
    // Enable React compiler for better performance
    reactRemoveProperties: process.env.NODE_ENV === 'production',
    removeConsole: process.env.NODE_ENV === 'production',
    styledComponents: true,
  },
  webpack: config => {
    config.resolve.alias = {
      ...config.resolve.alias,
      '@': path.resolve(__dirname, './'),
    };

    config.optimization.minimizer = [
      config.optimization.minimizer[0],
      new CssMinimizerPlugin({
        minimizerOptions: {
          preset: [
            'default',
            {
              colormin: { hsl: false }, // see https://github.com/cssnano/cssnano/issues/1515
            },
          ],
        },
      }),
    ];

    return config;
  },
};

export default nextConfig;



================================================
FILE: package.json
================================================
{
  "name": "koel-labs-webapp",
  "description": "Contains the website for Koel Labs and web interface for the pronunciation learning application.",
  "version": "0.1.0",
  "dependencies": {
    "@custom-react-hooks/use-media-query": "^1.5.1",
    "@headlessui/react": "^2.1.3",
    "@internationalized/date": "^3.8.2",
    "@radix-ui/react-avatar": "^1.1.0",
    "@radix-ui/react-checkbox": "^1.1.2",
    "@radix-ui/react-collapsible": "^1.1.0",
    "@radix-ui/react-context-menu": "^2.2.1",
    "@radix-ui/react-dialog": "^1.1.14",
    "@radix-ui/react-dropdown-menu": "^2.1.1",
    "@radix-ui/react-icons": "^1.3.0",
    "@radix-ui/react-label": "^2.1.0",
    "@radix-ui/react-navigation-menu": "^1.2.14",
    "@radix-ui/react-popover": "^1.1.1",
    "@radix-ui/react-progress": "^1.1.0",
    "@radix-ui/react-radio-group": "^1.2.3",
    "@radix-ui/react-scroll-area": "^1.2.3",
    "@radix-ui/react-select": "^2.1.2",
    "@radix-ui/react-separator": "^1.1.0",
    "@radix-ui/react-slider": "^1.3.5",
    "@radix-ui/react-slot": "^1.1.2",
    "@radix-ui/react-tabs": "^1.1.3",
    "@radix-ui/react-toast": "^1.2.4",
    "@radix-ui/react-tooltip": "^1.1.2",
    "@tailwindcss/postcss": "^4.0.14",
    "@types/uuid": "^10.0.0",
    "@vidstack/react": "^1.12.12",
    "@wavesurfer/react": "^1.0.11",
    "better-auth": "^1.2.12",
    "class-variance-authority": "^0.7.0",
    "clsx": "^2.1.1",
    "cmdk": "^1.1.1",
    "drizzle-kit": "^0.31.8",
    "drizzle-orm": "^0.44.2",
    "embla-carousel-autoplay": "^8.6.0",
    "embla-carousel-react": "^8.3.0",
    "formidable": "^3.5.2",
    "framer-motion": "^11.3.30",
    "fuse.js": "^7.1.0",
    "lucide-react": "^0.407.0",
    "media-chrome": "^4.2.3",
    "motion": "^12.5.0",
    "next": "^15.2.6",
    "next-themes": "^0.3.0",
    "pg": "^8.12.0",
    "postcss": "^8",
    "react": "^18",
    "react-aria-components": "^1.10.1",
    "react-canvas-confetti": "^2.0.7",
    "react-dom": "^18",
    "react-google-recaptcha-v3": "^1.10.1",
    "react-image-crop": "^11.0.10",
    "react-scan": "^0.4.3",
    "react-syntax-highlighter": "^16.1.0",
    "recharts": "^2.15.3",
    "swr": "^2.3.3",
    "tailwind-merge": "^2.5.2",
    "tailwind-scrollbar-hide": "^1.1.7",
    "tailwindcss": "^4.0.14",
    "tailwindcss-animate": "^1.0.7",
    "tw-animate-css": "^1.3.7",
    "uuid": "^11.1.0",
    "vaul": "^0.9.4",
    "wavesurfer.js": "^7.10.1",
    "zod": "^3.23.8"
  },
  "devDependencies": {
    "@types/formidable": "^3.4.5",
    "@types/node": "22.5.2",
    "@types/pg": "^8.15.4",
    "@types/react": "18.3.5",
    "@types/react-syntax-highlighter": "^15.5.13",
    "css-minimizer-webpack-plugin": "^7.0.0",
    "dotenv": "^16.4.5",
    "eslint": "^9.39.1",
    "eslint-config-next": "^16.0.7",
    "eslint-config-prettier": "^9.1.0",
    "fixpack": "^4.0.0",
    "prettier": "^3.3.3"
  },
  "optionalDependencies": {
    "@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
    "lightningcss-linux-x64-gnu": "^1.29.1"
  },
  "engines": {
    "node": "^18.18"
  },
  "overrides": {
    "react-is": "^19.0.0-rc-69d4b800-20241021"
  },
  "private": true,
  "proxy": "http://127.0.0.1:8080",
  "scripts": {
    "build": "next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/",
    "dev": "next dev",
    "docker": ". ./scripts/docker-run-dev.sh",
    "format": "(fixpack || true) && (eslint . --fix || true) && prettier --write .",
    "license-report": "npx license-report --output=markdown --fields=name --fields=licensePeriod --fields=licenseType --fields=link --fields=author",
    "lint": "npx eslint-config-prettier **/*.jsx && next lint && prettier --check .",
    "makemigrations": "drizzle-kit generate",
    "migrate": "eval $(cat .env.local) && drizzle-kit migrate",
    "scan": "gitleaks detect && npm audit && zizmor .",
    "start": "next start",
    "test": "echo \"Error: not implemented yet \" && exit 1"
  }
}



================================================
FILE: postcss.config.mjs
================================================
/** @type {import('postcss-load-config').Config} */
const config = {
  plugins: {
    '@tailwindcss/postcss': {},
  },
};

export default config;



================================================
FILE: tsconfig.json
================================================
{
  "compilerOptions": {
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "noEmit": true,
    "incremental": true,
    "module": "esnext",
    "esModuleInterop": true,
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "paths": {
      "@/*": [
        "./*"
      ]
    },
    "plugins": [
      {
        "name": "next"
      }
    ],
    "strictNullChecks": true,
    "target": "ES2017"
  },
  "include": [
    "next-env.d.ts",
    ".next/types/**/*.ts",
    "**/*.ts",
    "**/*.tsx",
    "components/ui/dashboard-stat-chart.jsx",
    "components/ui/dashboard-stat-chart.jsx",
    "app/dashboard/videoPlayer.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}



================================================
FILE: .editorconfig
================================================
# http://editorconfig.org
root = true

[*]
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 100

[{*.js,*.json,*.yml}]
indent_size = 2
indent_style = space



================================================
FILE: .env.example
================================================
NEXT_PUBLIC_SERVER_ORIGIN=http://localhost:8080
NEXT_PUBLIC_SERVER_HOST=localhost:8080

NEXT_PUBLIC_RECAPTCHA_SITE_KEY=6Lfm4a0qAAAAADOh_Y470P2JtrGq5V84RHd2wSOv
RECAPTCHA_PRIVATE_KEY=check https://www.google.com/recaptcha
CONTACT_FORM_URL=google formResponse url

POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=postgres
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres

BETTER_AUTH_SECRET=randomvalue
BETTER_AUTH_URL=http://localhost:3000
GOOGLE_CLIENT_ID=from gcp console
GOOGLE_CLIENT_SECRET=from gcp console
MICROSOFT_CLIENT_ID=from ENTRA app in Azure
MICROSOFT_CLIENT_SECRET=from ENTRA app in Azure
MICROSOFT_TENANT_ID=from ENTRA app in Azure



================================================
FILE: .eslintrc.json
================================================
{
  "extends": "next/core-web-vitals",
  "rules": { "react/no-unescaped-entities": 0 }
}



================================================
FILE: .gitleaksignore
================================================
9e719a59eaae067db632e575e419abf3303a5ffc:.env.example:generic-api-key:1
9e719a59eaae067db632e575e419abf3303a5ffc:.github/workflows/azure-static-web-apps-salmon-sky-0a6b6c10f.yml:generic-api-key:37



================================================
FILE: .prettierignore
================================================
# dependencies
node_modules

# Minified Files
**/*.min.js

# Cache
.firebase

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem
migrations

# postgres
data

# local env files
.env*.local



================================================
FILE: .prettierrc
================================================
{
  "printWidth": 100,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": true,
  "quoteProps": "as-needed",
  "trailingComma": "all",
  "bracketSpacing": true,
  "arrowParens": "avoid",
  "endOfLine": "auto"
}



================================================
FILE: app/globals.css
================================================
@import '../styles/animations.css' layer(base);

@import 'tailwindcss';

@plugin 'tailwindcss-animate';
@plugin 'tailwind-scrollbar-hide';
@plugin '@vidstack/react/tailwind.cjs' {
  selector: '.media-player';
  prefix: 'media';
}

@custom-variant dark (&:is(.dark *));

@theme {
  --font-inter: 'Inter', sans-serif;

  --breakpoint-xss: 390px;
  --breakpoint-special: 768px;

  --color-border: hsl(var(--border));
  --color-input: hsl(var(--input));
  --color-ring: hsl(var(--ring));
  --color-background: hsl(var(--background));
  --color-foreground: hsl(var(--foreground));

  --color-primary: hsl(var(--primary));
  --color-primary-foreground: hsl(var(--primary-foreground));

  --color-secondary: hsl(var(--secondary));
  --color-secondary-foreground: hsl(var(--secondary-foreground));

  --color-destructive: hsl(var(--destructive));
  --color-destructive-foreground: hsl(var(--destructive-foreground));

  --color-muted: hsl(var(--muted));
  --color-muted-foreground: hsl(var(--muted-foreground));

  --color-accent: hsl(var(--accent));
  --color-accent-foreground: hsl(var(--accent-foreground));

  --color-popover: hsl(var(--popover));
  --color-popover-foreground: hsl(var(--popover-foreground));

  --color-card: hsl(var(--card));
  --color-card-foreground: hsl(var(--card-foreground));

  --color-chart-1: hsl(var(--chart-1));
  --color-chart-2: hsl(var(--chart-2));
  --color-chart-3: hsl(var(--chart-3));
  --color-chart-4: hsl(var(--chart-4));
  --color-chart-5: hsl(var(--chart-5));

  --radius-lg: var(--radius);
  --radius-md: calc(var(--radius) - 2px);
  --radius-sm: calc(var(--radius) - 4px);

  --animate-accordion-down: accordion-down 0.2s ease-out;
  --animate-accordion-up: accordion-up 0.2s ease-out;

  @keyframes accordion-down {
    from {
      height: 0;
    }
    to {
      height: var(--radix-accordion-content-height);
    }
  }
  @keyframes accordion-up {
    from {
      height: var(--radix-accordion-content-height);
    }
    to {
      height: 0;
    }
  }
}

@font-face {
  font-family: 'OpenRundeRegular';
  src: url('/fonts/OpenRunde-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
}

@font-face {
  font-family: 'OpenRundeMedium';
  src: url('/fonts/OpenRunde-Medium.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
}

@font-face {
  font-family: 'OpenRundeSemibold';
  src: url('/fonts/OpenRunde-Semibold.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
}

@font-face {
  font-family: 'OpenRundeBold';
  src: url('/fonts/OpenRunde-Bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
}

.open-runde-regular {
  font-family: 'OpenRundeRegular', sans-serif;
}

.open-runde-medium {
  font-family: 'OpenRundeMedium', sans-serif;
}

.open-runde-semibold {
  font-family: 'OpenRundeSemibold', sans-serif;
}

.open-runde-bold {
  font-family: 'OpenRundeBold', sans-serif;
}

@utility container {
  margin-inline: auto;
  padding-inline: 2rem;
  @media (width >= --theme(--breakpoint-xss)) {
    max-width: none;
  }
  @media (width >= 1400px) {
    max-width: 1400px;
  }
}

/*
  The default border color has changed to `currentColor` in Tailwind CSS v4,
  so we've added these compatibility styles to make sure everything still
  looks the same as it did with Tailwind CSS v3.

  If we ever want to remove these styles, we need to add an explicit border
  color utility to any element that depends on these defaults.
*/
@layer base {
  *,
  ::after,
  ::before,
  ::backdrop,
  ::file-selector-button {
    border-color: var(--color-gray-200, currentColor);
  }
}

/* .screen-minus-sidebar-max-width {
  max-width: calc(100vw - 256px);
}

@media (max-width: 768px) {
  .screen-minus-sidebar-max-width {
    max-width: 100vw;
  }
} */

@utility main-transition {
  transition: max-width 150ms ease-in-out;
}

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 0 0% 3.9%;
    --card: 0 0% 100%;
    --card-foreground: 0 0% 3.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 0 0% 3.9%;
    --primary: 0 0% 9%;
    --primary-foreground: 0 0% 98%;
    --secondary: 0 0% 96.1%;
    --secondary-foreground: 0 0% 9%;
    --muted: 0 0% 96.1%;
    --muted-foreground: 0 0% 45.1%;
    --accent: 0 0% 96.1%;
    --accent-foreground: 0 0% 9%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 0 0% 98%;
    --border: 0 0% 89.8%;
    --input: 0 0% 89.8%;
    --ring: 0 0% 3.9%;
    --radius: 0.5rem;
    --chart-1: 12 76% 61%;
    --chart-2: 173 58% 39%;
    --chart-3: 197 37% 24%;
    --chart-4: 43 74% 66%;
    --chart-5: 27 87% 67%;
  }

  .dark {
    --background: 0 0% 3.9%;
    --foreground: 0 0% 98%;
    --card: 0 0% 3.9%;
    --card-foreground: 0 0% 98%;
    --popover: 0 0% 3.9%;
    --popover-foreground: 0 0% 98%;
    --primary: 0 0% 98%;
    --primary-foreground: 0 0% 9%;
    --secondary: 0 0% 14.9%;
    --secondary-foreground: 0 0% 98%;
    --muted: 0 0% 14.9%;
    --muted-foreground: 0 0% 63.9%;
    --accent: 0 0% 14.9%;
    --accent-foreground: 0 0% 98%;
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 0 0% 98%;
    --border: 0 0% 14.9%;
    --input: 0 0% 14.9%;
    --ring: 0 0% 83.1%;
    --chart-1: 220 70% 50%;
    --chart-2: 160 60% 45%;
    --chart-3: 30 80% 55%;
    --chart-4: 280 65% 60%;
    --chart-5: 340 75% 55%;
  }
}

@layer base {
  * {
    @apply border-border;
  }
  body {
    @apply bg-background text-foreground;
  }
}

.color-bg {
  background-image: radial-gradient(at 27% 37%, #0284c7 0, transparent 0),
    radial-gradient(at 97% 21%, #0284c7b0 0, transparent 50%),
    radial-gradient(at 52% 99%, #0284c7b0 0, transparent 50%),
    radial-gradient(at 10% 29%, #0284c7 0, transparent 50%),
    radial-gradient(at 97% 96%, #95c6e4 0, transparent 50%),
    radial-gradient(at 33% 50%, #ffffff 0, transparent 50%),
    radial-gradient(at 79% 53%, #ffffff00 0, transparent 50%);
}

.color-bg-ui {
  background-image: radial-gradient(at 27% 37%, #0284c7 0, transparent 0),
    radial-gradient(at 100% 0%, #0285c7 0, transparent 40%),
    radial-gradient(at 0% 100%, #0285c7 0, transparent 40%),
    radial-gradient(at 100% 96%, #95c6e4 0, transparent 20%),
    radial-gradient(at 13% 60%, #ffffff 0, transparent 50%),
    radial-gradient(at 79% 53%, #ffffff 0, transparent 50%);
}

.drops {
  position: relative;
  overflow: hidden;
}

.drops::before {
  content: '';
  position: absolute;
  top: -100%; /* Start above the bar */
  left: 0;
  right: 0;
  width: 100%;
  height: 50%;
  background: linear-gradient(to bottom, transparent, #1e3a8a);
  animation: drop-animation 15s linear infinite;
}

@keyframes drop-animation {
  0% {
    top: -200%;
  }
  100% {
    top: 200%;
  }
}

.drops2 {
  position: relative;
  overflow: hidden;
}

.drops2::before {
  content: '';
  position: absolute;
  top: -100%; /* Start above the bar */
  left: 0;
  right: 0;
  width: 100%;
  height: 50%;
  background: linear-gradient(to bottom, transparent, #0284c7);
  animation: drop-animation 10s linear infinite;
}

.drops3 {
  position: relative;
  overflow: hidden;
}

.drops3::before {
  content: '';
  position: absolute;
  top: -100%; /* Start above the bar */
  left: 0;
  right: 0;
  width: 100%;
  height: 50%;
  background: linear-gradient(to bottom, transparent, #1e3a8a);
  animation: drop-animation 18s linear infinite;
}

.drops4 {
  position: relative;
  overflow: hidden;
}

.drops4::before {
  content: '';
  position: absolute;
  top: -100%; /* Start above the bar */
  left: 0;
  right: 0;
  width: 100%;
  height: 50%;
  background: linear-gradient(to bottom, transparent, #1d4ed8);
  animation: drop-animation 22s linear infinite;
}

.shimmer path {
  opacity: 0.5;
  animation: shimmer 3s infinite;
}
.shimmer path:nth-child(1) {
  animation-delay: 0s;
}
.shimmer path:nth-child(2) {
  animation-delay: 2s;
}
.shimmer path:nth-child(3) {
  animation-delay: 4s;
}

@keyframes shimmer {
  0%,
  100% {
    opacity: 0.5;
    scale: 1;
  }
  50% {
    opacity: 1;
    scale: 1.05;
  }
}

html {
  overflow-x: hidden;
}

.box {
  position: relative;
  transform-style: preserve-3d;
}

.box::before {
  content: '';
  position: absolute;
  inset: 0px;
  background: radial-gradient(49% 81% at 45% 47%, rgb(5, 62, 115) 0%, #073aff00 100%),
    radial-gradient(113% 91% at 17% -2%, rgba(1, 40, 75, 0.548) 0%, #ff000000 99%),
    radial-gradient(142% 91% at 83% 7%, rgba(6, 30, 75, 0) 1%, #ff000000 99%),
    radial-gradient(142% 91% at -6% 74%, rgba(174, 196, 255, 0) 1%, #ff000000 99%),
    radial-gradient(142% 91% at 111% 84%, rgb(52, 125, 193) 0%, #ffffffff 99%);
  filter: blur(15px);
  opacity: 0.3;
  transform: translate3d(0px, 0px, -1px);
  pointer-events: none;
}

.box-inside {
  background: radial-gradient(49% 81% at 45% 47%, rgba(52, 125, 193, 0.249) 0%, #073aff00 100%),
    radial-gradient(113% 91% at 17% -2%, rgba(131, 170, 207, 0.348) 0%, #ff000000 99%),
    radial-gradient(142% 91% at 83% 7%, rgba(164, 138, 249, 0.326) 1%, #ff000000 99%),
    radial-gradient(142% 91% at -6% 74%, rgba(174, 196, 255, 0.735) 1%, #ff000000 99%),
    radial-gradient(142% 91% at 111% 84%, rgba(52, 125, 193, 0.37) 0%, #ffffffff 99%);
}

.vds-video-layout .vds-time-slider .vds-slider-value {
  background-color: var(--video-time-bg, unset);
  text-shadow:
    0px 0px 0px #333333,
    0px 0px 0px #333333,
    0px 0px 0px #333333,
    0px 0px 0px #333333 !important;
}

:where(.vds-video-layout .vds-time-slider .vds-slider-chapter-title) {
  text-shadow:
    0px 0px 0px #333333,
    0px 0px 0px #333333,
    0px 0px 0px #333333,
    0px 0px 0px #333333 !important;
}

:where(.vds-poster) {
  height: auto !important;
}

.vds-audio-layout,
.vds-video-layout {
  /* Shared. */
  --media-brand: #f5f5f5;
  --media-controls-color: #f5f5f5;
  --media-font-family: 'Inter', sans-serif;

  /* Buffering. */
  --media-buffering-animation: vds-buffering-spin 1s linear infinite;
  --media-buffering-size: 96px;
  --media-buffering-track-color: #f5f5f5;
  --media-buffering-track-fill-color: var(--media-brand);
  --media-buffering-track-fill-offset: 50;
  --media-buffering-track-fill-opacity: 0.75;
  --media-buffering-track-fill-width: 9;
  --media-buffering-track-opacity: 0.25;
  --media-buffering-track-width: 8;
  --media-buffering-transition: opacity 200ms ease;

  /* Buttons. */
  --media-button-border-radius: 8px;
  --media-button-color: var(--media-controls-color, #f5f5f5);
  --media-button-hover-bg: rgb(255 255 255 / 0.2);
  --media-button-hover-transform: scale(1);
  --media-button-hover-transition: transform 0.2s ease-in;
  --media-button-icon-size: 80%;
  --media-button-padding: 0px;
  --media-button-size: 40px;
  --media-button-touch-hover-bg: rgb(255 255 255 / 0.2);
  --media-button-touch-hover-border-radius: 100%;
  --media-sm-fullscreen-button-size: 42px;
  --media-fullscreen-button-size: 42px;

  /* Tooltips. */
  --media-tooltip-bg-color: black;
  --media-tooltip-border-radius: 4px;
  --media-tooltip-border: 1px solid rgb(255 255 255 / 0.1);
  --media-tooltip-color: hsl(0, 0%, 80%);
  --media-tooltip-font-size: 13px;
  --media-tooltip-font-weight: 500;
  --media-tooltip-padding: 2px 8px;
  --media-tooltip-enter-animation: vds-tooltip-enter 0.2s ease-in;
  --media-tooltip-exit-animation: vds-tooltip-exit 0.2s ease-out;

  /* Live Indicator. */
  --media-live-button-bg: #8a8a8a;
  --media-live-button-border-radius: 2px;
  --media-live-button-color: #161616;
  --media-live-button-edge-bg: #dc2626;
  --media-live-button-edge-color: #f5f5f5;
  --media-live-button-font-size: 12px;
  --media-live-button-font-weight: 600;
  --media-live-button-height: 40px;
  --media-live-button-letter-spacing: 1.5px;
  --media-live-button-padding: 1px 4px;
  --media-live-button-width: 40px;

  /* Captions. */
  --media-captions-padding: 1%;
  --media-cue-backdrop: blur(8px);
  --media-cue-bg: rgba(0, 0, 0, 0.7);
  --media-cue-border-radius: 2px;
  --media-cue-border: unset;
  --media-cue-box-shadow: var(--cue-box-shadow);
  --media-cue-color: white;
  --media-cue-display-bg: unset;
  --media-cue-display-border-radius: unset;
  --media-cue-display-padding: unset;
  --media-cue-font-size: calc(var(--overlay-height) / 100 * 4.5);
  --media-cue-line-height: calc(var(--cue-font-size) * 1.2);
  --media-cue-padding-x: calc(var(--cue-font-size) * 0.4);
  --media-cue-padding-x: calc(var(--cue-font-size) * 0.6);

  /* Chapter Title. */
  --media-chapter-title-color: rgba(255 255 255 / 0.64);
  --media-chapter-title-font-size: 14px;
  --media-chapter-title-font-weight: 500;
  --media-chapter-title-separator-color: var(--color);
  --media-chapter-title-separator-gap: 6px;
  --media-chapter-title-separator: '\2022';

  /* Controls. */
  --media-controls-padding: 0px;
  --media-controls-in-transition: opacity 0.2s ease-in;
  --media-controls-out-transition: opacity 0.2s ease-out;

  /* Thumbnails. */
  --media-thumbnail-bg: black;
  --media-thumbnail-border: 1px solid white;
  --media-thumbnail-aspect-ratio: 16 / 9;
  --media-thumbnail-min-width: 120px;
  --media-thumbnail-min-height: calc(var(--media-thumbnail-min-width) / var(--aspect-ratio));
  --media-thumbnail-max-width: 180px;
  --media-thumbnail-max-height: calc(var(--media-thumbnail-max-width) / var(--aspect-ratio));

  /* Time. */
  --media-time-bg: unset;
  --media-time-border-radius: unset;
  --media-time-border: unset;
  --media-time-color: #f5f5f5;
  --media-time-divider-color: #e0e0e0;
  --media-time-divider-gap: 2.5px;
  --media-time-font-size: 14px;
  --media-time-font-weight: 400;
  --media-time-letter-spacing: 0.025em;

  /* Sliders. */
  --media-slider-width: 100%;
  --media-slider-height: 48px;

  /* Slider Thumb. */
  --media-slider-thumb-bg: #fff;
  --media-slider-thumb-border-radius: 9999px;
  --media-slider-thumb-border: 1px solid #cacaca;
  --media-slider-thumb-size: 15px;
  --media-slider-thumb-transition: opacity 0.2s ease-in, box-shadow 0.2s ease;

  /* Slider Tracks. */
  --media-slider-track-width: 100%;
  --media-slider-track-bg: rgb(255 255 255 / 0.3);
  --media-slider-track-border-radius: 1px;
  --media-slider-track-fill-bg: var(--media-brand);
  --media-slider-track-fill-live-bg: #dc2626;
  --media-slider-track-height: 5px;
  --media-slider-track-progress-bg: rgb(255 255 255 / 0.5);
  --media-slider-focused-thumb-shadow: 0 0 0 0px hsla(0, 0%, 100%, 0);
  --media-slider-focused-thumb-size: calc(var(--thumb-size) * 1.1);
  --media-slider-focused-track-height: calc(var(--track-height) * 1.25);
  --media-slider-focused-track-height: var(--track-height);
  --media-slider-focused-track-width: calc(var(--track-width) * 1.25);
  --media-slider-focused-track-width: var(--track-width);

  /* Slider Steps. */
  --media-slider-step-width: 2.5px;
  --media-slider-step-color: rgb(124, 124, 124);

  /* Slider Chapter. */
  --media-slider-chapter-hover-transform: scaleY(2);
  --media-slider-chapter-hover-transition: transform 0.1s cubic-bezier(0.4, 0, 1, 1);

  /* Slider Preview. */
  --media-slider-preview-bg: unset;
  --media-slider-preview-border-radius: 2px;

  /* Slider Chapter Title. */
  --media-slider-chapter-title-bg: unset;
  --media-slider-chapter-title-color: #f5f5f5;
  --media-slider-chapter-title-font-size: 14px;
  --media-slider-chapter-title-gap: 6px;

  /* Slider Value. */
  --media-slider-value-bg: black;
  --media-slider-value-border-radius: 2px;
  --media-slider-value-border: unset;
  --media-slider-value-color: white;
  --media-slider-value-gap: 0px;
  --media-slider-value-padding: 1px 10px;

  /* Menu Theme. */
  --media-menu-color-gray-50: rgb(245 245 245 / 0.1);
  --media-menu-color-gray-100: rgb(245 245 245 / 0.45);
  --media-menu-color-gray-200: rgb(10 10 10 / 0.6);
  --media-menu-color-gray-300: rgb(27 27 27);

  /* Menu Text. */
  --media-menu-text-color: #f5f5f5;
  --media-menu-text-secondary-color: #6b6b6b;

  /* Menu. */
  --media-menu-bg: var(--media-menu-bg, var(--color-gray-400));
  --media-menu-border-radius: 4px;
  --media-menu-border: 1px solid rgb(255 255 255 / 0.1);
  --media-menu-box-shadow: 1px 1px 1px rgb(10 10 10 / 0.5);
  --media-menu-divider: 1px solid var(--color-gray-50);
  --media-menu-font-size: 14px;
  --media-menu-font-weight: 500;
  --media-menu-max-height: 250px;
  --media-menu-min-width: 220px;
  --media-menu-padding: 12px;
  --media-menu-top-bar-bg: rgb(10 10 10 / 0.6);
  --media-menu-arrow-icon-size: 18px;
  --media-menu-icon-rotate-deg: 90deg;

  --media-menu-enter-animation: vds-menu-enter 0.3s ease-out;
  --media-menu-exit-animation: vds-menu-exit 0.2s ease-out;

  --media-menu-scrollbar-track-bg: transparent;
  --media-menu-scrollbar-thumb-bg: var(--color-gray-50);

  --media-sm-menu-landscape-max-height: min(70vh, 400px);
  --media-sm-menu-portrait-max-height: 40vh;

  /* Menu Section. */
  --media-menu-section-bg: var(--color-gray-300);
  --media-menu-section-border: unset;
  --media-menu-section-divider: var(--divider);
  --media-menu-section-header-font-size: 12px;
  --media-menu-section-header-font-weight: 500;
  --media-menu-section-gap: 8px;
  --media-menu-section-border-radius: 2px;

  /* Menu Item. */
  --media-menu-item-bg: transparent;
  --media-menu-item-border-radius: 2px;
  --media-menu-item-border: 0;
  --media-menu-item-height: 40px;
  --media-menu-item-hover-bg: var(--color-gray-50);
  --media-menu-item-icon-size: 18px;
  --media-menu-item-icon-spacing: 6px;
  --media-menu-item-padding: 10px;

  /* Menu Radio. */
  --media-menu-radio-icon-color: var(--text-color);

  /* Menu Checkbox. */
  --media-menu-checkbox-width: 40px;
  --media-menu-checkbox-height: 18px;
  --media-menu-checkbox-bg-active: #1ba13f;
  --media-menu-checkbox-bg: var(--color-gray-100);
  --media-menu-checkbox-handle-bg: #f5f5f5;
  --media-menu-checkbox-handle-border: unset;
  --media-menu-checkbox-handle-diameter: calc(var(--checkbox-height) - 2px);

  /* Menu Slider. */
  --media-menu-slider-height: 32px;
  --media-menu-slider-track-bg: var(--color-gray-50);
  --media-menu-slider-track-fill-bg: var(--color-inverse);

  /* Menu Hint. */
  --media-menu-hint-color: var(--text-secondary-color);
  --media-menu-hint-font-size: 13px;
  --media-menu-hint-font-weight: 400;

  /* Chapters Menu. */
  --media-chapters-divider: var(--divider);
  --media-chapters-duration-bg: unset;
  --media-chapters-duration-border-radius: 2px;
  --media-chapters-focus-padding: 4px;
  --media-chapters-item-active-bg: var(--color-gray-50);
  --media-chapters-item-active-border-left: unset;
  --media-chapters-min-width: var(--media-menu-min-width, 220px);
  --media-chapters-padding: 0;
  --media-chapters-progress-bg: var(--color-inverse);
  --media-chapters-progress-border-radius: 0;
  --media-chapters-progress-height: 4px;
  --media-chapters-start-time-border-radius: 2px;
  --media-chapters-start-time-letter-spacing: 0.4px;
  --media-chapters-start-time-padding: 1px 4px;
  --media-chapters-thumbnail-border: 0;
  --media-chapters-thumbnail-gap: 12px;
  --media-chapters-thumbnail-max-height: 68px;
  --media-chapters-thumbnail-max-width: 120px;
  --media-chapters-thumbnail-min-height: 56px;
  --media-chapters-thumbnail-min-width: 100px;
  --media-chapters-time-font-size: 12px;
  --media-chapters-time-font-weight: 500;
  --media-chapters-time-gap: 6px;
  --media-chapters-with-thumbnails-min-width: 300px;
}

.NavigationMenuIndicator[data-state='visible'] {
  animation: fadeIn 200ms ease;
}
.NavigationMenuIndicator[data-state='hidden'] {
  animation: fadeOut 200ms ease;
}

@keyframes float-left-right {
  0%,
  100% {
    transform: translateX(-200px);
  }
  50% {
    transform: translateX(700px);
  }
}
@keyframes float-right-left {
  0%,
  100% {
    transform: translateX(200px);
  }
  50% {
    transform: translateX(-700px);
  }
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

strong {
  font-weight: semibold;
}

body {
  background-color: #ffffff;
}

main {
  background-color: #ffffff;
}

.path {
  animation: pathAnimation 24s ease-in-out infinite;
  stroke-dasharray: 612.5;
  stroke-dashoffset: 0;
}

.path0 {
  --stroke-dashoffset: 1000;
}

.path2 {
  --stroke-dashoffset: 2000;
}

.path4 {
  --stroke-dashoffset: 3000;
}

.path6 {
  --stroke-dashoffset: 4000;
}

.path8 {
  --stroke-dashoffset: 5000;
}

.grecaptcha-badge {
  visibility: hidden;
}

@keyframes pathAnimation {
  0% {
    stroke-dashoffset: var(--stroke-dashoffset);
  }
  50% {
    stroke-dashoffset: 0;
  }
  100% {
    stroke-dashoffset: var(--stroke-dashoffset);
  }
}

/* Navigation Menu Animations */
@keyframes enterFromLeft {
  from {
    opacity: 0;
    transform: translateX(-100px) translateY(-8px);
  }
  to {
    opacity: 1;
    transform: translateX(0) translateY(0);
  }
}

@keyframes enterFromRight {
  from {
    opacity: 0;
    transform: translateX(100px) translateY(-8px);
  }
  to {
    opacity: 1;
    transform: translateX(0) translateY(0);
  }
}

@keyframes exitToLeft {
  from {
    opacity: 1;
    transform: translateX(0) translateY(0);
  }
  to {
    opacity: 0;
    transform: translateX(-100px) translateY(-8px);
  }
}

@keyframes exitToRight {
  from {
    opacity: 1;
    transform: translateX(0) translateY(0);
  }
  to {
    opacity: 0;
    transform: translateX(100px) translateY(-8px);
  }
}

@keyframes scaleInContent {
  from {
    opacity: 0;
    transform: scale(0.95) translateY(-8px);
  }
  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

@keyframes scaleOutContent {
  from {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
  to {
    opacity: 0;
    transform: scale(0.9) translateY(-8px);
  }
}

.animate-enter-from-left {
  animation: enterFromLeft 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}

.animate-enter-from-right {
  animation: enterFromRight 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}

.animate-exit-to-left {
  animation: exitToLeft 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.animate-exit-to-right {
  animation: exitToRight 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.animate-scale-in-content {
  animation: scaleInContent 0.35s cubic-bezier(0.16, 1, 0.3, 1);
  transform-origin: top right !important;
}

.animate-scale-out-content {
  animation: scaleOutContent 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  transform-origin: top center !important;
}

/* Ensure Radix NavigationMenu viewport animates in/out based on data-state */
.nav-viewport {
  transition:
    width 300ms,
    height 300ms,
    transform 300ms;
}
.nav-viewport[data-state='open'] {
  animation: scaleInContent 0.35s cubic-bezier(0.16, 1, 0.3, 1);
  transform-origin: top right !important;
}
.nav-viewport[data-state='closed'] {
  animation: scaleOutContent 0.25s cubic-bezier(0.4, 0, 0.2, 1);
  transform-origin: top center !important;
}



================================================
FILE: app/layout.js
================================================
import { Inter } from 'next/font/google';
import './globals.css';
import '../styles/animations.css';
import { Toaster } from '@/components/ui/toaster';
import Script from 'next/script';
import { ReactScan } from '@/components/react-scan';

const inter = Inter({ subsets: ['latin'] });

export const viewport = {
  themeColor: 'white',
};

export const metadata = {
  metadataBase: new URL('https://koellabs.com'),
  title: {
    template: '%s | Koel Labs',
    default:
      'Koel Labs - Building out state-of-the-art models, tools, and datasets to make speech technologies more inclusive for all dialects.',
  },
  description:
    'A research lab building out state-of-the-art models, tools, and datasets to make speech technologies more inclusive for all dialects. We are a team of researchers and engineers inspired by our own experiences with language.',
  keywords: [
    'pronunciation learning',
    'AI language learning',
    'speech technology',
    'language education',
    'pronunciation assessment',
  ],
  openGraph: {
    title: 'Koel Labs',
    description:
      'A research lab building out state-of-the-art models, tools, and datasets to make speech technologies more inclusive for all dialects. We are a team of researchers and engineers inspired by our own experiences with language.',
    url: 'https://koellabs.com',
    siteName: 'Koel Labs',
    images: [
      {
        url: '/openGraph.png',
        width: 1600,
        height: 900,
        alt: 'An image with Koel Labs written on it.',
      },
    ],
    locale: 'en_US',
    type: 'website',
  },
  robots: {
    index: true,
    follow: true,
    googleBot: {
      index: true,
      follow: true,
      'max-video-preview': -1,
      'max-image-preview': 'large',
      'max-snippet': -1,
    },
  },
  twitter: {
    title: 'Koel Labs',
    card: 'summary_large_image',
    description:
      'A research lab building out state-of-the-art models, tools, and datasets to make speech technologies more inclusive for all dialects. We are a team of researchers and engineers inspired by our own experiences with language.',
    images: ['/openGraph.png'],
  },
  alternates: {
    canonical: 'https://koellabs.com',
  },
};

export default function RootLayout({ children }) {
  return (
    <html lang="en" className="scroll-smooth overflow-x-hidden">
      <ReactScan />
      <head>
        <Script id="org-schema" type="application/ld+json">
          {`
            {
              "@context": "https://schema.org",
              "@type": "Organization",
              "name": "Koel Labs",
              "alternateName": ["KoelLabs", "Koel"],
              "url": "https://koellabs.com",
              "logo": "https://koellabs.com/logo.png",
              "sameAs": [
                "https://twitter.com/koellabs",
                "https://github.com/koellabs",
                "https://www.linkedin.com/company/koellabs"
              ],
              "description": "Koel Labs is your new favorite tool for pronunciation learning. Other methods for pronunciation learning are often outdated, lack accessibility, and are ultimately boring. Language learners, like us and our families, desperately need a change—and we aim to be just that.",
              "foundingDate": "2024",
              "knowsAbout": [
                "Pronunciation Learning",
                "Speech Technology",
                "Artificial Intelligence",
                "Language Education",
                "Educational Technology"
              ],
              "areaServed": "Worldwide",
              "email": "info@koellabs.com",
              "founders": [
                {
                  "@type": "Person",
                  "name": "Alexander Metzger",
                  "jobTitle": "Chief Executive Officer",
                  "image": "https://koellabs.com/images/alexShot.png",
                  "sameAs": "https://www.linkedin.com/in/alexander-le-metzger/"
                },
                {
                  "@type": "Person",
                  "name": "Aruna Srivastava",
                  "jobTitle": "Chief Technology Officer",
                  "image": "https://koellabs.com/images/arunaShot.png",
                  "sameAs": "https://www.linkedin.com/in/arunasr/"
                },
                {
                  "@type": "Person",
                  "name": "Ruslan Mukhamedvaleev",
                  "jobTitle": "Chief Product Officer",
                  "image": "https://koellabs.com/images/ruslanShot.png",
                  "sameAs": [
                    "https://github.com/digitalRM",
                    "https://www.linkedin.com/in/ruslan-muk/", 
                    "https://www.instagram.com/ruslan_mk11/",
                    "https://www.ruslan.in",
                    "https://builders.mozilla.org/profile/ruslan-mukhamedvaleev/"
                  ]
                }
              ]
            }
          `}
        </Script>
      </head>
      <body className={`${inter.className} dark:bg-black`}>
        {children}
        <Toaster />
      </body>
    </html>
  );
}



================================================
FILE: app/not-found.js
================================================
import React from 'react';
import { Button } from '@/components/ui/base/button';
import { ArrowLeftIcon, ArrowRightIcon, MailIcon } from 'lucide-react';
import Link from 'next/link';
export default function NotFound() {
  return (
    <div className="w-full lg:grid lg:min-h-screen xl:min-h-screen dark:bg-neutral-950/[0.99] ">
      <div className="color-bg h-full w-11/12 left-0 right-0 mx-auto absolute z-1 blur-[64px] transform-gpu opacity-10"></div>
      <div className="bg-muted relative rounded-xl m-4 overflow-hidden dark:bg-neutral-900/[0.25]">
        <div className="mx-auto absolute top-0 left-0 right-0 bottom-0 h-full flex justify-between z-10 rotate-45 scale-2 opacity-35">
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
        </div>
        <div className="grid min-h-full place-items-center px-6 py-24 sm:py-32 lg:px-8 relative z-10">
          <div className="text-center lg:backdrop-blur-xs lg:bg-white/50 rounded-full lg:border lg:border-neutral-300/50 lg:aspect-square lg:p-24 flex flex-col items-center justify-center">
            <p className="text-base font-semibold text-sky-600">404</p>
            <h1 className="mt-4 text-balance text-5xl font-semibold tracking-tighter text-neutral-900 sm:text-7xl">
              Page Not Found
            </h1>
            <p className="mt-6 text-pretty text-lg font-base text-neutral-600 sm:text-xl/8">
              Sorry, we couldn’t find the page you’re looking for.
            </p>
            <div className="mt-10 flex items-center justify-center gap-x-3">
              <Link href="/">
                <Button className="w-full rounded-lg sm:w-40 bg-linear-to-b border border-double outline-white/50 outline-[0.1px] outline-offset-[-2px] border-black from-sky-900 to-blue-950">
                  <ArrowLeftIcon className="w-4 h-4 mr-2" />
                  Go back home
                </Button>
              </Link>
              <Link href="mailto:support@koellabs.com">
                <Button variant="outline" className="rounded-lg">
                  Contact support
                  <MailIcon className="w-4 h-4 ml-2 mt-px" />
                </Button>
              </Link>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}



================================================
FILE: app/page.js
================================================
'use client';

import Header from '@/components/ui/header';
import CTA from '@/components/sections/cta';
import Footer from '@/components/sections/footer';
import HeroNew from '@/components/sections/hero';
import Research from '@/components/sections/research';
import { useRef } from 'react';
import Models from '@/components/sections/models';
import Image from 'next/image';
import Autoplay from 'embla-carousel-autoplay';

import { Carousel, CarouselContent, CarouselItem } from '@/components/ui/base/carousel';
import Previews from '@/components/sections/previews';
import MagicHighlighter from '@/components/magic-highlighter';

const sliderImages = [
  '/images/frontpage/1-group.jpg',
  '/images/frontpage/2-aruna.jpg',
  '/images/frontpage/3-group.jpg',
  '/images/frontpage/4-alex.jpg',
  '/images/frontpage/5-group.jpg',
  '/images/frontpage/6-ruslan.jpg',
];

export default function Home() {
  const containerRef = useRef(null);

  return (
    <div ref={containerRef} className="flex-col flex w-screen relative scroll-smooth">
      <MagicHighlighter containerRef={containerRef} />
      <div
        data-cursor-opacity="0.3"
        data-cursor-size="240"
        className="z-9999 sticky top-0 mx-auto w-full"
      >
        <Header />
      </div>

      <HeroNew />

      <div
        data-cursor-opacity="0.8"
        data-cursor-size="240"
        data-cursor-color="#2A4BCC"
        className="z-10 relative"
      >
        <Research />
        <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-b">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
      </div>
      <div
        data-cursor-opacity="0.8"
        data-cursor-size="240"
        data-cursor-color="#2A4BCC"
        className="mx-auto md:px-6 lg:px-8 py-12 w-full bg-white z-[0] relative overflow-hidden flex items-center justify-center"
      >
        <div className="w-full h-full bg-radial from-transparent to-white via-white via-63% z-[0] absolute top-0 left-0 pointer-events-none"></div>
        <div
          data-cursor-opacity="0.8"
          data-cursor-size="240"
          data-cursor-color="#2A4BCC"
          className="mx-auto w-full scale-110 lg:scale-105 flex justify-center items-center rounded-3xl bg-white z-[5] relative min-w-[500px] "
        >
          <Carousel
            opts={{ loop: true, align: 'start' }}
            className="overflow-visible rounded-2xl w-full"
            plugins={[Autoplay({ delay: 5000 })]}
          >
            <CarouselContent className="overflow-visible" overflowVisible>
              {sliderImages.map((src, i) => (
                <CarouselItem key={i} className="lg:basis-1/3 p-[8px] border ml-2 rounded-[20px]">
                  <div className="relative aspect-video w-full overflow-hidden ring-1 ring-neutral-200 rounded-[12px] bg-white">
                    <Image
                      src={src}
                      alt={`Gallery image ${i + 1}`}
                      width={700}
                      height={600}
                      quality={50}
                      className="object-cover rounded-lg object-right-bottom grays cale transition-all duration-150"
                      priority={i < 4}
                      loading={i < 4 ? undefined : 'lazy'}
                    />
                  </div>
                </CarouselItem>
              ))}
            </CarouselContent>
          </Carousel>
        </div>
      </div>
      <div
        data-cursor-opacity="0.8"
        data-cursor-size="240"
        data-cursor-color="#2A4BCC"
        className="z-0 relative"
      >
        <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-t">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
        <Models />
      </div>
      <div
        data-cursor-opacity="0.8"
        data-cursor-size="240"
        data-cursor-color="#2A4BCC"
        className="z-0 relative"
      >
        <Previews />
        <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-b">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
      </div>
      <div className="w-full relative">
        <CTA />
      </div>
      <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
        <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
          {Array(500)
            .fill(0)
            .map((_, i) => (
              <div
                key={`bottom-${i}`}
                className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
              ></div>
            ))}
        </div>
      </div>

      <Footer />
    </div>
  );
}



================================================
FILE: app/about/page.tsx
================================================
import React from 'react';
import { Button } from '@/components/ui/base/button';
import Header from '@/components/ui/header';
import { ChevronRight, UserRoundPlus } from 'lucide-react';
import Link from 'next/link';
import { Card } from '@/components/ui/base/card';
import HeroVideoDialog from '@/components/ui/magicui/hero-video-dialog';
import CTA from '@/components/sections/cta';
import Footer from '@/components/sections/footer';

const people = [
  {
    name: 'Alexander Metzger',
    role: 'Chief Executive Officer',
    imageUrl: '/images/alexShot.png',
    linkedinUrl: 'https://www.linkedin.com/in/alexander-le-metzger/',
  },
  {
    name: 'Aruna Srivastava',
    role: 'Chief Technology Officer',
    imageUrl: '/images/arunaShot.png',
    linkedinUrl: 'https://www.linkedin.com/in/arunasr/',
  },
  {
    name: 'Ruslan Mukhamedvaleev',
    role: 'Chief Product Officer',
    imageUrl: '/images/ruslanShot.png',
    linkedinUrl: 'https://www.linkedin.com/in/ruslan-muk/',
  },
];

export default function About() {
  return (
    <div className="relative">
      <div className="z-[9999] sticky top-0 mx-auto w-full">
        <Header />
      </div>
      <div className="absolute right-0 -top-20 w-full h-[500px] bg-gradient-to-b from-white via-10% via-white to-transparent z-[0]"></div>

      <div className="absolute right-0 -top-20 w-[50.5px] h-[100%] overflow-hidden items-start justify-center bg-neutral-50 border-x z-[-1] hidden 2xl:flex shadow-xl">
        <div className="flex-col h-full items-start gap-[8px] mt-[2px] flex">
          {Array(165)
            .fill(0)
            .map((_, i) => (
              <div
                key={`right-${i}`}
                className="h-px w-[50.5px] bg-neutral-200 dark:bg-neutral-800"
              ></div>
            ))}
        </div>
      </div>
      <div className="absolute left-0 -top-20 w-[50.5px] h-[100%] overflow-hidden items-start justify-center bg-neutral-50 border-x z-[-1] hidden 2xl:flex shadow-xl">
        <div className="flex-col h-full items-start gap-[8px] mt-[2px] flex">
          {Array(165)
            .fill(0)
            .map((_, i) => (
              <div
                key={`right-${i}`}
                className="h-px w-[50.5px] bg-neutral-200 dark:bg-neutral-800"
              ></div>
            ))}
        </div>
      </div>
      <div className="mx-auto pt-0 py-32 pb-0 relative">
        <div className="relative">
          <div className="relative">
            <div className="absolute left-0 bottom-0 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[20] hidden 2xl:block">
              <div className="rounded-full w-full h-full border bg-white"></div>
            </div>

            <div className="absolute right-0 bottom-0 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[20] hidden 2xl:block">
              <div className="rounded-full w-full h-full border bg-white"></div>
            </div>
            <div className="mx-auto max-w-7xl px-6 py-16 pt-0 sm:py-40 lg:px-8 relative">
              <div className="mx-auto max-w-2xl lg:mx-0 mt-0 sm:mt-24 lg:mt-0 lg:my-12 lg:grid lg:max-w-none lg:grid-cols-2 lg:gap-x-16 lg:gap-y-8 xl:grid-cols-1 xl:grid-rows-1 xl:gap-x-8">
                {/* <h1 class="max-w-2xl text-balance text-5xl font-semibold tracking-tight text-gray-900 sm:text-7xl lg:col-span-2 xl:col-auto">We’re changing the way people connect</h1> */}
                <h1 className="max-w-2xl xss:text-3xl pt-12 text-balance text-3xl font-semibold tracking-tighter text-gray-950 sm:text-6xl lg:col-span-2 xl:col-auto">
                  Building Inclusive <span className="text-[#003a59]">Speech Technology</span>
                </h1>
                <div className="mt-6 max-w-xl lg:mt-0 xl:col-end-1 xl:row-start-1">
                  <p className="sm:text-lg/8 text-neutral-600">
                    Your voice is unique and should be understood not just by those around you, but
                    also by the technology you interact with every day.
                  </p>
                  <p className="sm:text-lg/8 text-neutral-600 mt-4">
                    Too often, voice assistants and smart speakers struggle with accents, speech
                    differences, or non-standard dialects, leaving millions of people frustrated and
                    unheard.
                  </p>
                  <p className="sm:text-lg/8 text-neutral-600 mt-4">
                    As a research lab, we collaborate with top universities, other researchers, and
                    domain experts to create technologies that actually understand your voice.
                  </p>
                  <div className="flex gap-x-2">
                    <p className="text-pretty text-md font-medium text-neutral-600 mt-8">—</p>
                    <img
                      alt="Koel Labs Signature"
                      src="/images/koelLabsSig.png"
                      className="mt-6 w-1/2 sm:w-1/5 opacity-75"
                    />
                  </div>
                </div>
                <div className="mt-10 w-full md:max-w-lg rounded-[24px] object-cover sm:mt-16 lg:mt-0 xl:mt-8 lg:max-w-none xl:row-span-2 xl:row-end-2 p-2 bg-white/75 backdrop-blur-md border">
                  <img
                    alt="A photo of the Koel Labs founders, Alexander Metzger, Aruna Srivastava, and Ruslan Mukhamedvaleev standing in front of the bay bridge in San Francisco."
                    src="/images/aboutShot.jpeg"
                    className=" aspect-5/5 scale w-full md:max-w-lg rounded-2xl object-cover object-[23%] lg:max-w-none xl:row-span-2 xl:row-end-2 border"
                  />
                  <div className="w-full h-12 rounded-2xl mt-2 border relative gap-y-2 flex items-center overflow-hidden justify-center">
                    {Array(120)
                      .fill(0)
                      .map((_, i) => (
                        <div
                          key={`bottom-${i}`}
                          className="h-[200%] w-px bg-neutral-200 dark:bg-neutral-800 -ml-1 -mr-1 rotate-45"
                        ></div>
                      ))}
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div className="bg-white/50 backdrop-blur-md border border-neutral-300/50">
            <div className="mx-auto max-w-7xl px-6 lg:px-8 py-36">
              <div className="mx-auto max-w-6xl lg:mx-0">
                <p className="text-lg font-semibold text-sky-600 mb-2">The Team</p>
                <h2 className="text-pretty text-4xl font-semibold tracking-tight text-neutral-900 sm:text-5xl">
                  Our Co-Founders
                </h2>
                <p className="mt-6 sm:text-lg/8 text-neutral-600">
                  Koel Labs began with three students sharing a common vision. As immigrants and
                  children of immigrants, the experience of language barriers shaped our
                  understanding of how pronunciation challenges impact confidence and opportunities.
                </p>
              </div>
              <ul
                role="list"
                className="mx-auto mt-20 grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 sm:grid-cols-2 lg:mx-0 lg:max-w-none lg:grid-cols-3"
              >
                {people.map(person => (
                  <li key={person.name}>
                    <img
                      alt={`A photo of ${person.name}, ${person.role} at Koel Labs`}
                      src={person.imageUrl}
                      className="aspect-square w-full rounded-2xl object-cover"
                    />
                    <h3 className="mt-6 text-lg/8 font-semibold tracking-tight text-gray-900">
                      {person.name}
                    </h3>
                    <p className="text-base/7 text-neutral-500">{person.role}</p>
                    <ul role="list" className="mt-6 flex gap-x-6">
                      <li>
                        <a href={person.linkedinUrl} className="text-gray-400 hover:text-gray-500">
                          <span className="sr-only">LinkedIn</span>
                          <svg
                            fill="currentColor"
                            viewBox="0 0 20 20"
                            aria-hidden="true"
                            className="size-5"
                          >
                            <path
                              d="M16.338 16.338H13.67V12.16c0-.995-.017-2.277-1.387-2.277-1.39 0-1.601 1.086-1.601 2.207v4.248H8.014v-8.59h2.559v1.174h.037c.356-.675 1.227-1.387 2.526-1.387 2.703 0 3.203 1.778 3.203 4.092v4.711zM5.005 6.575a1.548 1.548 0 11-.003-3.096 1.548 1.548 0 01.003 3.096zm-1.337 9.763H6.34v-8.59H3.667v8.59zM17.668 1H2.328C1.595 1 1 1.581 1 2.298v15.403C1 18.418 1.595 19 2.328 19h15.34c.734 0 1.332-.582 1.332-1.299V2.298C19 1.581 18.402 1 17.668 1z"
                              clipRule="evenodd"
                              fillRule="evenodd"
                            />
                          </svg>
                        </a>
                      </li>
                    </ul>
                  </li>
                ))}
              </ul>
            </div>
          </div>
        </div>
        <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-b">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
        <div className="w-full relative bg-white">
          <CTA />
        </div>
        <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
        <Footer />
      </div>
    </div>
  );
}



================================================
FILE: app/api/auth/[...all]/route.ts
================================================
import { auth } from '@/lib/auth';
import { toNextJsHandler } from 'better-auth/next-js';

export const { POST, GET } = toNextJsHandler(auth);



================================================
FILE: app/api/auth/update-user/route.ts
================================================
import { NextResponse } from 'next/server';
import { auth } from '@/lib/auth';
import { db, users } from '@/db/schema';
import { eq } from 'drizzle-orm';

export async function POST(request: Request) {
  try {
    // Get the current session
    const session = await auth.api.getSession({ headers: request.headers });

    if (!session || !session.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    // Parse the request body
    const { name } = await request.json();

    // Update the user record with the new name
    await db
      .update(users)
      .set({
        name: name,
        updatedAt: new Date(),
      })
      .where(eq(users.id, session.user.id));

    return NextResponse.json({ success: true });
  } catch (error) {
    console.error('Error updating user information:', error);
    return NextResponse.json({ error: 'Failed to update user information' }, { status: 500 });
  }
}



================================================
FILE: app/api/user/preferences/route.ts
================================================
import { NextResponse } from 'next/server';
import { auth } from '@/lib/auth';
import { db, users } from '@/db/schema';
import { eq } from 'drizzle-orm';

export async function POST(request: Request) {
  try {
    const session = await auth.api.getSession({ headers: request.headers });

    if (!session || !session.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const body = await request.json();
    const {
      nativeLanguage,
      nativeLanguageCountry,
      birthday,
      targetLanguage,
      experienceLevel,
      learningCity,
      challengingWords,
      hasConsented,
      avatar,
    } = body;

    const metadata = {
      nativeLanguage,
      nativeLanguageCountry,
      birthday,
      targetLanguage,
      experienceLevel,
      learningCity,
      challengingWords,
      hasConsented,
      lastUpdated: new Date().toISOString(),
    };

    await db
      .update(users)
      .set({
        metadata: JSON.stringify(metadata),
        ...(avatar ? { image: avatar } : {}),
        onboardingCompleted: true,
        updatedAt: new Date(),
      })
      .where(eq(users.id, session.user.id));

    return NextResponse.json({ success: true });
  } catch (error) {
    console.error('Error updating user preferences:', error);
    return NextResponse.json({ error: 'Failed to update preferences' }, { status: 500 });
  }
}



================================================
FILE: app/blog/bloglist.tsx
================================================
// Component to display the lists of blog posts by category.

import React from 'react';
import { ArrowUpRight } from 'lucide-react';
import { Card } from '@/components/ui/base/card';
import HeroVideoDialog from '@/components/ui/magicui/hero-video-dialog';
import Link from 'next/link';
import { getPosts } from './posts';
import type { Post } from './posts';
import { ArrowUpRightIcon } from 'lucide-react';
import CTA from '@/components/sections/cta';
import Footer from '@/components/sections/footer';

export const metadata = {
  title: 'Blog | Koel Labs Research and Updates',
  description:
    'Stay up to date with the latest research, technical reports, and announcements from Koel Labs about pronunciation learning and speech technology.',
};

function formatDate(dateString: string): string {
  const date = new Date(dateString);
  return date.toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  });
}

function PostCard({ post }: { post: Post }) {
  return (
    <article className="relative border p-2 rounded-3xl rounded-b-2xl bg-white font-sans shadow-xs flex flex-col justify-between">
      <div>
        <div className="relative flex h-fit flex-col overflow-hidden rounded-2xl border">
          <img
            alt={`Cover image for blog post: ${post.title}`}
            src={post.image}
            className="max-h-80 top-0 object-cover object-bottom aspect-video"
          />
        </div>
        <div className="relative flex flex-col justify-between  overflow-hidden rounded-2xl border mt-2">
          <div className="p-6 text-left">
            <h2 className="text-xl sm:text-xl lg:text-2xl max-w-full text-balance font-medium tracking-tight text-neutral-950">
              {post.title}
            </h2>

            <div className="flex flex-col sm:flex-row gap-1 justify-between mt-3">
              <div className="flex justify-center align-baseline sm:items-center gap-1 grayscale flex-col sm:flex-row text-left">
                <div className="text-neutral-600 flex items-center gap-1.5">
                  {/* {formatDate(dateISO)}
            {byline ? ` • ${byline}` : ''} */}
                  <div className=" -space-x-1 overflow-hidden inline-block">
                    <img
                      alt="A photo of Alexander Metzger"
                      src="/images/mini-alex.png"
                      className="inline-block size-6 rounded-full outline outline-1 -outline-offset-1 outline-black/5 ring-2 ring-white"
                    />
                    <img
                      alt="A photo of Aruna Srivastava"
                      src="/images/mini-aruna.png"
                      className="inline-block size-6 rounded-full outline outline-1 -outline-offset-1 outline-black/5 ring-2 ring-white"
                    />
                    <img
                      alt="A photo of Ruslan Mukhamedvaleev"
                      src="/images/mini-ruslan.png"
                      className="inline-block size-6 rounded-full outline outline-1 -outline-offset-1 outline-black/5 ring-2 ring-white"
                    />
                  </div>
                  By Koel Labs <span className="hidden sm:inline">·</span>
                </div>
                <time dateTime={post.date} className="text-neutral-600">
                  {formatDate(post.date)}
                </time>
              </div>
            </div>
          </div>
          <div className="px-6 pb-6 -mt-2 pt-1 h-full text-left">
            <p className="mt-2 max-w-lg text-sm/6 text-neutral-600">
              {post.summary.slice(0, 350)}
              {post.summary.length > 350 && '...'}
              <span className="text-sky-600">{post.summary.length > 350 && ' Read More →'}</span>
            </p>
          </div>
        </div>
      </div>
      <div className="relative flex flex-row gap-2 w-full">
        {/* <div className="flex flex-row gap-2 mt-2 min-w-fit">
          <span className="transition-all inline-flex items-center px-2 w-full py-1.5 border text-sm leading-4 font-medium tracking-tight rounded-xl text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 sm:w-fit flex-row justify-between hover:shadow-sm group">
            <div
              className={`h-2 w-2 rounded-full relative transition-all mr-1`}
              style={{
                backgroundColor: post.category === 'Technical Report' ? '#3779B5' : '#154063',
              }}
            ></div>
            {post.category}
          </span>
        </div> */}
        <div className="flex-row gap-2 mt-2 w-full hidden lg:flex">
          <span className="transition-all inline-flex items-center overflow-hidden w-full border text-sm leading-4 font-medium tracking-tight rounded-xl text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 flex-row justify-between hover:shadow-sm group gap-px">
            {Array(90)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-[200%] w-px bg-neutral-200 dark:bg-neutral-800 -ml-1 -mr-1 rotate-45"
                ></div>
              ))}
          </span>
        </div>

        <div className="flex-row gap-2 mt-2 w-full hidden md:flex lg:hidden">
          <span className="transition-all inline-flex items-center overflow-hidden w-full border text-sm leading-4 font-medium tracking-tight rounded-xl text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 flex-row justify-between hover:shadow-sm group gap-px">
            {Array(70)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-[200%] w-px bg-neutral-200 dark:bg-neutral-800 -ml-1 -mr-1 rotate-45"
                ></div>
              ))}
          </span>
        </div>

        <div className="flex-row gap-2 mt-2 w-full flex md:hidden">
          <span className="transition-all inline-flex items-center overflow-hidden w-full border text-sm leading-4 font-medium tracking-tight rounded-xl text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 flex-row justify-between hover:shadow-sm group gap-px">
            {Array(40)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-[200%] w-px bg-neutral-200 dark:bg-neutral-800 -ml-1 -mr-1 rotate-45"
                ></div>
              ))}
          </span>
        </div>

        <div className="flex flex-row gap-2 mt-2 min-w-fit">
          <span className="transition-all inline-flex items-center px-2 w-full py-1.5 border text-sm leading-4 font-medium tracking-tight rounded-xl text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 sm:w-fit flex-row justify-between hover:shadow-sm group">
            <div
              className={`h-2 w-2 rounded-full relative transition-all mr-1`}
              style={{
                backgroundColor: post.category === 'Technical Report' ? '#3779B5' : '#154063',
              }}
            ></div>
            {post.category}
          </span>
        </div>
      </div>
      <Link
        href={`/blog/${post.slug}`}
        className="absolute bottom-0 left-0 h-full w-full"
        aria-label={`Read full article: ${post.title}`}
      ></Link>
    </article>
  );
}

function BlogList({ posts }: { posts: Post[] }) {
  return (
    <div className="relative min-h-[900px] h-full">
      <div className="absolute right-0 -top-20 w-full h-[500px] bg-gradient-to-b from-white via-10% via-white to-transparent z-[0]"></div>

      <div className="absolute left-0 bottom-0 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[200] hidden 2xl:block border-b">
        <div className="rounded-full w-full h-full border bg-white"></div>
      </div>

      <div className="absolute right-0 bottom-0 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[200] hidden 2xl:block border-y">
        <div className="rounded-full w-full h-full border bg-white"></div>
      </div>
      {/* <div className="absolute right-0 -top-20 w-full h-[110%] bg-gradient-to-b from-[#0086FF] to-[#2A4BCC] z-[2] mix-blend-color pointer-events-none"></div> */}
      {/* <div className="absolute left-0 -top-20 w-[60px] h-[110%] bg-gradient-to-b from-[#0086FF] to-[#2A4BCC] z-[2] mix-blend-color"></div> */}

      <div className="mx-auto pt-0 lg:px-0 py-32 pb-0">
        <div className="mx-auto p-4 max-w-7xl py-32 z-[90] relative">
          <div className="mx-auto max-w-2xl px-6 lg:max-w-6xl lg:px-8 z-10 mb-20 -mt-12">
            <div className="px-2.5 py-0.5 border rounded-xl w-fit mb-3">
              <p className="text-base/7 font-semibold text-sky-600">Most Recent</p>
            </div>
            <h1
              id="recent-posts-heading"
              className="mt-2 text-pretty text-4xl font-semibold tracking-tighter text-neutral-950 sm:text-5xl"
            >
              Newsroom
            </h1>
          </div>
          <section
            aria-labelledby="hero-heading"
            className="text-center relative grid grid-cols-1 md:grid-cols-2 gap-4"
          >
            {/* <div className="flex flex-row justify-center items-center my-8"></div> */}
            {posts
              .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
              .splice(0, 2)
              .map(post => (
                <PostCard key={post.slug} post={post} />
              ))}
          </section>
        </div>

        {/* <div className="absolute -bottom-2  h-[65px] w-[90%] bg-gradient-to-b from-[#0086FF] to-[#2A4BCC] z-[3] mix-blend-color"></div> */}

        {/* <div className="absolute bottom-0 left-0 w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-t">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div> */}
        <div className="mx-auto absolute opacity-25 sm:opacity-100 top-0 left-0 right-0 bottom-0 lg:max-w-[1264px] flex justify-between z-[-1]">
          <div className="h-full"></div>
          <div className="w-[1px] h-full bg-gradient-to-b from-white via-30% via-neutral-200 to-neutral-200 translate-x-[7px]"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="w-[1px] h-full bg-gradient-to-b from-white via-30% via-neutral-200 to-neutral-200 -translate-x-1"></div>
          <div className="h-full"></div>
          <div className="w-[1px] h-full bg-gradient-to-b from-white via-30% via-neutral-200 to-neutral-200 translate-x-1"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="w-[1px] h-full bg-gradient-to-b from-white via-30% via-neutral-200 to-neutral-200 -translate-x-[7px]"></div>
          <div className="h-full"></div>
        </div>
        <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="141"
          height="906"
          fill="none"
          className="absolute -bottom-28 xl:-right-px hidden 2xl:block z-[-3]"
          viewBox="0 0 141 906"
        >
          <path
            stroke="#E5E5E5"
            d="M140.505 0C140.505 97.5.721-.44.707 97.06c-.008 57.199 0 447.333 0 610.999m139.798 197.003c0-97.5-139.784.441-139.798-97.059-.008-57.2 0-447.333 0-611"
          ></path>
        </svg>
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="141"
          height="906"
          fill="none"
          className="absolute rotate-180 -bottom-28 xl:left-0 hidden 2xl:block z-[-3]"
          viewBox="0 0 141 906"
        >
          <path
            stroke="#E5E5E5"
            d="M140.505 0C140.505 97.5.721-.44.707 97.06c-.008 57.199 0 447.333 0 610.999m139.798 197.003c0-97.5-139.784.441-139.798-97.059-.008-57.2 0-447.333 0-611"
          ></path>
        </svg>
      </div>
    </div>
  );
}

export default async function BlogListWrapper() {
  const posts = await getPosts();

  return (
    <div className="flex-col flex w-screen relative scroll-smooth z-0">
      <BlogList posts={posts} />

      <div id="technical-reports" className="relative">
        <div className="mx-auto p-4 max-w-7xl py-32 z-[0]">
          <div className="absolute left-0 -bottom-12.5 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[200] hidden 2xl:block border-b">
            <div className="rounded-full w-full h-full border bg-white"></div>
          </div>

          <div className="absolute right-0 -bottom-12.5 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[200] hidden 2xl:block border-b">
            <div className="rounded-full w-full h-full border bg-white"></div>
          </div>

          <div className="mx-auto max-w-2xl px-6 lg:max-w-6xl lg:px-8 z-10 mb-20 -mt-12">
            <h1
              id="recent-posts-heading"
              className="mt-2 text-pretty text-4xl font-semibold tracking-tighter text-neutral-950 sm:text-5xl"
            >
              Technical Reports
            </h1>
          </div>
          <section
            aria-labelledby="hero-heading"
            className="text-center relative grid grid-cols-1 md:grid-cols-2 gap-4"
          >
            {/* <div className="flex flex-row justify-center items-center my-8"></div> */}
            {posts
              .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
              .filter(post => post.category === 'Technical Report')
              .map(post => (
                <PostCard key={post.slug} post={post} />
              ))}
          </section>
        </div>
      </div>
      <div className="z-[3] bg-white">
        <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
        <div className="relative">
          <div id="announcements" className="mx-auto p-4 max-w-7xl py-32 z-[0]">
            <div className="mx-auto max-w-2xl px-6 lg:max-w-6xl lg:px-8 z-10 mb-20 -mt-12">
              <h1
                id="recent-posts-heading"
                className="mt-2 text-pretty text-4xl font-semibold tracking-tighter text-neutral-950 sm:text-5xl"
              >
                Announcements
              </h1>
            </div>
            <section
              aria-labelledby="hero-heading"
              className="text-center relative grid grid-cols-1 md:grid-cols-2 gap-4"
            >
              {/* <div className="flex flex-row justify-center items-center my-8"></div> */}
              {posts
                .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
                .filter(post => post.category === 'Announcement')
                .map(post => (
                  <PostCard key={post.slug} post={post} />
                ))}
            </section>
          </div>
        </div>
        <div className="w-full h-[46px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y mt-[4.5px]">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800"
                ></div>
              ))}
          </div>
        </div>
        <CTA />
        <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
      </div>
      <Footer />
    </div>
  );
}



================================================
FILE: app/blog/page.tsx
================================================
// The main blog page where the user can see all the blog posts.
// Checkout posts.ts for general utility functions, post loading/caching, and post type definitions.
// Checkout [slug]/page.tsx for the individual blog post page (this is the general layout for all blog posts).
// Checkout posts/*.tsx for individual blog post content.

import Header from '@/components/ui/header';
import BlogList from './bloglist';

export default function BlogPage() {
  return (
    <div className="flex-col flex w-screen relative scroll-smooth">
      <div className="z-2 sticky top-0 mx-auto w-full">
        <Header />
      </div>
      <BlogList />
    </div>
  );
}



================================================
FILE: app/blog/posts.ts
================================================
import fs from 'fs/promises';
import path from 'path';
import { cache } from 'react';

export type Tag = {
  text: string;
  url: string;
};

export type Metadata = {
  title: string;
  slug: string;
  date: string;
  published: boolean;
  image: string;
  summary: string;
  category: 'Technical Report' | 'Announcement' | 'Tutorial' | 'Language Learning' | 'Other';
  tags: Tag[];
};

export type Post = Metadata & {
  content: () => JSX.Element;
};

export const getPosts = cache(async () => {
  const files = await fs.readdir('./app/blog/posts/');

  const posts = await Promise.all(
    files
      .filter(file => path.extname(file) === '.tsx')
      .map(async file => {
        const post = await import(`./posts/${file}`);
        const metadata = post.metadata;

        if (!metadata.published) {
          return null;
        }

        const content = post.default;
        return { ...metadata, content } as Post;
      }),
  );

  return posts.filter(p => p !== null);
});

export async function getPost(slug: string) {
  const posts = await getPosts();
  return posts.find(post => post.slug === slug);
}



================================================
FILE: app/blog/[slug]/page.tsx
================================================
// General layout that is shared between all blog posts goes here (e.g. footer, header, display author, etc).
// The posts are defined in app/blog/posts/*.tsx.

import { getPost } from '../posts';
import { notFound } from 'next/navigation';
import Header from '@/components/ui/header';
import CTA from '@/components/sections/cta';
import Footer from '@/components/sections/footer';

export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const post = await getPost(slug);
  if (!post) return {};

  return {
    title: `${post.title} | Koel Labs Blog`,
    description: post.summary,
    openGraph: {
      title: post.title,
      description: post.summary,
      type: 'article',
      publishedTime: post.date,
      authors: ['Koel Labs', 'Alexander Metzger', 'Aruna Srivastava', 'Ruslan Mukhamedvaleev'],
      images: [
        {
          url: post.image,
          width: 1200,
          height: 630,
          alt: post.title,
        },
      ],
    },
    twitter: {
      card: 'summary_large_image',
      title: post.title,
      description: post.summary,
      images: [post.image],
    },
  };
}

export default async function PostPage({
  params,
}: {
  params: Promise<{
    slug: string;
  }>;
}) {
  const { slug } = await params;
  const post = await getPost(slug);
  if (!post) return notFound();

  return (
    <div className="flex-col flex w-screen relative scroll-smooth">
      <div className="z-2 sticky top-0 mx-auto w-full">
        <Header />
      </div>
      <div className="relative">
        <div className="color-bg h-[80%] w-11/12 left-0 right-0 mx-auto absolute z-0 blur-[64px] transform-gpu opacity-10 top-48"></div>
        <main className="mx-auto relative">
          <div className="mx-auto absolute h-full flex justify-between z-[-1]"></div>

          <article className="mx-auto w-full h-fit bg-neutral-50/20 border-b border-neutral-200 backdrop-blur-md relative overflow-hidden">
            <post.content />
            <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-t absolute bottom-0 left-0 mt-12">
              <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
                {Array(500)
                  .fill(0)
                  .map((_, i) => (
                    <div
                      key={`bottom-${i}`}
                      className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                    ></div>
                  ))}
              </div>
            </div>
          </article>
          <CTA />
          <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
            <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
              {Array(500)
                .fill(0)
                .map((_, i) => (
                  <div
                    key={`bottom-${i}`}
                    className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                  ></div>
                ))}
            </div>
          </div>
          <Footer />
        </main>
      </div>
    </div>
  );
}



================================================
FILE: app/blog/blog-components/body.tsx
================================================
import React, { PropsWithChildren } from 'react';

export default function BlogBody({ children }: PropsWithChildren) {
  return (
    <div className="bg-white/50 py-24 sm:py-32 relative">
      <div className="mx-auto absolute opacity-25 sm:opacity-100 top-0 left-0 right-0 bottom-0 lg:max-w-[1346px] justify-between z-[-1] h-[1300px] lg:flex hidden">
        <div className="h-full"></div>
        <div className="w-[1px] h-full bg-gradient-to-b from-white via-30% via-neutral-200 to-neutral-400"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="w-[1px] h-full bg-gradient-to-b from-white via-30% via-neutral-200 to-neutral-400"></div>
        <div className="h-full"></div>
      </div>

      <div className="bg-white absolute h-full w-full mt-96 border-y border-neutral-200 lg:block hidden">
        <div className="absolute left-0 top-0 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[5] hidden 2xl:block">
          <div className="rounded-full w-full h-full border bg-white"></div>
        </div>

        <div className="absolute right-0 top-0 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[5] hidden 2xl:block">
          <div className="rounded-full w-full h-full border bg-white"></div>
        </div>

        <div className="absolute left-0 top-[225px] w-[49.3px] h-[48px] bg-neutral-50 p-1 z-[5] hidden 2xl:block">
          <div className="rounded-full w-full h-full border bg-white"></div>
        </div>

        <div className="absolute right-0 top-[225px] w-[49.3px] h-[48px] bg-neutral-50 p-1 z-[5] hidden 2xl:block">
          <div className="rounded-full w-full h-full border bg-white"></div>
        </div>
        <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-b absolute top-0 left-0 z-[1]">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
        <div className=" w-full h-[250px] overflow-hidden bg-neutral-50 absolute top-0 left-0"></div>
        <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y absolute top-56 left-0">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
      </div>

      <div className="mx-auto max-w-2xl px-6 lg:max-w-6xl lg:px-8 z-10">{children}</div>
    </div>
  );
}



================================================
FILE: app/blog/blog-components/code.tsx
================================================
import React from 'react';
import { CodeBlock } from '@/components/ui/code-block';

export default function BlogCode({ code }: { code: string }) {
  return (
    <div className="p-2 mb-4 bg-white border rounded-2xl">
      <CodeBlock code={code} />
    </div>
  );
}



================================================
FILE: app/blog/blog-components/decorations.tsx
================================================
import React from 'react';

export default function BlogDecorations() {
  return (
    <>
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width="1121"
        height="1308"
        fill="none"
        viewBox="0 0 1121 1308"
        className="absolute -top-128 -left-[890px] scale-50"
      >
        <path
          stroke="#E5E5E5"
          d="M53 .5h710c28.443 0 51.5 23.057 51.5 51.5v217.25c0 28.995 23.505 52.5 52.5 52.5h201.5c28.44 0 51.5 23.057 51.5 51.5v882.72c0 28.44-23.06 51.5-51.5 51.5H53c-28.443 0-51.5-23.06-51.5-51.5V52C1.5 23.557 24.557.5 53 .5Z"
        ></path>
        <path fill="url(#paint0_linear_4063_253)" d="M1 599h1120v709H1z"></path>
        <path
          fill="url(#paint1_linear_4063_253)"
          d="M554.5 0h1308v554h-1308z"
          transform="rotate(90 554.5 0)"
        ></path>
        <defs>
          <linearGradient
            id="paint0_linear_4063_253"
            x1="561"
            x2="561"
            y1="599"
            y2="1308"
            gradientUnits="userSpaceOnUse"
          >
            <stop stopColor="#fff" stopOpacity="0"></stop>
            <stop offset="1" stopColor="#fff"></stop>
          </linearGradient>
          <linearGradient
            id="paint1_linear_4063_253"
            x1="1208.5"
            x2="1208.5"
            y1="0"
            y2="554"
            gradientUnits="userSpaceOnUse"
          >
            <stop stopColor="#fff" stopOpacity="0"></stop>
            <stop offset="0.87" stopColor="#fff"></stop>
          </linearGradient>
        </defs>
      </svg>

      <svg
        xmlns="http://www.w3.org/2000/svg"
        width="1121"
        height="1308"
        fill="none"
        viewBox="0 0 1121 1308"
        className="absolute -top-128 -right-[890px] scale-50 rotate-y-180"
      >
        <path
          stroke="#E5E5E5"
          d="M53 .5h710c28.443 0 51.5 23.057 51.5 51.5v217.25c0 28.995 23.505 52.5 52.5 52.5h201.5c28.44 0 51.5 23.057 51.5 51.5v882.72c0 28.44-23.06 51.5-51.5 51.5H53c-28.443 0-51.5-23.06-51.5-51.5V52C1.5 23.557 24.557.5 53 .5Z"
        ></path>
        <path fill="url(#paint0_linear_4063_253)" d="M1 599h1120v709H1z"></path>
        <path
          fill="url(#paint1_linear_4063_253)"
          d="M554.5 0h1308v554h-1308z"
          transform="rotate(90 554.5 0)"
        ></path>
        <defs>
          <linearGradient
            id="paint0_linear_4063_253"
            x1="561"
            x2="561"
            y1="599"
            y2="1308"
            gradientUnits="userSpaceOnUse"
          >
            <stop stopColor="#fff" stopOpacity="0"></stop>
            <stop offset="1" stopColor="#fff"></stop>
          </linearGradient>
          <linearGradient
            id="paint1_linear_4063_253"
            x1="1208.5"
            x2="1208.5"
            y1="0"
            y2="554"
            gradientUnits="userSpaceOnUse"
          >
            <stop stopColor="#fff" stopOpacity="0"></stop>
            <stop offset="0.87" stopColor="#fff"></stop>
          </linearGradient>
        </defs>
      </svg>
    </>
  );
}



================================================
FILE: app/blog/blog-components/heading.tsx
================================================
import React from 'react';
import { ArrowLeft } from 'lucide-react';
import Link from 'next/link';

type MaxWidthOption = '5xl' | '4xl' | '3xl' | '2xl' | 'xl' | number | undefined;

export type BlogHeadingProps = {
  category: string;
  categoryColorClass?: string; // e.g. 'text-sky-600' | 'text-purple-600'
  title: string;
  dateISO: string;
  byline?: string; // defaults to 'By Koel Labs'
  maxWidth?: MaxWidthOption; // default lg:max-w-4xl
};

function formatDate(dateString: string): string {
  const date = new Date(dateString);
  return date.toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  });
}

function resolveMaxWidthClass(maxWidth: MaxWidthOption): string {
  switch (maxWidth) {
    case '5xl':
      return 'lg:max-w-5xl';
    case '3xl':
      return 'lg:max-w-3xl';
    case 'xl':
      return 'lg:max-w-xl';
    case '2xl':
      return 'lg:max-w-2xl';
    case '4xl':
    default:
      return 'lg:max-w-4xl';
  }
}

export default function BlogHeading({
  category,
  categoryColorClass = 'text-sky-600',
  title,
  dateISO,
  byline = 'By Koel Labs',
  maxWidth,
}: BlogHeadingProps) {
  const wrapperMax = resolveMaxWidthClass(maxWidth);
  return (
    <div
      className={`relative ${wrapperMax} mx-auto`}
      style={typeof maxWidth === 'number' ? { maxWidth: maxWidth } : undefined}
    >
      <Link href="/blog" className="flex justify-center relative z-10 max-w-sm mx-auto mb-6">
        <div className="relative rounded-full px-2 py-0.5 pr-4.5 text-sm/6 text-gray-600 border-y border-l rounded-r-none">
          <ArrowLeft className="w-3 h-3 inline-block -ml-0.5 mb-px mr-1" strokeWidth={2} />
          Back to Blog
        </div>
        <h2
          className={`text-sm tracking-tight font-semibold ${categoryColorClass} text-center border border-neutral-200 rounded-full w-fit -ml-3 px-3 py-1`}
        >
          {category}
        </h2>
      </Link>
      <h1 className="mt-2 text-pretty text-3xl sm:text-4xl font-semibold tracking-tighter text-neutral-950 md:text-5xl text-center">
        {title}
      </h1>
      <div className="flex justify-center mt-7 items-center gap-1">
        <div className="text-neutral-600 flex items-center gap-1.5">
          {/* {formatDate(dateISO)} 
          {byline ? ` • ${byline}` : ''} */}
          <div className=" -space-x-1 overflow-hidden inline-block">
            <img
              alt="A photo of Alexander Metzger"
              src="/images/mini-alex.png"
              className="inline-block size-6 rounded-full outline outline-1 -outline-offset-1 outline-black/5 ring-2 ring-white"
            />
            <img
              alt="A photo of Aruna Srivastava"
              src="/images/mini-aruna.png"
              className="inline-block size-6 rounded-full outline outline-1 -outline-offset-1 outline-black/5 ring-2 ring-white"
            />
            <img
              alt="A photo of Ruslan Mukhamedvaleev"
              src="/images/mini-ruslan.png"
              className="inline-block size-6 rounded-full outline outline-1 -outline-offset-1 outline-black/5 ring-2 ring-white"
            />
          </div>
          By Koel Labs ·
        </div>
        <time dateTime={dateISO} className="text-neutral-600">
          {formatDate(dateISO)}
        </time>
      </div>
    </div>
  );
}



================================================
FILE: app/blog/blog-components/hero-image.tsx
================================================
import React from 'react';

export type BlogHeroImageProps = {
  src: string;
  alt: string;
};

export default function BlogHeroImage({ src, alt }: BlogHeroImageProps) {
  return (
    <div className="p-2 mt-16 relative z-10 rounded-3xl border overflow-hidden bg-neutral-50">
      <img src={src} alt={alt} className="w-full h-auto rounded-2xl z-10 relative border" />
    </div>
  );
}



================================================
FILE: app/blog/blog-components/image.tsx
================================================
import React from 'react';
import Image from 'next/image';
import { cn } from '@/lib/styles';

export default function BlogImage({
  src,
  alt,
  width,
  height,
  expanded = false,
  sizes,
  className,
  link,
  linkSide,
}: {
  src: string;
  alt: string;
  width: number;
  height: number;
  expanded: boolean;
  sizes?: string;
  className: string;
  link?: string;
  linkSide?: 'left' | 'right';
}) {
  return (
    <div
      className={cn(
        'w-full border p-2 rounded-3xl overflow-hidden',
        className,
        expanded && 'scale-150 my-36 border-[0.75px] p-1.5',
      )}
    >
      {link && (
        <a href={link} target="_blank" className="relative group/item overflow-hidden bg-white">
          <Image
            src={src}
            alt={alt}
            width={width}
            height={height}
            sizes={sizes}
            quality={100}
            className={cn(
              'w-full h-auto border rounded-[16px]',
              expanded && 'border-[0.75px] rounded-[19px]',
            )}
          />

          {/* {linkSide === 'left' && (
            <span className="transition-all inline-flex items-center px-2 w-full py-1.5 border text-sm leading-4 font-medium tracking-tight rounded-xl text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 sm:w-fit flex-row justify-between hover:shadow-sm group">
              <div className={`h-2 w-2 rounded-full relative transition-all mr-1`}></div>
              From: {link}
            </span>
          )}
          {linkSide === 'right' && (
            <span className="pointer-events-none group-hover/item:scale-100 scale-0 group-hover/item:blur-none group-hover/item:translate-x-0 translate-x-60 group-hover/item:translate-y-0 translate-y-20 blur-2xl absolute bottom-2 right-2 bg-white font-sans transition-all inline-flex items-center px-2 w-full py-1.5 border text-sm leading-4 font-medium tracking-tight rounded-xl text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 sm:w-fit flex-row justify-between hover:shadow-sm group">
              <div className={`h-2 w-2 rounded-full relative transition-all mr-1 bg-sky-700`}></div>
              From: {link}
            </span>
          )} */}
        </a>
      )}
      {!link && (
        <Image
          src={src}
          alt={alt}
          width={width}
          height={height}
          sizes={sizes}
          quality={100}
          className={cn(
            'w-full h-auto border rounded-[16px]',
            expanded && 'border-[0.75px] rounded-[19px]',
          )}
        />
      )}
    </div>
  );
}



================================================
FILE: app/blog/blog-components/subheading.tsx
================================================
import React, { PropsWithChildren } from 'react';

export default function BlogSubheading({ children }: PropsWithChildren) {
  return <h2 className="text-2xl font-semibold mt-8 mb-4 font-sans">{children}</h2>;
}



================================================
FILE: app/blog/blog-components/utils.ts
================================================
export function formatDate(dateString: string): string {
  const date = new Date(dateString);
  return date.toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  });
}



================================================
FILE: app/blog/posts/building-open-source-leaderboards.tsx
================================================
// This is the individual blog post page content. It is rendered insides [slug]/page.tsx.
// The metadata object is used to display the blog post on the main blog page (app/blog/page.tsx).
// It will also be used to set meta tags for SEO once I get around to adding that.

import type { Metadata } from '../posts';
import Link from 'next/link';
import { Source_Serif_4 } from 'next/font/google';
import BlogBody from '../blog-components/body';
import BlogHeading from '../blog-components/heading';
import BlogHeroImage from '../blog-components/hero-image';
import BlogSubheading from '../blog-components/subheading';
import BlogImage from '../blog-components/image';
import BlogDecorations from '../blog-components/decorations';

const sourceSerif = Source_Serif_4({
  subsets: ['latin'],
  weight: ['400', '700'],
});

export const metadata: Metadata = {
  title: 'Building Open Source Hugging Face Leaderboards',
  slug: 'building-open-source-leaderboards',
  date: '2025-01-11',
  published: true,
  image: '/images/blogLeaderboards.png',
  summary:
    "Sometimes, the best machine learning models are hidden in plain sight. During our work on phonemic transcription, we stumbled upon a specialized ginic model that had been finetuned on Facebook's XLSR-53 model using the Buckeye corpus. This discovery proved significant: Ginic performs 1.2x better than Facebook, and iterating on their approach, our model performs 2.2x better than ginic. However, finding this model was more a product of extensive searching than systematic discovery, highlighting a broader challenge in the phoneme transcription space.",
  category: 'Technical Report',
  tags: [
    {
      text: 'Hugging Face',
      url: 'https://huggingface.co/KoelLabs',
    },
  ],
};

export default function PostBody() {
  return (
    <BlogBody>
      <div className="">
        <BlogHeading
          category={metadata.category}
          categoryColorClass="text-sky-600"
          title={metadata.title}
          dateISO={metadata.date}
          maxWidth={600}
        />
        <BlogHeroImage
          src="/images/blogLeaderboardsAlt.png"
          alt="Building Open Source Leaderboards"
        />
        <br></br>
        <div className="relative lg:col-span-3 max-w-3xl mx-auto mt-12">
          <BlogDecorations />
          <div
            className={`relative flex h-full flex-col tracking-[-0.010em] text-lg ${sourceSerif.className}`}
          >
            <BlogSubheading>An Introduction</BlogSubheading>
            <p className="mb-4">
              Sometimes, the best machine learning models are hidden in plain sight. During our work
              on phonemic transcription, we stumbled upon a specialized{' '}
              <Link
                className="text-sky-600 hover:underline"
                href="https://huggingface.co/ginic"
                target="_blank"
                rel="noopener noreferrer"
              >
                ginic model
              </Link>{' '}
              that had been finetuned on{' '}
              <Link
                className="text-sky-600 hover:underline"
                href="https://huggingface.co/facebook/wav2vec2-large-xlsr-53"
                target="_blank"
                rel="noopener noreferrer"
              >
                Facebook's XLSR-53 model
              </Link>{' '}
              using the Buckeye corpus. This discovery proved significant: Ginic performs 1.2x
              better than Facebook, and iterating on their approach, our model performs 2.2x better
              than ginic. However, finding this model was more a product of extensive searching than
              systematic discovery, highlighting a broader challenge in the phoneme transcription
              space that led us to build{' '}
              <Link
                className="text-sky-600 hover:underline"
                href="https://huggingface.co/spaces/KoelLabs/IPA-Transcription-EN"
                target="_blank"
                rel="noopener noreferrer"
              >
                this open-source leaderboard
              </Link>
              .
            </p>
            <BlogSubheading>
              The Need for Better Model Discovery and Standardized Evaluation
            </BlogSubheading>

            <p className="mb-4">
              While leaderboards have become fundamental infrastructure in many areas of machine
              learning - from{' '}
              <Link
                href="https://huggingface.co/spaces/open-llm-leaderboard/open_llm_leaderboard#/"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                large language models
              </Link>{' '}
              to{' '}
              <Link
                href="https://huggingface.co/spaces/hf-audio/open_asr_leaderboard"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                automatic speech recognition
              </Link>{' '}
              - the field of phonemic transcription notably lacks such standardized evaluation
              frameworks. This gap isn't just about missing leaderboards - it reflects a broader
              absence of unified evaluation standards and comprehensive survey papers that could
              allow researchers and practitioners to track progress and compare approaches
              effectively.
            </p>

            <BlogSubheading>A Streamlined Architecture for Open Evaluation</BlogSubheading>

            <p className="mb-4">
              To address this gap, we implemented a system that handles both the queue backend and
              the leaderboard frontend. This design prioritizes transparency and accessibility -
              crucial elements often missing in evaluation. Our architecture consists of two main
              components:
            </p>

            <ul className="list-disc list-inside mb-4 pl-4">
              <li className="mb-2">
                <span className="font-semibold text-sky-600 font-sans">app.py:</span> Handles the
                front-end logic using Gradio, providing a clean interface for viewing the
                leaderboard, checking model status, and submitting new models
              </li>
              <li className="mb-2">
                <span className="font-semibold text-sky-600 font-sans">tasks.py:</span> Manages the
                back-end operations, interfacing with three JSON files in the queue directory:
                <ul className="list-disc list-inside ml-4 mt-2">
                  <li>
                    <span className="font-semibold text-sky-600 font-sans">leaderboard.json:</span>{' '}
                    Stores the final, processed rankings
                  </li>
                  <li>
                    <span className="font-semibold text-sky-600 font-sans">tasks.json:</span> Tracks
                    newly submitted models
                  </li>
                  <li>
                    <span className="font-semibold text-sky-600 font-sans">results.json:</span>{' '}
                    Contains detailed metadata for completed evaluations
                  </li>
                </ul>
              </li>
            </ul>

            <p className="mb-4">
              Transparency was a key consideration in our design. Unlike some existing leaderboards
              like{' '}
              <Link
                href="https://huggingface.co/spaces/hf-audio/open_asr_leaderboard"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                Open ASR
              </Link>{' '}
              that require users to request model evaluation and wait, our system automates the
              process. Most models can be evaluated on the whole test set within hours of
              submission.
            </p>

            <p className="mb-4">
              Additionally, the front-end leaderboard and queue backend are visible to all Hugging
              Face users - a deliberate choice to promote transparency. The results file provides
              detailed metadata about evaluations and model outputs, allowing users to understand
              precisely how models perform and evaluations are conducted. that require users to
              request model evaluation and wait, our system automates the process.
            </p>

            <BlogImage
              src="/images/blogLeaderboard1.png"
              alt="Check status of your model"
              width={1200}
              height={600}
              expanded={true}
              className="my-32 mb-36"
            />

            <p className="mb-4">
              This openness and automation represent a step toward the kind of standardized
              evaluation infrastructure that has helped accelerate progress in other areas of
              machine learning but has been notably absent in phonemic transcription.
            </p>

            <BlogSubheading>Technical Implementation Details</BlogSubheading>

            <p className="mb-4">
              Our evaluation system measures model performance using two key metrics:
            </p>

            <ol className="list-decimal list-inside mb-4 pl-4">
              <li className="mb-2">
                PER (Phoneme Error Rate): Calculated using Levenshtein distance between predicted
                and actual phoneme sequences
              </li>
              <li className="mb-2">
                PWED (Phoneme Weighted Edit Distance): A more nuanced metric that considers phonemic
                feature distances, implemented using the panphon library
              </li>
            </ol>

            <p className="mb-4">
              You can read more about these evaluation methods{' '}
              <Link
                href="/blog/phonemic-transcription-metrics"
                className="text-sky-600 hover:underline"
              >
                in our blog post here
              </Link>
              .
            </p>

            <p className="mb-4">
              We use the TIMIT speech corpus as our evaluation dataset, providing a standardized
              benchmark widely recognized in the speech recognition community. The evaluation runs
              on a consistent compute environment (16GB RAM, 2vCPUs) to ensure reproducibility.
            </p>

            <BlogSubheading>We Need More of These Projects</BlogSubheading>

            <p className="mb-4">
              The success of platforms like the Open LLM Leaderboard, with nearly 3,000 submissions,
              demonstrates the community's appetite for transparent model comparison. While some
              argue that gamifying model development could lead to metric gaming, we've seen how
              leaderboards can transform competition into collaboration. They provide standardized
              benchmarks, foster innovation through transparency, and create an engaging entry point
              for newcomers to the field. Most importantly, they help surface promising but
              lesser-known models that might otherwise remain undiscovered.
            </p>

            <BlogSubheading>Looking Forward</BlogSubheading>

            <p className="mb-4">
              Creating leaderboards has historically been challenging, with many templates becoming
              quickly outdated. Hugging Face has recently streamlined this process through their
              Space SDK, which is ideal for evaluating models of varying sizes and computational
              requirements. To create a leaderboard using their template:
            </p>

            <BlogImage
              src="/images/blogLeaderboard2.png"
              alt="Hosting your leaderboard"
              width={1200}
              height={600}
              expanded={true}
              className="my-36"
            />

            <ol className="list-decimal list-inside mb-4 pl-4 italic">
              <li className="mb-2">
                Navigate to{' '}
                <Link
                  href="https://huggingface.co/new-space"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-sky-600 hover:underline"
                >
                  https://huggingface.co/new-space
                </Link>
              </li>
              <li className="mb-2">Select "Space SDK" as the template type</li>
              <li className="mb-2">Choose "Gradio" as the framework</li>
              <li className="mb-2">Select "Leaderboard" from the template options</li>
              <li className="mb-2">
                You will be asked for an access token in the UI before you create the space. This
                can be created in{' '}
                <Link
                  href="https://huggingface.co/login?next=%2Fsettings%2Ftokens"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-sky-600 hover:underline"
                >
                  your settings
                </Link>{' '}
                and needs read access for the leaderboard to function.
              </li>
            </ol>

            <p className="mb-4">
              For evaluating collections of smaller models that don't require extensive pre-testing,
              our lightweight implementation offers a practical working example. It demonstrates a
              complete end-to-end leaderboard system while maintaining simplicity in both setup and
              maintenance. We've made our codebase publicly available - feel free to duplicate it
              for your own specialized evaluation needs or use it as a reference implementation when
              building more complex systems. We are actively working on adding more evaluation
              datasets/metrics and support for more model architectures and{' '}
              <Link
                href="https://github.com/KoelLabs/.github/blob/main/CONTRIBUTING.md"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                welcome contributions
              </Link>
              !
            </p>

            <p className="mb-4">
              The path to better model evaluation shouldn't be blocked by infrastructure complexity.
              Whether using Hugging Face's template or our simpler architecture, the goal remains
              the same: making model discovery and comparison more accessible to the community.
            </p>
          </div>
        </div>
      </div>
    </BlogBody>
  );
}



================================================
FILE: app/blog/posts/dialect-sensitivity.tsx
================================================
// This is the individual blog post page content. It is rendered insides [slug]/page.tsx.
// The metadata object is used to display the blog post on the main blog page (app/blog/page.tsx).
// It will also be used to set meta tags for SEO once I get around to adding that.

import type { Metadata } from '../posts';
import Image from 'next/image';
import { Source_Serif_4 } from 'next/font/google';
import BlogBody from '../blog-components/body';
import BlogHeading from '../blog-components/heading';
import BlogHeroImage from '../blog-components/hero-image';
import BlogSubheading from '../blog-components/subheading';
import BlogCode from '../blog-components/code';

const sourceSerif = Source_Serif_4({
  subsets: ['latin'],
  weight: ['400', '700'],
});

export const metadata: Metadata = {
  title: 'Dialect Sensitivity — Why it matters for the future of language acquisition',
  slug: 'dialect-sensitivity',
  date: '2024-12-23',
  published: false,
  image: '/images/blogDialect.png',
  summary:
    'Dialect sensitivity is a crucial aspect of language learning. It refers to the ability of a language learning platform to adapt to the specific pronunciation and accent of a learner. This is important because it allows learners to better understand and speak the language, and it can also help them avoid making mistakes that could be embarrassing or even harmful in certain contexts.',
  category: 'Language Learning',
  tags: [],
};

export default function PostBody() {
  return (
    <BlogBody>
      <div className="">
        <BlogHeading
          category={metadata.category}
          categoryColorClass="text-sky-600"
          title={metadata.title}
          dateISO={metadata.date}
          maxWidth="5xl"
        />
        <BlogHeroImage src={metadata.image} alt={metadata.title} />
        <br></br>
        <div className="relative lg:col-span-3 max-w-3xl mx-auto mt-12">
          <div
            className={`relative flex h-full flex-col overflow-hidden tracking-[-0.010em] text-lg ${sourceSerif.className}`}
          >
            <p className="mb-4">{metadata.summary}</p>
            <p className="mb-4">
              At Koel Labs, we use two key metrics to evaluate phonemic transcription models:
            </p>

            <ol className="list-decimal list-inside mb-4 pl-4">
              <li className="mb-2">
                Phonemic Error Rate (PER): The classic "how many mistakes did you make?" metric
              </li>
              <li className="mb-2">
                Weighted Phonemic Edit Distance (WPED): A smarter approach that considers how
                similar sounds are to each other
              </li>
            </ol>

            <BlogSubheading>
              Why Traditional Metrics Fall Short: A Tale of Three Words
            </BlogSubheading>

            <p className="mb-4">
              Let's say we're trying to transcribe the word "Bop". Our model could make different
              types of mistakes, and this is where things get interesting.
            </p>

            <p className="mb-4">Consider two models making different predictions:</p>

            <ul className="list-disc list-inside mb-4 pl-4">
              <li className="mb-2">Model 1 predicts: "Pop"</li>
              <li className="mb-2">Model 2 predicts: "Sop"</li>
            </ul>

            <p className="mb-4">
              From a linguistics perspective, these mistakes are not created equal:
            </p>

            <ul className="list-disc list-inside mb-4 pl-4">
              <li className="mb-2">
                'B' and 'P' are like cousins—they're both plosive bilabial consonants, made by
                stopping airflow with your lips. The only difference is that 'B' is voiced (your
                vocal cords vibrate) and 'P' isn't.
              </li>
              <li className="mb-2">
                'B' and 'S', on the other hand, are more like distant relatives. 'S' is a fricative
                alveolar consonant, made by forcing air between your tongue and the ridge behind
                your upper teeth—a completely different sound!
              </li>
            </ul>

            <p className="mb-4">
              This is where traditional PER falls short. It calculates errors based on simple
              substitutions, deletions, and insertions. In our example:
            </p>

            <div className="p-2 mb-4 bg-white border rounded-2xl">
              <BlogCode
                code={`"Bop" → "Pop": 1 substitution = 33.33% error rate
"Bop" → "Sop": 1 substitution = 33.33% error rate`}
              />
            </div>

            <p className="mb-4">
              This is like saying someone who almost hit the bullseye did just as poorly as someone
              who hit the wall next to the dartboard. You can imagine that this would create very
              misleading evaluations.
            </p>

            <BlogSubheading>Weighted Phonemic Edit Distance</BlogSubheading>

            <p className="mb-4">
              This is where WPED comes to the rescue, powered by the{' '}
              <a href="https://github.com/dmort27/panphon" className="text-sky-600 hover:underline">
                Panphon library
              </a>
              . Instead of treating each phoneme as completely different or identical, it represents
              them as a sequence of features—things like:
            </p>

            <ul className="list-disc list-inside mb-4 pl-4">
              <li className="mb-2">Is it voiced?</li>
              <li className="mb-2">Where in the mouth is it made?</li>
              <li className="mb-2">How is the air released?</li>
            </ul>

            <p className="mb-4">Each phoneme becomes a feature vector, something like:</p>

            <BlogCode
              code={`B: [+voiced, +bilabial, +plosive, -fricative, ...]
P: [-voiced, +bilabial, +plosive, -fricative, ...]
S: [-voiced, +alveolar, -plosive, +fricative, ...]`}
            />

            <p className="mb-4">
              When we calculate the distance between these vectors, we get a much more nuanced view:
            </p>

            <BlogCode
              code={`Distance("Bop" → "Pop") = 0.2  // Small difference
Distance("Bop" → "Sop") = 0.8  // Large difference`}
            />

            <div className="my-8">
              <Image
                src="/placeholder.svg"
                alt="Diagram illustrating phonemic distances"
                width={600}
                height={400}
                className="mx-auto"
              />
            </div>

            <BlogSubheading>Why This Matters</BlogSubheading>

            <p className="mb-4">
              When you're teaching a model to transcribe speech, you want it to understand that
              predicting a similar sound is better than predicting a completely different one. This
              is especially important because different models might use different phoneme
              vocabularies—some might have 40 symbols, others up to 400.
            </p>

            <p className="mb-4">
              Traditional PER might unfairly favor models that happen to use the exact same phoneme
              set as your ground truth data, even if other models are making more linguistically
              sensible predictions. WPED helps level the playing field by considering phonetic
              similarity.
            </p>

            <BlogSubheading>The Takeaway</BlogSubheading>

            <p className="mb-4">
              By using WPED alongside traditional metrics like PER, we can better understand how
              well our models are really performing at phonemic transcription. It's not just about
              getting the exact right symbol—it's about understanding the underlying sounds of
              language.
            </p>

            <p className="mb-4">
              As we continue to develop better speech recognition models, metrics like WPED will be
              crucial in helping us measure progress in a way that actually reflects linguistic
              reality. After all, in the world of pronunciation, being close sometimes counts for a
              lot more than traditional metrics might suggest!
            </p>
          </div>
        </div>
      </div>
    </BlogBody>
  );
}



================================================
FILE: app/blog/posts/feature-extraction-deep-dive.tsx
================================================
// This is the individual blog post page content. It is rendered insides [slug]/page.tsx.
// The metadata object is used to display the blog post on the main blog page (app/blog/page.tsx).
// It will also be used to set meta tags for SEO once I get around to adding that.

import type { Metadata } from '../posts';
import BlogBody from '../blog-components/body';
import BlogHeading from '../blog-components/heading';
import BlogHeroImage from '../blog-components/hero-image';
import BlogSubheading from '../blog-components/subheading';
import BlogImage from '../blog-components/image';
import BlogDecorations from '../blog-components/decorations';
import BlogCode from '../blog-components/code';
import { Source_Serif_4 } from 'next/font/google';

const sourceSerif = Source_Serif_4({
  subsets: ['latin'],
  weight: ['400', '700'],
});

export const metadata: Metadata = {
  title: "The Underlying Intuition of Wav2Vec2's CNN",
  slug: 'wav2vec2-feature-extractor-intuition',
  date: '2025-10-19',
  published: true,
  image: '/blog/cnn/blogCNN.png',
  summary:
    "Typically, every explanation of the Wav2vec2 architecture begins with the iconic diagram, but without extensive background, it is hard to know what the cones labeled as the CNN are really doing. What does it actually mean to extract features from audio? Let's find a stronger visual intuition for this.",
  category: 'Technical Report',
  tags: [
    { text: 'Audio Processing', url: '/tags/audio-processing' },
    { text: 'Wav2Vec2', url: '/tags/wav2vec2' },
    { text: 'CNN', url: '/tags/cnn' },
  ],
};

export default function PostBody() {
  return (
    <BlogBody>
      <div className="">
        <BlogHeading
          category={metadata.category}
          categoryColorClass="text-sky-600"
          title={metadata.title}
          dateISO={metadata.date}
          maxWidth={700}
        />
        <BlogHeroImage src="/blog/cnn/wav2vec2-border.png" alt="Wav2Vec2 Architecture Diagram" />
        <br></br>
        <div className="relative lg:col-span-3 max-w-3xl mx-auto mt-12">
          <BlogDecorations />
          <div
            className={`relative flex h-full flex-col tracking-[-0.010em] text-lg ${sourceSerif.className}`}
          >
            <BlogSubheading>An Introduction</BlogSubheading>
            <p className="mb-4">{metadata.summary}</p>

            <BlogSubheading>Background</BlogSubheading>
            <p className="mb-4">
              For those new to audio processing, audio is incredibly dense compared to other forms
              of data like text.
            </p>
            <p className="mb-4">
              You can imagine sound as a continuous, smooth curve, but because we want to discretize
              this (represent audio numerically), we take snapshots of this wave at regular
              intervals. How frequently we take these snapshots in one second of sound is the
              sampling rate. This sampling rate decides how much information we have to store in
              audio.
            </p>
            <p className="mb-4">
              The typical sampling rate of 16kHz represents processing 16 thousands values per
              second of audio. That's a lot of information! So how can the Wav2Vec2 architecture
              handle all of this information?
            </p>

            <BlogSubheading>The Feature Extractor</BlogSubheading>
            <p className="mb-4">
              The Feature Extractor, also called the Convolutional Neural Network (CNN), aims to
              extract high-level features while compressing a very dense temporal dimension . Think
              of it as when you want to do a quick portrait of someone: you want to capture their
              distinguishable facial features without spending too much time capturing every detail.
            </p>

            <BlogImage
              src="/blog/cnn/kids-drawing.png"
              link="https://www.boredpanda.com/kids-drawing-dads-1949-vintage-jimatjimat/"
              linkSide="right"
              alt="Kids asked to draw their fathers in 1949"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="text-center text-sm text-neutral-600 mb-12">
              Kids asked to draw their fathers in 1949
            </p>

            <p className="mb-4">
              The Feature Extractor will take 1/50th of a second (20ms) at a time and use the
              previous 1/200th of a second (5ms) to give itself some context. So lets take a closer
              look at how that single 25ms chunk gets processed.
            </p>

            <BlogSubheading>Audio Stream to Representation</BlogSubheading>
            <p className="mb-4">
              This first 25ms chunk of raw audio starts as a chunk of 400 values (seconds ×
              sampling-rate = 0.025 × 16,000 = 400 samples) representing the audio waveform. Just a
              simple list like{' '}
            </p>
            <BlogCode code={`[0.1, -0.3, 0.8, -0.2, 0.1, 0.5, -0.1, -0.4, 0.2, 0.3, ...]`} />
            <p className="mb-4">
              Think of an audio waveform representing tiny vibrations of air molecules that result
              in changes in air pressure. While very cool, air pressure changes do not communicate
              any clear patterns in acoustic signals like pitch, timbre, and other audio
              characteristics. It would be much better to transform these 400 temporal samples into
              512 higher-level features that capture these different acoustic properties across the
              entire 25ms window.
            </p>
            <p className="mb-4">
              So that's what the feature extractor does, starting with the first layer. It takes
              this single monochannel audio input and projects to 512 dimensional space via 512
              channels. And to load each of these channels, we look at a 1 × 10 window and take the
              dot product against a 10 × 1 kernel to compute a single value. We then slide over by a
              stride of 5 samples for the next 1 × 10 window. After the first window processes 10
              unseen samples, the remaining 1 × 10 windows process 5 seen + 5 unseen samples at a
              time. So to find how many windows span the 400 samples, we consider just what are the
              unseen samples: 78 windows process 5 unseen samples at a time and the very first
              window processes 10 unseen samples, giving us 79 windows for this layer.
            </p>

            <BlogImage
              src="/blog/cnn/layer-kernel.png"
              link="https://arxiv.org/pdf/2006.11477"
              alt="First layer convolution: kernel_size = 10, stride = 5"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="text-center text-sm font-medium text-neutral-700 mb-12">
              First layer convolution: kernel_size = 10, stride = 5
            </p>

            <p className="mb-4">
              The output dimension should feel intuitive but if you don't want to use your brain to
              figure out your output dimension of a single channel you can use this nice formula:
            </p>

            <BlogCode
              code={`# Layer 0
kernel_size = 10
stride = 5
input_values = 400
num_output_values = math.floor((input_values - kernel_size) / stride) + 1  # 79`}
            />

            <p className="mb-4">Okay, now we have our first layer!</p>

            <BlogImage
              src="/blog/cnn/single-layer.png"
              link="https://arxiv.org/pdf/2006.11477"
              alt="Visual representation of layer progression"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />

            <BlogSubheading>First Layer Convolution</BlogSubheading>
            <p className="mb-4">
              Remember, we want to reduce the temporal dimension, so let's apply another
              convolution! To do this, the next layer will stride every second value of a
              3-sample-window of the first layer. So basically look at every second value. Can you
              guess what the next block will look like?
            </p>
            <p className="mb-4">Using our little formula…</p>

            <BlogCode
              code={`# Layer 1
kernel_size = 3
stride = 2
input_values = 79
math.floor((input_values - kernel_size) / stride + 1)  # Output = 39`}
            />

            <p className="mb-4">
              39 values across 512 channels, nice! Layers 1–4 have the same kernel size and stride
              so lets just repeat this…
            </p>

            <BlogCode
              code={`kernel_size = 3
stride = 2
input_values = 79  # Layer 0 input

# Layers 1-4
for i in range(4):
    output = math.floor((input_values - kernel_size) / stride + 1)
    input_values = output
# output = 39 -> 19 -> 9 -> 4`}
            />

            <p className="mb-4">Awesome! Now the last 2 layers have stride and kernel size 2..</p>

            <BlogCode
              code={`kernel_size = 1
stride = 2
input_values = 4  # Layer 4 input

# Layers 5-6
for i in range(2):
    output = math.floor((input_values - kernel_size) / stride + 1)
    input_values = output
# output = 2 -> 1`}
            />

            <p className="mb-4">Wow. We now just have a single value across 512 channels.</p>
            <p className="mb-4">
              Throughout this process, activation functions like GeLU add non-linearity between each
              layer, allowing the network to learn complex patterns.
            </p>

            <BlogImage
              src="/blog/cnn/single-chunk.png"
              link="https://arxiv.org/pdf/2006.11477"
              alt="Single Chunk Processed by CNN"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="text-center text-sm font-medium text-neutral-700 mt-2">
              Single Chunk Processed by CNN
            </p>

            <BlogSubheading>
              Why not just directly compress from 400 samples to 512 features in one step?
            </BlogSubheading>
            <p className="mb-4">
              Jumping directly would require learning 204,800 parameters in one massive linear
              transformation, which is both hard to optimize and limited in what patterns it can
              capture. Multiple smaller layers with non-linear activations between them train more
              reliably and can build complex representations by combining simpler patterns. A chef
              that takes time to make components of a dish from scratch will produce a much better,
              complex dish than any microwave meal.
            </p>
            <p className="mb-4">
              So that's how we process a single 25ms chunk of audio - transforming 400 raw samples
              into a rich 512-dimensional feature vector. Now we slide this entire process across
              the audio stream, moving 320 samples at a time...
            </p>

            <p className="mb-4">All of that has been nicely wrapped in a few lines of code:</p>
            <BlogCode
              code={`input_values = inputs.input_values.type(torch.float32)
with torch.no_grad():
    extract_features = model.wav2vec2.feature_extractor(input_values)`}
            />

            <p className="mb-4">We can also grab the attention masks to</p>
            <BlogCode
              code={`attention_mask = inputs.attention_mask
with torch.no_grad():
    extract_features = model.wav2vec2.feature_extractor(input_values).transpose(1, 2)
    attention_masks = model.wav2vec2._get_feature_vector_attention_mask(
        extract_features.shape[1], 
        attention_mask, 
        add_adapter=False
    )`}
            />

            <BlogSubheading>Feature Projection</BlogSubheading>
            <p className="mb-4">
              Okay we are almost done, the Transformer (yellow block of the first Diagram) just
              requires a much larger dimension input. So we will just apply a linear projection to
              reach 1024 features. Lastly, we make sure to mask out the features we don't care about
              by using the attention masks.
            </p>
            <BlogCode
              code={`hidden_states, _ = model.wav2vec2.feature_projection(extract_features)
hidden_states = model.wav2vec2._mask_hidden_states(hidden_states, attention_masks)`}
            />

            <p className="mb-4">
              We did it! 🎉 You just walked through exactly what the feature extractor (CNN) does in
              the Wav2Vec2 architecture!
            </p>

            <BlogSubheading>Takeaways</BlogSubheading>
            <p className="mb-4">
              After walking through each convolutional layer, you can probably understand how much
              computation and time this can consume. To be able to get these audio models to run in
              real time requires some careful optimization which is critical for many of our
              products.{' '}
              <a href="/streaming-optimizations" className="text-sky-600 hover:underline">
                Learn more about streaming optimizations here!
              </a>
            </p>
            <p className="mb-4">
              Part 2:{' '}
              <a href="/transformer-deep-dive" className="text-sky-600 hover:underline">
                The Transformer!
              </a>
            </p>
          </div>
        </div>
      </div>
    </BlogBody>
  );
}



================================================
FILE: app/blog/posts/new-look-for-koel-labs.tsx
================================================
// This is the individual blog post page content. It is rendered insides [slug]/page.tsx.
// The metadata object is used to display the blog post on the main blog page (app/blog/page.tsx).
// It will also be used to set meta tags for SEO once I get around to adding that.

import type { Metadata } from '../posts';
import { Source_Serif_4 } from 'next/font/google';
import BlogBody from '../blog-components/body';
import BlogHeading from '../blog-components/heading';
import BlogHeroImage from '../blog-components/hero-image';
import BlogSubheading from '../blog-components/subheading';
import BlogImage from '../blog-components/image';
import BlogDecorations from '../blog-components/decorations';

const sourceSerif = Source_Serif_4({
  subsets: ['latin'],
  weight: ['400', '700'],
});

export const metadata: Metadata = {
  title: 'A New Look for Koel Labs',
  slug: 'new-look-for-koel-labs',
  date: '2025-11-02',
  published: true,
  image: '/images/blog/new-look/blogNewLook.png',
  summary:
    'You might have noticed that we’ve given Koel Labs a fresh new look. This change is intended to better align us with our mission of pioneering inclusive speech technology, with our goals as a research-focused startup, and with our belief in openly sharing our work.',
  category: 'Announcement',
  tags: [
    {
      text: 'Website',
      url: 'https://koellabs.com',
    },
  ],
};

export default function PostBody() {
  return (
    <BlogBody>
      <div className="">
        <BlogHeading
          category={metadata.category}
          categoryColorClass="text-sky-600"
          title={metadata.title}
          dateISO={metadata.date}
          maxWidth={600}
        />
        <BlogHeroImage src="/images/blog/new-look/5-opt.png" alt="A New Look for Koel Labs" />
        <br></br>
        <div className="relative lg:col-span-3 max-w-3xl mx-auto mt-12">
          <BlogDecorations />
          <div
            className={`relative flex h-full flex-col tracking-[-0.010em] text-lg ${sourceSerif.className}`}
          >
            <BlogSubheading>A Fresh New Look</BlogSubheading>
            <p className="mb-4">
              You might have noticed that we’ve given Koel Labs a fresh new look. This change is
              intended to better align us with our mission of pioneering inclusive speech
              technology, with our goals as a research-focused startup, and with our belief in
              openly sharing our work.
            </p>
            <p className="mb-4">
              Over the last few months, we’ve built a new state-of-the-art model for phonetic
              transcription, published multiple datasets, and developed internal exploratory tools,
              all while writing papers and showcasing our research.
            </p>
            <p className="mb-10">
              Explore our website and sign up for the waitlist to be the first to experience our
              previews!
            </p>

            <div className="grid gap-6">
              <BlogImage
                src="/images/blog/new-look/2.jpeg"
                alt="New Look preview 2"
                width={1200}
                height={800}
                expanded={false}
                sizes="(max-width: 640px) 100vw, 50vw"
                className=""
              />
              <BlogImage
                src="/images/blog/new-look/3.jpeg"
                alt="New Look preview 3"
                width={1200}
                height={800}
                expanded={false}
                sizes="(max-width: 640px) 100vw, 50vw"
                className=""
              />
              <BlogImage
                src="/images/blog/new-look/4.jpeg"
                alt="New Look preview 4"
                width={1200}
                height={800}
                expanded={false}
                sizes="(max-width: 640px) 100vw, 50vw"
                className=""
              />
              <BlogImage
                src="/images/blog/new-look/5.jpeg"
                alt="New Look preview 5"
                width={1200}
                height={800}
                expanded={false}
                sizes="(max-width: 640px) 100vw, 50vw"
                className=""
              />
              <BlogImage
                src="/images/blog/new-look/6.jpeg"
                alt="New Look preview 6"
                width={1200}
                height={800}
                expanded={false}
                sizes="(max-width: 640px) 100vw, 50vw"
                className=""
              />
              <BlogImage
                src="/images/blog/new-look/7.jpeg"
                alt="New Look preview 7"
                width={1200}
                height={800}
                expanded={false}
                sizes="(max-width: 640px) 100vw, 50vw"
                className=""
              />
              <BlogImage
                src="/images/blog/new-look/8.jpeg"
                alt="New Look preview 8"
                width={1200}
                height={800}
                expanded={false}
                sizes="(max-width: 640px) 100vw, 50vw"
                className=""
              />
            </div>
          </div>
        </div>
      </div>
    </BlogBody>
  );
}



================================================
FILE: app/blog/posts/open-source-announcement.tsx
================================================
// This is the individual blog post page content. It is rendered insides [slug]/page.tsx.
// The metadata object is used to display the blog post on the main blog page (app/blog/page.tsx).
// It will also be used to set meta tags for SEO once I get around to adding that.

import type { Metadata } from '../posts';
import BlogBody from '../blog-components/body';
import BlogHeading from '../blog-components/heading';
import BlogHeroImage from '../blog-components/hero-image';
import BlogSubheading from '../blog-components/subheading';
import BlogDecorations from '../blog-components/decorations';
import { Source_Serif_4 } from 'next/font/google';

const sourceSerif = Source_Serif_4({
  subsets: ['latin'],
  weight: ['400', '700'],
});

export const metadata: Metadata = {
  title: 'Hello World! — Our Open Source Project Launch',
  slug: 'open-source-project',
  date: '2024-12-23',
  published: true,
  image: '/images/blogOpenSource.png',
  summary: `
    At Koel Labs, our goal is to make pronunciation learning more accessible and inclusive.
    To represent the diversity of language and dialects, we're excited to announce that everything 
    from model weights and training code to datasets, research papers, and the frontend UI is 
    officially open source!
  `,
  category: 'Announcement',
  tags: [
    {
      text: 'GitHub',
      url: 'https://github.com/KoelLabs',
    },
    {
      text: 'Hugging Face',
      url: 'https://huggingface.co/KoelLabs',
    },
  ],
};

export default function PostBody() {
  return (
    <BlogBody>
      <div className="">
        <BlogHeading
          category={metadata.category}
          categoryColorClass="text-sky-600"
          title={metadata.title}
          dateISO={metadata.date}
          maxWidth="2xl"
        />
        <BlogHeroImage src={metadata.image} alt={metadata.title} />
        <br></br>
        <div className="relative lg:col-span-3 max-w-3xl mx-auto mt-12">
          <BlogDecorations />
          <div
            className={`relative flex h-full flex-col overflow-hidden tracking-[-0.010em] text-lg ${sourceSerif.className}`}
          >
            <BlogSubheading>An Introduction</BlogSubheading>
            <p>{metadata.summary}</p>
            <BlogSubheading>The problem of pronunciation learning</BlogSubheading>

            <p className="mb-4">
              Currently, 48% of foreign speakers are anxious about their accents [1]. Pronunciation
              is one of the most complex parts of learning a language. It's difficult to hear the
              difference between what you're saying and what you should be saying (sometimes, it's
              impossible without a teacher, which is not affordable for many). Once you hear the
              difference, it is also super hard to learn to make sounds you've never made in your
              native language.
            </p>

            <p className="mb-4">
              Technology can bridge this gap; only existing language learning tools do not value the
              diversity of languages and dialects. A good solution should be able to understand and
              teach any accent, not just define a "standard." Moreover, the feedback should be
              nuanced, actionable, and personalized based on your native language background, not
              just a human-void ASR system saying "yes" if it recognizes each word you're saying.
            </p>

            <p className="mb-4">
              We want to collect datasets that represent the diversity of languages and dialects and
              make the entire process of training and evaluating models and then interpreting the
              results to surface explainable feedback to users reflect the diversity of backgrounds
              that language learners have.
            </p>

            <p className="mb-4">
              For us, as immigrants and children of immigrants, pronunciation learning has a special
              meaning because we see not only the importance of fitting into our new communities but
              also of fitting into our extended families.
            </p>

            <p className="mb-4">
              For others, pronunciation learning has other meanings, and we want to make sure that
              our tools can help everyone. This is why we're making the project open source — it
              allows for discussion and ideas from a worldwide audience.
            </p>

            <BlogSubheading>Current progress and plans</BlogSubheading>

            <p className="mb-4">
              We were fortunate to join the{' '}
              <a
                href="https://blog.mozilla.org/en/mozilla/14-ai-projects-to-watch-mozillas-first-builders-accelerator-cohort-kicks-off/"
                className="text-sky-600 hover:underline"
              >
                2024 Mozilla Builders program
              </a>
              . This has provided us with the resources to train state-of-the-art audio models for
              the first version of our tool targeting foreign English speakers. We are in the
              process of publishing an academic paper on our approach. We are planning on continuing
              to iterate on the pipeline to support more languages, dialects, and use cases such as
              speech pathology for speech-impaired children.
            </p>

            <p className="mb-4">
              Our web application is not yet ready, but we are gearing up for a closed beta launch
              soon. In the meantime, check out our models on{' '}
              <a
                href="https://huggingface.co/KoelLabs/xlsr-timit-b0"
                className="text-sky-600 hover:underline"
              >
                Hugging Face
              </a>{' '}
              and training code on{' '}
              <a href="https://github.com/KoelLabs/ML" className="text-sky-600 hover:underline">
                GitHub
              </a>
              .
            </p>

            <BlogSubheading>How do I get involved?</BlogSubheading>

            <p className="mb-4">
              If your institution is interested in collaborating, please reach out to us at{' '}
              <a href="mailto:info@koellabs.com" className="text-sky-600 hover:underline">
                info@koellabs.com
              </a>
              . We have already partnered with several leading HCI, Phonology, and Linguistics
              researchers from institutions like CMU, BCU, and UW.
            </p>

            <p className="mb-4">
              If you are a developer, designer, or just interested in language learning, please
              partake in the discussion on our GitHub after consulting our{' '}
              <a
                href="https://github.com/KoelLabs/.github/blob/main/CONTRIBUTING.md"
                className="text-sky-600 hover:underline"
              >
                contribution guidelines
              </a>
              . Any feedback is welcome. User feedback is especially important to us, so if you are
              open to joining the beta testing program, please sign up{' '}
              <a
                href="https://forms.gle/12A9e2YYd9Ptzi2X6"
                className="text-sky-600 hover:underline"
              >
                here
              </a>
              .
            </p>

            <hr className="my-8 border-t border-neutral-200" />

            <p className="text-sm text-neutral-600">
              [1] Babbel Anxiety Study. Retrieved from{' '}
              <a
                href="https://www.babbel.com/en/magazine/accent-anxiety-study"
                className="text-sky-600 hover:underline"
              >
                https://www.babbel.com/en/magazine/accent-anxiety-study
              </a>
            </p>
          </div>
        </div>
      </div>
    </BlogBody>
  );
}



================================================
FILE: app/blog/posts/phonemic-transcription-metrics.tsx
================================================
// This is the individual blog post page content. It is rendered insides [slug]/page.tsx.
// The metadata object is used to display the blog post on the main blog page (app/blog/page.tsx).
// It will also be used to set meta tags for SEO once I get around to adding that.

import type { Metadata } from '../posts';
import { Source_Serif_4 } from 'next/font/google';
import BlogBody from '../blog-components/body';
import BlogHeading from '../blog-components/heading';
import BlogHeroImage from '../blog-components/hero-image';
import BlogSubheading from '../blog-components/subheading';
import BlogCode from '../blog-components/code';
import BlogDecorations from '../blog-components/decorations';
import BlogImage from '../blog-components/image';

const sourceSerif = Source_Serif_4({
  subsets: ['latin'],
  weight: ['400', '700'],
});

// formatDate moved to blog primitives; using internal from heading

export const metadata: Metadata = {
  title: 'A Deep Dive into Phonemic Transcription Metrics',
  slug: 'phonemic-transcription-metrics',
  date: '2024-12-30',
  published: true,
  image: '/images/blogPhonetic.png',
  summary:
    'The International Phonetic Alphabet (IPA) is like the Swiss Army knife of pronunciation—it gives us precise symbols to represent every sound humans make in language. In recent years, predicting these phonemic transcriptions from audio has become a popular machine learning task. But how do we calculate the accuracy of these models?',
  category: 'Technical Report',
  tags: [
    {
      text: 'Leaderboard',
      url: 'https://huggingface.co/spaces/KoelLabs/IPA-Transcription-EN',
    },
  ],
};

export default function PostBody() {
  return (
    <BlogBody>
      <BlogHeading
        category={metadata.category}
        categoryColorClass="text-purple-600"
        title={metadata.title}
        dateISO={metadata.date}
        maxWidth="3xl"
      />

      <BlogHeroImage src={metadata.image} alt="Phonemic Transcription Metrics" />
      <br></br>
      <div className="relative lg:col-span-3 max-w-3xl mx-auto mt-12">
        <BlogDecorations />
        <div
          className={`relative flex h-full flex-col tracking-[-0.010em] text-lg ${sourceSerif.className}`}
        >
          <BlogSubheading>An Introduction</BlogSubheading>
          <p className="mb-4">{metadata.summary}</p>
          <p className="mb-4">
            At Koel Labs, we use two key metrics to evaluate phonemic transcription models:
          </p>

          <ol className="list-decimal list-inside mb-4 pl-4">
            <li className="mb-2">
              Phonemic Error Rate (PER): The classic "how many mistakes did you make?" metric
            </li>
            <li className="mb-2">
              Weighted Phonemic Edit Distance (WPED): A smarter approach that considers how similar
              sounds are to each other
            </li>
          </ol>

          <BlogSubheading>Why Traditional Metrics Fall Short: A Tale of Three Words</BlogSubheading>

          <p className="mb-4">
            Let's say we're trying to transcribe the word "Bop". Our model could make different
            types of mistakes, and this is where things get interesting.
          </p>

          <p className="mb-4">Consider two models making different predictions:</p>

          <ul className="list-disc list-inside mb-4 pl-4">
            <li className="mb-2">Model 1 predicts: "Pop"</li>
            <li className="mb-2">Model 2 predicts: "Sop"</li>
          </ul>

          <p className="mb-4">
            From a linguistics perspective, these mistakes are not created equal:
          </p>

          <ul className="list-disc list-inside mb-4 pl-4">
            <li className="mb-2">
              'B' and 'P' are like cousins—they're both plosive bilabial consonants, made by
              stopping airflow with your lips. The only difference is that 'B' is voiced (your vocal
              cords vibrate) and 'P' isn't.
            </li>
            <li className="mb-2">
              'B' and 'S', on the other hand, are more like distant relatives. 'S' is a fricative
              alveolar consonant, made by forcing air between your tongue and the ridge behind your
              upper teeth—a completely different sound!
            </li>
          </ul>

          <p className="mb-4">
            This is where traditional PER falls short. It calculates errors based on simple
            substitutions, deletions, and insertions. In our example:
          </p>

          <BlogCode
            code={`"Bop" → "Pop": 1 substitution = 33.33% error rate
"Bop" → "Sop": 1 substitution = 33.33% error rate`}
          />

          <p className="mb-4">
            This is like saying someone who almost hit the bullseye did just as poorly as someone
            who hit the wall next to the dartboard. You can imagine that this would create very
            misleading evaluations.
          </p>

          <BlogSubheading>Weighted Phonemic Edit Distance</BlogSubheading>

          <p className="mb-4">
            This is where WPED comes to the rescue, powered by the{' '}
            <a href="https://github.com/dmort27/panphon" className="text-sky-600 hover:underline">
              Panphon library
            </a>
            . Instead of treating each phoneme as completely different or identical, it represents
            them as a sequence of features—things like:
          </p>

          <ul className="list-disc list-inside mb-4 pl-4">
            <li className="mb-2">Is it voiced?</li>
            <li className="mb-2">Where in the mouth is it made?</li>
            <li className="mb-2">How is the air released?</li>
          </ul>

          <p className="mb-4">Each phoneme becomes a feature vector, something like:</p>

          <BlogCode
            code={`B: [+voiced, +bilabial, +plosive, -fricative, ...]
P: [-voiced, +bilabial, +plosive, -fricative, ...]
S: [-voiced, +alveolar, -plosive, +fricative, ...]`}
          />

          <p className="mb-4">
            When we calculate the distance between these vectors, we get a much more nuanced view:
          </p>

          <BlogCode
            code={`Distance("Bop" → "Pop") = 0.2  // Small difference
Distance("Bop" → "Sop") = 0.8  // Large difference`}
          />

          <div className="my-8">
            <BlogImage
              src="/images/PERversus.svg"
              alt="Diagram illustrating phonemic distances"
              width={600}
              height={400}
              className="mx-auto"
              expanded={false}
            />
          </div>

          <BlogSubheading>Why This Matters</BlogSubheading>

          <p className="mb-4">
            When you're teaching a model to transcribe speech, you want it to understand that
            predicting a similar sound is better than predicting a completely different one. This is
            especially important because different models might use different phoneme
            vocabularies—some might have 40 symbols, others up to 400.
          </p>

          <p className="mb-4">
            Traditional PER might unfairly favor models that happen to use the exact same phoneme
            set as your ground truth data, even if other models are making more linguistically
            sensible predictions. WPED helps level the playing field by considering phonetic
            similarity.
          </p>

          <BlogSubheading>The Takeaway</BlogSubheading>

          <p className="mb-4">
            By using WPED alongside traditional metrics like PER, we can better understand how well
            our models are really performing at phonemic transcription. It's not just about getting
            the exact right symbol—it's about understanding the underlying sounds of language.
          </p>

          <p className="mb-4">
            As we continue to develop better speech recognition models, metrics like WPED will be
            crucial in helping us measure progress in a way that actually reflects linguistic
            reality. After all, in the world of pronunciation, being close sometimes counts for a
            lot more than traditional metrics might suggest!
          </p>
        </div>
      </div>
    </BlogBody>
  );
}



================================================
FILE: app/blog/posts/transformer-deep-dive.tsx
================================================
import type { Metadata } from '../posts';
import BlogBody from '../blog-components/body';
import BlogHeading from '../blog-components/heading';
import BlogHeroImage from '../blog-components/hero-image';
import BlogSubheading from '../blog-components/subheading';
import BlogDecorations from '../blog-components/decorations';
import BlogCode from '../blog-components/code';
import { Source_Serif_4 } from 'next/font/google';
import BlogImage from '../blog-components/image';

const sourceSerif = Source_Serif_4({
  subsets: ['latin'],
  weight: ['400', '700'],
});

export const metadata: Metadata = {
  title: 'The Underlying Intuition of Wav2Vec2’s Transformer',
  slug: 'transformer-deep-dive',
  date: '2025-10-25',
  published: true,
  image: '/blog/transformer/blogTransformer.png',
  summary:
    'Wav2Vec2’s Transformer handles encoded audio features and aligns them to text. Building on our blog post about the feature extractor, this post dives into positional encodings tailored to audio and how CTC loss solves alignment without frame-level labels.',
  category: 'Technical Report',
  tags: [
    { text: 'Audio Processing', url: '/tags/audio-processing' },
    { text: 'Wav2Vec2', url: '/tags/wav2vec2' },
    { text: 'Transformer', url: '/tags/transformer' },
  ],
};

export default function PostBody() {
  return (
    <BlogBody>
      <div className="">
        <BlogHeading
          category={metadata.category}
          categoryColorClass="text-sky-600"
          title={metadata.title}
          dateISO={metadata.date}
          maxWidth={700}
        />
        <BlogHeroImage
          src="/blog/transformer/blogTransformer.png"
          alt="Wav2Vec2 Architecture Diagram"
        />
        <br></br>
        <div className="relative lg:col-span-3 max-w-3xl mx-auto mt-12">
          <BlogDecorations />
          <div
            className={`relative flex h-full flex-col tracking-[-0.010em] text-lg ${sourceSerif.className}`}
          >
            <p className="mb-4">
              Typically, every explanation of the{' '}
              <a
                href="https://arxiv.org/pdf/2006.11477"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                Wav2vec2 architecture
              </a>{' '}
              begins with this iconic diagram (Baevski et. al). But without extensive background, it
              is hard to know how this yellow block compares to the traditional Transformer.
            </p>
            <p className="mb-4">
              The Wav2Vec2 architecture distinguishes itself from other Transformer-based
              architectures largely in processing audio input and aligning the output. In our last
              article, we discuss Wav2Vec2's Feature Extractor: turning raw audio into feature
              vectors. Now we'll trace how Wav2Vec2 encodes positional information of sound in the
              Transformer and how it aligns its predictions to text.
            </p>

            <BlogSubheading>Wav2Vec2 Transformer: Processing Input</BlogSubheading>
            <p className="mb-4">
              Also called the Context Network, the Transformer processes feature vectors using self-
              <a
                href="https://arxiv.org/pdf/1706.03762"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                attention
              </a>
              , which lets each feature attend to all other features in the sequence.
            </p>
            <BlogImage
              src="/blog/transformer/image-one.png"
              alt="Wav2Vec2 diagram"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="text-center text-sm font-medium text-neutral-700 mb-12">
              Visual glimpse into attention matrix computation of self-attention
            </p>
            <p className="mb-4">
              But a critical challenge is that attention naturally ignores the order of the input
              sequence.
            </p>
            <p className="mb-4">
              When we take the dot product of the query and key vectors, a different ordering of the
              input sequence can produce equivalent vectors. This goes back to the dot product being
              commutative.
            </p>
            <p className="mb-4">
              We can look at another commutative operation as a <strong>toy example</strong>:
              addition. You can see that there is{' '}
              <strong>
                no way to distinguish a 1 in the very first position from a 1 in the very last
                position,
              </strong>{' '}
              the attention mechanism understands the sequences equivalently.
            </p>
            <BlogImage
              src="/blog/transformer/image-two.png"
              alt="image2"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />

            <BlogSubheading>Why is this a problem?</BlogSubheading>
            <p className="mb-4">
              The sounds we produce are often influenced by surrounding sounds. For example, in many
              dialects, a vowel before the “L” in “bottle” gets inserted, to create the syllabic “
              <strong>l̩</strong>” : “bottal”. Understanding each sound individually would likely
              mean that these syllabic sounds like “<strong>l̩</strong>” would be poorly predicted by
              the model. Surrounding consonants and vowels influence our speech making embeddings
              that encode these temporal relationships essential.
            </p>

            <BlogSubheading>Positional Embeddings</BlogSubheading>
            <p className="mb-4">
              Before we understand how Wav2Vec2 handles position, let's look at various attempts to
              develop positional embeddings. We will start with absolute positional embeddings.
            </p>
            <p className="mb-4">
              The simplest approach is to give each position in the sequence a unique vector, almost
              like a name tag:
            </p>
            <p className="mb-4">
              Position <strong>0</strong> gets vector A, Position <strong>1</strong> gets vector B,
              Position <strong>2</strong> gets vector C, …
            </p>
            <p className="mb-4">
              But hardcoded positions are limiting. You can only have as many tags as the{' '}
              <strong>longest training</strong> example so generalizing to unseen, longer lengths
              during inference is difficult.
            </p>
            <BlogImage
              src="/blog/transformer/image-three.png"
              alt="image3"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="mb-4">
              <strong>Sinusoidal Positional Embeddings</strong>
            </p>
            <p className="mb-4">
              In an attempt to develop a method that could handle unseen sequence lengths, the
              authors of{' '}
              <a
                href="https://arxiv.org/pdf/1706.03762"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                <em>Attention Is All You Need</em>
              </a>{' '}
              introduced <strong>sinusoidal embeddings</strong>.
            </p>
            <BlogImage
              src="/blog/transformer/image-four.png"
              link="https://arxiv.org/pdf/1706.03762"
              alt="Sinusoidal Positional Embeddings"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />

            <p className="text-center text-sm font-medium text-neutral-700 mb-12 max-w-md mx-auto">
              They use sine and cosine functions on even and odd positions, denoted as{' '}
              <em>PE(pos, 2i)</em> and <em>PE(pos, 2i+1)</em>, respectively.
            </p>

            <BlogSubheading>Break: Story Time</BlogSubheading>
            <p className="mb-4">
              For an intuition of sinusoidal embeddings, let me tell you a story.
            </p>
            <p className="mb-4">
              My friend Helen was attending school in Germany and told me that they did terribly in
              English class, she had gotten a 4! I laughed and said she was being dramatic: “A 4
              isn’t bad at all!” To make her feel better, I told her: “I got a <strong>D</strong> in
              science”.
            </p>
            <p className="mb-4">
              But then, she told me that a 5 was the worst grade you could get. Turns out, I was
              doing about as badly in science as she was in English…
            </p>
            <p className="">
              Funny enough, our poor academics illustrate the sine function quite well. The sine
              function allows for strong local understanding. Within my American school system, my
              classmates all knew how grades compared: an A is better than a B, a B is better than a
              C. Within Helen’s German system, her peers also understood the relative order. So
              global distance is harder to understand but local relative distance can be well
              understood.
            </p>
            <BlogImage
              src="/blog/transformer/image-five.png"
              alt="image5"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />

            <p className="mb-4">
              For a model that cares more about local distance, this function is very practical.
              Instead of giving every position its own unique number, which would quickly become
              unmanageable, they use a smaller set of values along a few smooth repeating functions.
              Note that the authors added cosine for additional expressability so more numbers could
              be represented but it follows the same principle as the sine function.
            </p>
            <BlogImage
              src="/blog/transformer/image-six.png"
              alt="image6"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="text-center text-sm font-medium text-neutral-700 mb-12">
              Sine and cosine functions for arbitrarily chosen dimension 16
            </p>
            <p className="mb-4">
              Funny enough,{' '}
              <a
                href="https://arxiv.org/pdf/1706.03762"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                <em>Attention Is All You Need</em>
              </a>{' '}
              spent time adding in sinusoidal embeddings for it to perform identically to simple
              indexing.
            </p>
            <p className="mb-4">
              The challenge appears not to be formulating positional understanding but preserving
              it.{' '}
              <a
                href="https://arxiv.org/pdf/1911.04474"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                Yan et al.
              </a>{' '}
              finds that relative positional understanding in the input embedding gets destroyed
              during the attention mechanism when projected through the weight matrices (W_Q and
              W_K).
            </p>
            <BlogImage
              src="/blog/transformer/image-seven.png"
              alt="image7"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="mb-4">
              <a
                href="https://arxiv.org/pdf/1911.04474"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                https://arxiv.org/pdf/1911.04474
              </a>
            </p>
            <p className="mb-4">
              In the Figure, (Yan et al.), distance information is preserved in the raw positional
              encodings (blue line) as shown by the symmetrical peak where positions close to each
              other (in the center) have a higher dot product . However, after multiplication by the
              attention weight matrices, we get seemingly random patterns (orange/green lines) that
              no longer clearly encode distance.
            </p>

            <BlogSubheading>Limitations of Absolute Positional Embeddings</BlogSubheading>
            <p className="mb-4">
              Both methods of absolute positional embeddings are limited by the fact that you can
              only recover positional information by some global lookup table telling you the
              sinusoidal values and simple indices which every feature corresponds to.
            </p>
            <p className="">
              Instead, a good way to find the positional information of a feature could be to bake
              it into the feature itself. Positional information would be innate to the feature like
              a puzzle piece. Each piece has grooves from the neighboring pieces that inform you
              where it should go. Even though the puzzle piece does not have a number indicating its
              position, it can be determined where the puzzle piece belongs using other neighboring
              pieces.
            </p>
            <BlogImage
              src="/blog/transformer/image-eight.png"
              alt="image8"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />

            <BlogSubheading>Wav2Vec2 positional encodings</BlogSubheading>
            <p className="mb-4">
              Wav2Vec2 accomplishes positional understanding by capturing local dependencies through{' '}
              <a
                href="https://arxiv.org/pdf/1904.11660"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                convolutions at the input level
              </a>
              , before features reach the transformer (
              <em>
                methods like RoPE achieve similar goals by modifying the attention mechanism itself,
                but that's a story for{' '}
                <a
                  href="http://koellabs.com"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-sky-600 hover:underline"
                >
                  another pos
                </a>
              </em>
              <a
                href="http://koellabs.com"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                t
              </a>
              ).
            </p>
            <p className="mb-4">
              As we covered in our{' '}
              <a
                href="http://koellabs.com"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                previous post
              </a>{' '}
              on the feature extractor (CNN), convolutions are used to naturally encode positions by
              using a sliding window over adjacent frames. They effectively represent relative local
              patterns like "a pattern across frames t-1, t, and t+1" rather than absolute global
              ones like "frame t with a position tag."
            </p>
            <p className="mb-4">
              Likewise, convolutions can be applied to the output feature vectors after linear
              projection from the feature extractor for positional understanding.
            </p>
            <BlogImage
              src="/blog/transformer/image-nine.png"
              alt="image9"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="">
              The wav2vec2 architecture uses grouped convolutions, where different groups specialize
              in different temporal relationships. Some might focus on quick changes between sounds,
              while others capture longer patterns like rhythm and intonation.
            </p>
            <BlogImage
              src="/blog/transformer/image-ten.png"
              alt="image10"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="">
              So now the positional information survives as it is intrinsic to what the feature
              represents. If a feature encodes "a rising pitch across three frames," that relational
              pattern persists through linear transformations.
            </p>

            <BlogImage
              src="/blog/transformer/image-eleven.png"
              alt="image11"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />

            <p className="mb-4">
              From here, every 25 millisecond frame processed has positional information that the
              Transformer processes, outputting a single token prediction.
            </p>
            <p className="mb-4">
              But this creates obvious problems: people don’t speak one character every 20
              milliseconds! For example, the “o” in “hello” probably takes ~1/10th a second which is
              100 milliseconds, much more than 20 milliseconds.
            </p>
            <p className="mb-4">
              Finding what parts of the audio correspond to the predicted transcription is quite
              challenging. The audio datasets the model is trained on will (most of the time) not
              include timing information that says which word or syllable occurs where in the audio
              file because annotating this is super labor intensive. How will we know how to align
              the sequence to text?
            </p>

            <BlogSubheading>CTC Loss: Aligning The Output</BlogSubheading>
            <p className="mb-4">
              <strong>Training with CTC Loss:</strong>
            </p>
            <p className="mb-4">
              Goal: Train the model to assign high probability to paths that match the target
              sequence as shown below.
            </p>
            <BlogImage
              src="/blog/transformer/image-twelve.png"
              alt="image11"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="mb-4">
              Note that we will “collapse” sequences by merging repeated characters and dropping the
              ε character:
            </p>
            <p className="mb-4">
              The challenging part of this task is that there are many ways to predict this
              distribution such that you collapse to the correct target sequence. For example,
              “CAAB” and “εCAεB” both collapse to “CAB”. So how do we train a model with a multitude
              of possible sequences?.
            </p>
            <p className="mb-4">
              Your intuition may be to sum across the probabilities of paths that produce correct
              sequences.
            </p>
            <BlogImage
              src="/blog/transformer/image-thirteen.png"
              alt="image12"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="mb-4">
              Not a bad idea! But this will just give us some arbitrary number like 5.76 which is
              hard to know how well the model is performing.
            </p>
            <p className="mb-4">
              In an ideal world where the model has 100% certainty of the path that produces a
              correct sequence, it should receive 0 penalty. Likewise, if the model is very
              uncertain but still produces a correct sequence, it should receive more penalty.
            </p>
            <p className="mb-4">
              <em>
                It is like a multiple choice exam, two students can score well but one may have
                guessed more than another. If we know each student’s own personal certainty can we
                write a function that reflects this?
              </em>
            </p>
            <p className="mb-4">
              Easy! We use the function -log(x). For certainty of 1, we have penalty -log(1) = 0.
              Likewise for low certainty like 0.2, we have penalty -log(0.2) = 0.69
            </p>
            <BlogImage
              src="/blog/transformer/image-fourteen.png"
              alt="image13"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="mb-4">Nice! This is a good loss function for training.</p>

            <BlogSubheading>Efficiency</BlogSubheading>
            <p className="mb-4">
              But a brute force approach to sum path probabilities as illustrated above would be
              very slow. Dynamic programming can be used instead where we use memoization to store
              total probabilities at each timestep. Here is what the DP table could look like:
            </p>
            <BlogImage
              src="/blog/transformer/image-fifteen.png"
              alt="image14"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="mb-4">
              <strong>Inference with CTC Loss:</strong>
            </p>
            <p className="mb-4">
              Goal: Given the trained model’s outputs, find the most likely text sequence.
            </p>
            <BlogImage
              src="/blog/transformer/image-sixteen.png"
              alt="image15"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="mb-4">
              We could simply use{' '}
              <a
                href="https://en.wikipedia.org/wiki/Greedy_algorithm"
                target="_blank"
                rel="noopener noreferrer"
                className="text-sky-600 hover:underline"
              >
                greedy search
              </a>{' '}
              to grab the maximum probability at each timestep, but greedy makes locally optimal
              choices that can miss the globally best path. A slightly lower probability token now
              might enable much higher probabilities later. So, a modified beam search is used to
              optimally find the best sequence even when you have multiple possible alignments
              mapping to the same output.
            </p>
            <p className="mb-4">
              So this modified beam search on the CTC head outputs allows us to find our final
              output!
            </p>

            <BlogSubheading>Conclusion</BlogSubheading>
            <p className="mb-4">
              To summarize, we started with a fundamental problem: attention mechanisms don’t
              naturally understand order. To fix this, Wav2Vec2 uses convolutional positional
              encodings that capture local context in sound rather than absolute positions (crucial
              for variable-length audio and how adjacent sounds influence each other).
            </p>
            <p className="mb-4">
              Then we tackled the alignment challenge. Without knowing exactly when each character
              appears in the audio, CTC provides an elegant solution: consider all possible
              alignments, predict at regular 20ms intervals, use blank tokens for silence, and
              collapse duplicates during decoding.
            </p>
            <BlogImage
              src="/blog/transformer/image-seventeen.png"
              alt="image16"
              width={1200}
              height={600}
              expanded={false}
              className="my-8"
            />
            <p className="mb-4">
              By focusing on relationships rather than absolute positions, and probabilities rather
              than hard alignments, Wav2Vec2 can learn from audio at scale.
            </p>
          </div>
        </div>
      </div>
    </BlogBody>
  );
}



================================================
FILE: app/contact/page.tsx
================================================
'use client';

import CTA from '@/components/sections/cta';
import Footer from '@/components/sections/footer';
import Header from '@/components/ui/header';
import { Button } from '@/components/ui/base/button';
import { Input } from '@/components/ui/base/input';
import { Label } from '@/components/ui/base/label';
import { Textarea } from '@/components/ui/base/textarea';
import { useToast } from '@/hooks/use-toast';
import { useCharacterLimit } from '@/lib/use-character-limit';
import { AtSign, BookDashed, User } from 'lucide-react';
import { useState, useCallback } from 'react';

import { GoogleReCaptchaProvider, useGoogleReCaptcha } from 'react-google-recaptcha-v3';

function ContactForm() {
  const { toast } = useToast();

  const maxLength = 500;
  const [value, setValue] = useState('');
  const { characterCount, handleChange, maxLength: limit } = useCharacterLimit({ maxLength });

  // setup reCaptcha v3 (background score)
  const { executeRecaptcha } = useGoogleReCaptcha();
  // event handler for reCaptcha verification on form submission
  const submitFormWithReCaptchaVerification = useCallback(
    async (formData: FormData) => {
      if (!executeRecaptcha) {
        toast({
          title: 'Error',
          description:
            'ReCAPTCHA not yet loaded. Cannot verify that you are a human, please wait a bit and try again. Double check you are not using a VPN or adblocker if the problem persists and, if all else fails, reach out via email.',
          status: 'error',
        });
        return;
      }

      const token = await executeRecaptcha('contactFormSubmit');
      const res = await fetch(
        `/api/submitGoogleFormWithReCaptcha?formName=contact&token=${token}`,
        {
          method: 'POST',
          body: formData,
        },
      );

      if (res.ok) {
        toast({
          title: 'Submitted',
          description: 'Thank you for contacting us!',
        });
        return true;
      } else {
        res.text().then(console.error);
        toast({
          title: 'Error',
          description:
            'Failed to verify your humanity. Make sure to disable VPNs and adblockers, double check you are not a robot, and email us if the issue persists.',
          status: 'error',
        });
        return false;
      }
    },
    [executeRecaptcha],
  );

  return (
    <div className="mx-auto max-w-md text-center lg:flex-auto lg:py-32">
      <p className="text-sm/4 font-semibold text-sky-800 mb-2">Contact Form</p>
      <h2 className="text-balance text-3xl font-semibold tracking-tight text-black sm:text-4xl">
        {/* Ready to start learning? */}
        Let's get in touch
      </h2>
      <p className="text-lg/8 text-neutral-700 mt-4">
        We're here to help you with any questions, concerns, or feedback you may have.
      </p>
      <form
        method="POST"
        onSubmit={e => {
          e.preventDefault();
          const target = e.currentTarget;
          const formData = new FormData(target);
          submitFormWithReCaptchaVerification(formData).then(success => {
            if (success) {
              setValue('');
              target.reset();
            }
          });
        }}
        className="space-y-2"
      >
        <div className="space-y-2  text-left mt-4">
          <Label htmlFor="input-name">Name</Label>
          <div className="relative">
            <Input
              id="input-name"
              required
              autoComplete="name nickname given-name"
              name="entry.358867278"
              className="peer ps-9 rounded-xl"
              placeholder="Name"
              type="text"
            />
            <div className="pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 text-muted-foreground/80 peer-disabled:opacity-50">
              <User size={16} strokeWidth={2} aria-hidden="true" />
            </div>
          </div>
        </div>
        <div className="space-y-2  text-left mt-3">
          <Label htmlFor="input-email">Email</Label>
          <div className="relative">
            <Input
              id="input-email"
              required
              name="entry.65859822"
              className="peer ps-9 rounded-xl"
              placeholder="Email"
              type="email"
            />
            <div className="pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 text-muted-foreground/80 peer-disabled:opacity-50">
              <AtSign size={16} strokeWidth={2} aria-hidden="true" />
            </div>
          </div>
        </div>
        <div className="space-y-2  text-left mt-3">
          <Label htmlFor="input-topic">Topic</Label>
          <div className="relative">
            <Input
              id="input-topic"
              required
              name="entry.1735979938"
              className="peer ps-9 rounded-xl"
              placeholder="Topic"
              type="text"
            />
            <div className="pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 text-muted-foreground/80 peer-disabled:opacity-50">
              <BookDashed size={16} strokeWidth={2} aria-hidden="true" />
            </div>
          </div>
        </div>
        <div className="space-y-2 text-left mt-3">
          <Label htmlFor="textarea-message">Message</Label>
          <Textarea
            id="textarea-message"
            name="entry.1856129796"
            required
            value={value}
            maxLength={maxLength}
            placeholder="Message"
            onChange={e => {
              setValue(e.target.value);
              handleChange(e);
            }}
            aria-describedby="characters-left-textarea"
          />
          <p
            id="characters-left-textarea"
            className="mt-2 text-right text-xs text-muted-foreground"
            role="status"
            aria-live="polite"
          >
            <span className="tabular-nums">{limit - characterCount}</span> characters left
          </p>
        </div>
        <Button type="submit" className="mt-3 bg-linear-to-b border-black bg-sky-950 w-full">
          Submit
        </Button>
        <p className="text-xs text-neutral-500 mt-2 pt-2">
          This form is protected by reCAPTCHA and the Google{' '}
          <a className="underline" href="https://policies.google.com/privacy">
            Privacy Policy
          </a>{' '}
          and{' '}
          <a className="underline" href="https://policies.google.com/terms">
            Terms of Service
          </a>{' '}
          apply.
        </p>
      </form>
    </div>
  );
}

export default function Contact() {
  return (
    <div className={`min-h-screen`}>
      <div className="z-10 sticky top-0 mx-auto w-full">
        <Header />
      </div>

      {/* <div className="absolute right-0 -top-20 w-full h-[110%] bg-gradient-to-b from-[#0086FF] to-[#2A4BCC] z-[2] mix-blend-color pointer-events-none"></div> */}
      {/* <div className="absolute left-0 -top-20 w-[60px] h-[110%] bg-gradient-to-b from-[#0086FF] to-[#2A4BCC] z-[2] mix-blend-color"></div> */}

      <div className="mx-auto py-24 sm:py-32 sm:pt-0 sm:-mt-px  z-[8] relative">
        <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
        <div className="max-w-[908px] mx-auto relative overflow-x-hidden lg:overflow-x-visible">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="1234"
            height="1815"
            fill="none"
            viewBox="0 0 1234 1815"
            className="absolute -top-104 -left-[960px] scale-50 md:block hidden"
          >
            <g stroke="#E5E5E5" strokeWidth="2" clipPath="url(#clip0_4363_485)">
              <path d="M505.393 957.159c-21.522-31.138-21.522-72.348 0-103.486L1088.81 9.566c50.75-73.424 165.87-37.511 165.87 51.743V1749.52c0 89.26-115.12 125.17-165.87 51.75z"></path>
              <rect
                width="1813"
                height="1231.7"
                x="1232.7"
                y="1"
                rx="33"
                transform="rotate(90 1232.7 1)"
              ></rect>
            </g>
            <defs>
              <clipPath id="clip0_4363_485">
                <rect
                  width="1815"
                  height="1233.7"
                  x="1233.7"
                  fill="#fff"
                  rx="30"
                  transform="rotate(90 1233.7 0)"
                ></rect>
              </clipPath>
            </defs>
          </svg>
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="1234"
            height="1815"
            fill="none"
            viewBox="0 0 1234 1815"
            className="absolute -top-104 -right-[960px] scale-50 rotate-y-180 md:block hidden"
          >
            <g stroke="#E5E5E5" strokeWidth="2" clipPath="url(#clip0_4363_485)">
              <path d="M505.393 957.159c-21.522-31.138-21.522-72.348 0-103.486L1088.81 9.566c50.75-73.424 165.87-37.511 165.87 51.743V1749.52c0 89.26-115.12 125.17-165.87 51.75z"></path>
              <rect
                width="1813"
                height="1231.7"
                x="1232.7"
                y="1"
                rx="33"
                transform="rotate(90 1232.7 1)"
              ></rect>
            </g>
            <defs>
              <clipPath id="clip0_4363_485">
                <rect
                  width="1815"
                  height="1233.7"
                  x="1233.7"
                  fill="#fff"
                  rx="30"
                  transform="rotate(90 1233.7 0)"
                ></rect>
              </clipPath>
            </defs>
          </svg>

          <div className="absolute left-0 top-0 w-[43.5px] ml-px h-[43.5px] bg-neutral-50 p-1 z-[2] hidden 2xl:block">
            <div className="rounded-full w-full h-full border bg-white"></div>
          </div>

          <div className="absolute -right-[0.25px] top-0 w-[44px] mr-px h-[43.5px] bg-neutral-50 p-1 z-[2] hidden 2xl:block">
            <div className="rounded-full w-full h-full border bg-white"></div>
          </div>

          <div className="absolute left-0 bottom-0 w-[43.5px] ml-px h-[43.5px] bg-neutral-50 p-1 z-[2] hidden 2xl:block">
            <div className="rounded-full w-full h-full border bg-white"></div>
          </div>

          <div className="absolute right-0 bottom-0 w-[43.5px] mr-px h-[43.5px] bg-neutral-50 p-1 z-[2] hidden 2xl:block">
            <div className="rounded-full w-full h-full border bg-white"></div>
          </div>
          <div className="absolute -right-[0.5px] top-0 w-[46px] h-full overflow-hidden items-start justify-center bg-neutral-50 border-x z-[1] hidden 2xl:flex">
            <div className="flex-col h-full items-start gap-[8px] -mt-px flex">
              {Array(109)
                .fill(0)
                .map((_, i) => (
                  <div
                    key={`right-${i}`}
                    className="h-px w-[50.5px] bg-neutral-200 dark:bg-neutral-800"
                  ></div>
                ))}
            </div>
          </div>
          <div className="absolute left-0 top-0 w-[45.5px] h-full overflow-hidden items-start justify-center bg-neutral-50 border-x z-[1] hidden 2xl:flex">
            <div className="flex-col h-full items-start gap-[8px] -mt-px flex">
              {Array(109)
                .fill(0)
                .map((_, i) => (
                  <div
                    key={`right-${i}`}
                    className="h-px w-[50.5px] bg-neutral-200 dark:bg-neutral-800"
                  ></div>
                ))}
            </div>
          </div>
          <div className="backdrop-opacity-35 bg-cover bg-center relative isolate overflow-hidden border-x px-6 py-16 shadow-xs sm:px-16 md:py-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0">
            <GoogleReCaptchaProvider reCaptchaKey={process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY!}>
              <ContactForm />
            </GoogleReCaptchaProvider>
          </div>
        </div>
        <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
      </div>
      <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
        <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
          {Array(500)
            .fill(0)
            .map((_, i) => (
              <div
                key={`bottom-${i}`}
                className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
              ></div>
            ))}
        </div>
      </div>
      <CTA />
      <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
        <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
          {Array(500)
            .fill(0)
            .map((_, i) => (
              <div
                key={`bottom-${i}`}
                className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
              ></div>
            ))}
        </div>
      </div>
      <Footer />
    </div>
  );
}



================================================
FILE: app/dashboard/customTimeline.tsx
================================================
'use client';

import React, { useRef, useState } from 'react';
import * as SliderPrimitive from '@radix-ui/react-slider';

interface PracticableSection {
  start: number;
  end: number;
}

interface CustomTimelineProps {
  currentTime: number;
  duration: number;
  practicableSections: PracticableSection[];
  onSeek: (newValue: number) => void;
  onTimelineClick: (time: number) => void;
}

export default function CustomTimeline({
  currentTime,
  duration,
  practicableSections,
  onSeek,
  onTimelineClick,
}: CustomTimelineProps) {
  const timelineRef = useRef<HTMLDivElement>(null);
  const [isHovering, setIsHovering] = useState(false);

  const isInPracticableSection = (time: number) => {
    return practicableSections.some(section => time >= section.start && time <= section.end);
  };

  const renderHighlightedSections = () => {
    return practicableSections.map((section, index) => {
      const startPercentage = (section.start / duration) * 100;
      const endPercentage = (section.end / duration) * 100;
      const width = endPercentage - startPercentage;

      return (
        <div
          key={index}
          className="absolute h-full bg-blue-500"
          style={{
            left: `${startPercentage}%`,
            width: `${width}%`,
          }}
        />
      );
    });
  };

  return (
    <div
      className="relative h-5 flex items-center cursor-pointer"
      ref={timelineRef}
      onMouseEnter={() => setIsHovering(true)}
      onMouseLeave={() => setIsHovering(false)}
      onClick={e => {
        const rect = e.currentTarget.getBoundingClientRect();
        const clickPosition = (e.clientX - rect.left) / rect.width;
        onTimelineClick(clickPosition * duration);
      }}
    >
      <div className="absolute inset-0 h-1 bg-gray-600/50 rounded-full">
        {renderHighlightedSections()}
        <div
          className="absolute h-full bg-white/90 rounded-full transition-colors"
          style={{
            width: `${(currentTime / duration) * 100}%`,
            backgroundColor: isInPracticableSection(currentTime)
              ? 'rgb(59 130 246 / 0.9)'
              : undefined,
          }}
        />
      </div>
      <SliderPrimitive.Root
        className="relative flex w-full touch-none select-none items-center"
        value={[currentTime]}
        max={duration}
        step={0.1}
        onValueChange={newValue => onSeek(newValue[0])}
        aria-label="Video progress"
      >
        <SliderPrimitive.Track className="relative h-1 w-full grow rounded-full">
          <SliderPrimitive.Range className="absolute h-full rounded-full" />
        </SliderPrimitive.Track>
        <SliderPrimitive.Thumb
          className={`block h-3 w-3 rounded-full bg-white shadow-md transition-opacity absolute top-1/2 -translate-y-1/2 ${
            isHovering ? 'opacity-100' : 'opacity-0'
          } hover:opacity-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-blue-500`}
        />
      </SliderPrimitive.Root>
    </div>
  );
}



================================================
FILE: app/dashboard/layout.js
================================================
'use server';

import { AppSidebar } from '@/components/sidebar/app-sidebar';
import { SidebarLayout } from '@/components/ui/sidebar';
import { ThemeProvider } from '@/components/ui/base/theme-provider';
import { cookies } from 'next/headers';

export default async function DashboardLayout({ children }) {
  const cook = await cookies();
  const sidebarCookie = cook.get('sidebar:state');
  const defaultOpen = sidebarCookie?.value !== 'false';

  return (
    <ThemeProvider attribute="class" defaultTheme="light" enableSystem disableTransitionOnChange>
      <SidebarLayout defaultOpen={defaultOpen}>
        <AppSidebar />
        <main className="flex flex-1 flex-col transition-all duration-150 ease-in-out w-full bg-neutral-50 dark:bg-neutral-900">
          <div className="mt-4 ml-4 rounded-tl-xl rounded-br-xl border-t border-l bg-white/90 backdrop-blur-md  dark:bg-black border-neutral-200 dark:border-neutral-800 h-full relative z-[1]">
            {children}
          </div>
        </main>
      </SidebarLayout>
    </ThemeProvider>
  );
}



================================================
FILE: app/dashboard/microphone.tsx
================================================
'use client';

import React, { useState, useEffect, useCallback, useRef } from 'react';
import { Button } from '@/components/ui/base/button';
import { Circle, RefreshCw } from 'lucide-react';

export default function RecordingComponent({ feedbackGiver }) {
  const [status, setStatus] = useState<'idle' | 'recording' | 'recorded'>('idle');
  const [audioBlob, setAudioBlob] = useState<Blob | null>(null);
  const [audioUrl, setAudioUrl] = useState<string | null>(null);
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const chunksRef = useRef<Blob[]>([]);

  const startRecording = useCallback(async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      mediaRecorderRef.current = new MediaRecorder(stream);

      mediaRecorderRef.current.ondataavailable = event => {
        if (event.data.size > 0) {
          chunksRef.current.push(event.data);
        }
      };

      mediaRecorderRef.current.onstop = () => {
        const blob = new Blob(chunksRef.current, { type: 'audio/webm' });
        setAudioBlob(blob);
        setAudioUrl(URL.createObjectURL(blob));
        setStatus('recorded');
        chunksRef.current = [];
      };

      mediaRecorderRef.current.start();
      setStatus('recording');
    } catch (error) {
      console.error('Error accessing microphone:', error);
    }
  }, []);

  const stopRecording = useCallback(() => {
    if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') {
      mediaRecorderRef.current.stop();
      mediaRecorderRef.current.stream.getTracks().forEach(track => track.stop());
    }
  }, []);

  const restartRecording = useCallback(() => {
    setStatus('idle');
    setAudioBlob(null);
    setAudioUrl(null);
    startRecording();
  }, [startRecording]);

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.code === 'Space' && status === 'idle') {
        e.preventDefault();
        startRecording();
      }
    };

    const handleKeyUp = (e: KeyboardEvent) => {
      if (e.code === 'Space' && status === 'recording') {
        e.preventDefault();
        stopRecording();
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    window.addEventListener('keyup', handleKeyUp);

    return () => {
      window.removeEventListener('keydown', handleKeyDown);
      window.removeEventListener('keyup', handleKeyUp);
    };
  }, [status, startRecording, stopRecording]);

  return (
    <div className="flex flex-col max-w-[22rem] bg-neutral-100 rounded-md dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-950">
      <div className="flex gap-3 justify-between items-center m-4 mb-2">
        <h2 className="text-xl font-semibold tracking-tighter flex items-center gap-2">
          {status === 'recording' ? 'Recording' : status === 'recorded' ? 'Recorded' : 'Record'}
          {status === 'recording' && (
            <Circle className="h-4 w-4 text-red-500 animate-pulse" fill="currentColor" />
          )}
          {status === 'recorded' && (
            <Circle className="h-4 w-4 text-[#1B997B]" fill="currentColor" />
          )}
        </h2>
        <p className="text-xs tracking-tight text-neutral-500">
          Hold{' '}
          <span className="rounded-full bg-neutral-200/50 border border-neutral-300 px-1.5 py-0.5">
            Space
          </span>
        </p>
      </div>
      <p className="text-sm tracking-tight text-neutral-600 mx-4 mb-4">
        {status === 'idle'
          ? 'Start recording below using the microphone button or hold down the space bar.'
          : status === 'recording'
            ? 'Recording in progress. Release space or click stop to finish.'
            : 'Recording complete. Click restart to record again.'}
      </p>
      <div className="flex border-y mb-1 border-neutral-200 dark:border-neutral-800 p-4 gap-2">
        {status !== 'recorded' && (
          <Button
            variant="outline"
            className={`px-2 h-7 text-xs font-medium rounded-md ${
              status === 'recording'
                ? 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200 border border-red-200 dark:border-red-900 hover:bg-red-200 dark:hover:bg-red-800'
                : 'bg-[#C7E9DE] border border-[#9DD8C5] text-[#1B997B] hover:bg-[#C7E9DE]/80 hover:text-[#1B997B]'
            }`}
            onClick={status === 'recording' ? stopRecording : startRecording}
          >
            <Circle
              className={`h-4 w-4 mr-1 ${status === 'recording' ? 'text-red-800 dark:text-red-200' : 'text-[#1B997B]'}`}
              fill="currentColor"
            />
            {status === 'recording' ? 'Stop' : 'Start'}
          </Button>
        )}
        {status === 'recorded' && (
          <Button
            variant="outline"
            className="px-2 h-7 text-xs font-medium rounded-md bg-neutral-200 text-neutral-700 border border-neutral-300 hover:bg-neutral-300 dark:bg-neutral-700 dark:text-neutral-200 dark:border-neutral-600 dark:hover:bg-neutral-600"
            onClick={restartRecording}
          >
            <RefreshCw className="h-4 w-4 mr-1" />
            Restart
          </Button>
        )}
      </div>
      {audioUrl && (
        <div className="m-4">
          <p className="text-sm text-neutral-600 dark:text-neutral-400 mb-2">Recording saved!</p>
          <audio controls src={audioUrl} className="w-full" />
        </div>
      )}
    </div>
  );
}



================================================
FILE: app/dashboard/page.jsx
================================================
'use client';

import SearchCenter from '@/components/ui/dashboard/SearchCenter';
import { useEffect } from 'react';

export default function Page() {
  return (
    <div className="h-full rounded-md relative">
      <SearchCenter />
    </div>
  );
}



================================================
FILE: app/dashboard/practiceMode.tsx
================================================
import React, { useEffect, useReducer } from 'react';

export default function PracticeMode({
  isInPracticeSection,
  currentVideo,
  getCurrentSection,
  getWordStyle,
  isRecording,
}) {
  const [, forceWordUpdate] = useReducer(x => x + 1, 0);
  useEffect(() => {
    let intervalId: NodeJS.Timeout;

    if (isRecording) {
      intervalId = setInterval(() => {
        forceWordUpdate();
        console.log(currentVideo?.practicableSections[getCurrentSection()]?.target_by_word);
      }, 500); // 500ms = 0.5 seconds
    }

    return () => {
      if (intervalId) {
        clearInterval(intervalId);
      }
    };
  }, [isRecording]);
  return (
    <div className="m-3">
      {isInPracticeSection() &&
        currentVideo?.practicableSections[getCurrentSection()]?.target_by_word.map(
          (word, index) => (
            <button key={`${index}-${forceWordUpdate}`} style={getWordStyle(index)}>
              {word[0]} + {Math.random()}
            </button>
          ),
        )}
    </div>
  );
}



================================================
FILE: app/dashboard/videoPlayer.tsx
================================================
'use client';

import '@vidstack/react/player/styles/default/theme.css';
import '@vidstack/react/player/styles/default/layouts/audio.css';
import '@vidstack/react/player/styles/default/layouts/video.css';

import { MediaPlayer, MediaProvider, Poster, Track, useMediaRemote } from '@vidstack/react';
import { DefaultVideoLayout, defaultLayoutIcons } from '@vidstack/react/player/layouts/default';

export default function VideoPlayer({
  src,
  title,
  poster,
  practicableSections,
  captions,
  onTimeUpdate,
  onSeek,
}) {
  const remote = useMediaRemote();

  return (
    <MediaPlayer
      ref={el => {
        if (el) onSeek?.(remote);
      }}
      src={src}
      viewType="video"
      streamType="on-demand"
      logLevel="warn"
      crossOrigin
      playsInline
      title={title}
      poster={poster}
      onTimeUpdate={e => {
        onTimeUpdate(e.currentTime);
      }}
      className="aspect-video"
    >
      <MediaProvider>
        <Poster className="vds-poster aspect-video h-auto" />

        <Track src={practicableSections} kind="chapters" default />
        <Track src={captions} kind="subtitles" label="English" lang="en-US" type="vtt" />
      </MediaProvider>
      <DefaultVideoLayout
        thumbnails={poster}
        icons={defaultLayoutIcons}
        className="font-inter"
        slots={{
          googleCastButton: null,
          pipButton: null,
          fullscreenButton: null,
          settingsMenu: null,
        }}
      />
    </MediaPlayer>
  );
}



================================================
FILE: app/dashboard/settings/page.jsx
================================================
'use client';

import React, { useId, useState, useEffect, useMemo, useCallback, memo, useRef } from 'react';
import { Button } from '@/components/ui/base/button';
import { Input } from '@/components/ui/base/input';
import { Label } from '@/components/ui/base/label';
import { Textarea } from '@/components/ui/base/textarea';
import { Card, CardContent, CardFooter, CardHeader } from '@/components/ui/base/card';
import { ScrollArea, ScrollBar } from '@/components/ui/base/scroll-area';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/base/tabs';
import { Lock, User2, Check, Minus } from 'lucide-react';
import { RadioGroup, RadioGroupItem } from '@/components/ui/base/radio-group';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/base/select';
import { useTheme } from 'next-themes';
import { authClient } from '@/lib/auth-client';
import { useToast } from '@/hooks/use-toast';
import { Skeleton } from '@/components/ui/base/skeleton';

// Import shared form components
import LanguageSelector from '@/components/forms/language-selector';
import CountrySelector from '@/components/forms/country-selector';
import TargetLanguageSelector from '@/components/forms/target-language-selector';
import ExperienceLevelSelector from '@/components/forms/experience-level-selector';
import ChallengingWordsSelector from '@/components/forms/challenging-words-selector';
import CitySelector from '@/components/forms/city-selector';
import DatePickerComponent from '@/components/ui/base/date';
import { parseDate } from '@internationalized/date';

const themeItems = [
  { value: 'light', label: 'Light', image: '/images/light.png' },
  { value: 'dark', label: 'Dark', image: '/images/dark.png' },
  { value: 'system', label: 'System', image: '/images/system.png' },
];

// Memoized input field component
const FormInput = memo(({ label, id, name, value, onChange, isPending }) => {
  const handleChange = useCallback(
    e => {
      onChange(name, e.target.value);
    },
    [name, onChange],
  );

  if (isPending) {
    return (
      <div className="space-y-2">
        <Label htmlFor={id} className="text-sm font-medium">
          {label}
        </Label>
        <Skeleton className="h-10 w-full rounded-xl mt-1" />
      </div>
    );
  }

  return (
    <div className="space-y-2">
      <Label htmlFor={id} className="text-sm font-medium">
        {label}
      </Label>
      <Input
        id={id}
        name={name}
        className="text-sm rounded-xl mt-1"
        value={value}
        onChange={handleChange}
      />
    </div>
  );
});
FormInput.displayName = 'FormInput';

// Memoized textarea field component
const FormTextarea = memo(
  ({ label, id, name, value, onChange, isPending, placeholder, maxLength }) => {
    const handleChange = useCallback(
      e => {
        onChange(name, e.target.value);
      },
      [name, onChange],
    );

    if (isPending) {
      return (
        <div className="space-y-2">
          <Label htmlFor={id} className="text-sm font-medium ml-0.5">
            {label}
          </Label>
          <Skeleton className="h-20 w-full rounded-xl mt-1" />
          <Skeleton className="h-4 w-26 rounded-lg mt-1" />
        </div>
      );
    }

    return (
      <div className="space-y-2">
        <Label htmlFor={id} className="text-sm font-medium ml-0.5">
          {label}
        </Label>
        <Textarea
          id={id}
          name={name}
          className="min-h-[80px] rounded-xl resize-none mt-1"
          placeholder={placeholder}
          value={value}
          onChange={handleChange}
          maxLength={maxLength}
        />
        {maxLength && (
          <p className="text-xs text-muted-foreground">
            {value?.length || 0}/{maxLength} characters
          </p>
        )}
      </div>
    );
  },
);
FormTextarea.displayName = 'FormTextarea';

// Memoized appearance section
const AppearanceSection = memo(({ theme, setTheme }) => {
  const id = useId();

  return (
    <Card className="rounded-xl">
      <CardHeader className="p-5 border-b border-neutral-200 dark:border-neutral-800 rounded-t-xl bg-neutral-50 dark:bg-neutral-900">
        <div>
          <h2 className="text-lg font-medium tracking-[-0.04em]">Appearance</h2>
          <p className="text-sm text-muted-foreground mt-1">
            Customize how the app looks and feels.
          </p>
        </div>
      </CardHeader>
      <CardContent className="p-5 space-y-5">
        <div className="space-y-4">
          <fieldset className="space-y-4">
            <legend className="text-sm font-medium leading-none text-foreground">
              Choose a theme
            </legend>
            <RadioGroup className="flex gap-3" value={theme} onValueChange={setTheme}>
              {themeItems.map(item => (
                <label key={`${id}-${item.value}`}>
                  <RadioGroupItem
                    id={`${id}-${item.value}`}
                    value={item.value}
                    className="peer sr-only after:absolute after:inset-0"
                  />
                  <img
                    src={item.image}
                    alt={item.label}
                    width={90}
                    height={90}
                    className="relative object-cover cursor-pointer overflow-hidden rounded-lg border border-input shadow-xs shadow-black/5 outline-offset-2 transition-colors peer-focus-visible:outline-2 peer-focus-visible:outline-ring/70 peer-data-disabled:cursor-not-allowed peer-data-[state=checked]:border-ring peer-data-[state=checked]:bg-accent peer-data-disabled:opacity-50"
                  />
                  <span className="mt-2 flex items-center gap-1 peer-data-[state=unchecked]:text-muted-foreground/70">
                    {theme === item.value ? (
                      <Check size={16} strokeWidth={2} aria-hidden="true" />
                    ) : (
                      <Minus size={16} strokeWidth={2} aria-hidden="true" />
                    )}
                    <span className="text-xs font-medium">{item.label}</span>
                  </span>
                </label>
              ))}
            </RadioGroup>
          </fieldset>
        </div>
      </CardContent>
    </Card>
  );
});
AppearanceSection.displayName = 'AppearanceSection';

// Memoized security section
const SecuritySection = memo(() => {
  return (
    <>
      <Card className="rounded-xl">
        <CardHeader className="p-5 border-b border-neutral-200 dark:border-neutral-800 rounded-t-xl bg-neutral-50 dark:bg-neutral-900">
          <div>
            <h2 className="text-lg font-medium tracking-[-0.04em]">Change Password</h2>
            <p className="text-sm text-muted-foreground mt-1">
              Update your password associated with your account.
            </p>
          </div>
        </CardHeader>
        <CardContent className="p-6 space-y-8">
          <div className="space-y-3">
            <div className="space-y-2">
              <Label htmlFor="current-password" className="text-sm font-normal ml-0.5">
                Current Password
              </Label>
              <Input
                id="current-password"
                name="current_password"
                type="password"
                className="text-sm rounded-lg mt-1"
              />
            </div>

            <div className="space-y-2">
              <Label htmlFor="new-password" className="text-sm font-normal ml-0.5">
                New Password
              </Label>
              <Input
                id="new-password"
                name="new_password"
                type="password"
                className="text-sm rounded-lg mt-1"
              />
            </div>

            <div className="space-y-2">
              <Label htmlFor="confirm-password" className="text-sm font-normal ml-0.5">
                Confirm New Password
              </Label>
              <Input
                id="confirm-password"
                name="confirm_password"
                type="password"
                className="text-sm rounded-lg mt-1"
              />
            </div>
          </div>
        </CardContent>
        <CardFooter className="bg-neutral-50 dark:bg-neutral-900 rounded-b-xl border-t border-neutral-200 dark:border-neutral-800 p-4">
          <Button size="settings">Update Password</Button>
        </CardFooter>
      </Card>

      <Card className="rounded-xl">
        <CardHeader className="p-5 border-b border-neutral-200 dark:border-neutral-800 rounded-t-xl bg-neutral-50 dark:bg-neutral-900">
          <div>
            <h2 className="text-lg font-medium tracking-[-0.04em] text-destructive dark:text-red-500">
              Delete Account
            </h2>
            <p className="text-sm text-muted-foreground mt-1">
              No longer want to use our service? You can delete your account here. This action is
              not reversible. All information related to this account will be deleted permanently.
            </p>
          </div>
        </CardHeader>
        <CardContent className="p-5 space-y-8">
          <div>
            <Button size="settings" variant="destructive">
              Yes, Delete My Account
            </Button>
          </div>
        </CardContent>
      </Card>
    </>
  );
});
SecuritySection.displayName = 'SecuritySection';

export default function SettingsPage() {
  const { theme, setTheme } = useTheme();
  const { toast } = useToast();
  const fileInputRef = useRef(null);

  const { data: session, isPending, refetch } = authClient.useSession();

  const [formData, setFormData] = useState({
    firstName: '',
    lastName: '',
    targetLanguage: '',
    nativeLanguage: '',
    nativeLanguageCountry: '',
    birthday: '',
    learningCity: '',
    experienceLevel: '',
    challengingWords: '',
  });

  const [isSaving, setIsSaving] = useState(false);
  const [previewAvatar, setPreviewAvatar] = useState('');

  useEffect(() => {
    if (session?.user) {
      const nameParts = session.user.name?.split(' ') || ['', ''];
      const firstName = nameParts[0] || '';
      const lastName = nameParts.slice(1).join(' ') || '';

      let userPreferences = {};
      if (session.user.metadata) {
        try {
          userPreferences =
            typeof session.user.metadata === 'string'
              ? JSON.parse(session.user.metadata)
              : session.user.metadata;
        } catch (error) {
          console.error('Error parsing user metadata:', error);
        }
      }

      setFormData({
        firstName,
        lastName,
        targetLanguage: userPreferences.targetLanguage || '',
        nativeLanguage: userPreferences.nativeLanguage || '',
        nativeLanguageCountry: userPreferences.nativeLanguageCountry || '',
        birthday: userPreferences.birthday || '',
        learningCity: userPreferences.learningCity || '',
        experienceLevel: userPreferences.experienceLevel || '',
        challengingWords: userPreferences.challengingWords || '',
      });

      setPreviewAvatar(session.user.image || '');
    }
  }, [session]);

  const handleInputChange = useCallback((field, value) => {
    setFormData(prev => ({
      ...prev,
      [field]: value,
    }));
  }, []);

  const handleAvatarClick = useCallback(() => {
    fileInputRef.current?.click();
  }, []);

  const handleAvatarChange = useCallback(
    e => {
      const file = e.target.files[0];
      if (!file) return;

      if (file.size > 1024 * 1024) {
        toast({
          title: 'File too large',
          description: 'Avatar image must be less than 1MB',
          variant: 'destructive',
        });
        return;
      }

      const reader = new FileReader();
      reader.onload = event => {
        const base64Image = event.target.result;
        setPreviewAvatar(base64Image);
      };
      reader.readAsDataURL(file);
    },
    [toast],
  );

  const saveInformation = useCallback(async () => {
    if (!session?.user) return;

    setIsSaving(true);

    try {
      // First update name if changed
      if (session.user.name !== `${formData.firstName} ${formData.lastName}`.trim()) {
        const nameUpdateResponse = await fetch('/api/auth/update-user', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            name: `${formData.firstName} ${formData.lastName}`.trim(),
          }),
        });

        if (!nameUpdateResponse.ok) {
          throw new Error('Failed to update name');
        }
      }

      const preferences = {
        targetLanguage: formData.targetLanguage,
        nativeLanguage: formData.nativeLanguage,
        nativeLanguageCountry: formData.nativeLanguageCountry,
        birthday: formData.birthday,
        learningCity: formData.learningCity,
        experienceLevel: formData.experienceLevel,
        challengingWords: formData.challengingWords,
        ...(previewAvatar && previewAvatar !== session.user.image && { avatar: previewAvatar }),
      };

      const preferencesResponse = await fetch('/api/user/preferences', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(preferences),
      });

      if (!preferencesResponse.ok) {
        throw new Error('Failed to update preferences');
      }

      await refetch();

      toast({
        title: 'Settings updated',
        description: 'Your preferences have been saved successfully.',
        variant: 'default',
      });
    } catch (error) {
      console.error('Error saving information:', error);
      toast({
        title: 'Update failed',
        description: 'There was a problem saving your preferences.',
        variant: 'destructive',
      });
    } finally {
      setIsSaving(false);
    }
  }, [formData, session, toast, refetch, previewAvatar]);

  const safeParseBirthday = useCallback(dateString => {
    if (!dateString || typeof dateString !== 'string') return null;
    try {
      if (dateString.match(/^\d{4}-\d{2}-\d{2}$/)) {
        return parseDate(dateString);
      }
      return null;
    } catch (error) {
      console.warn('Failed to parse birthday:', dateString, error);
      return null;
    }
  }, []);

  const userAvatar = useMemo(() => {
    if (isPending) {
      return <Skeleton className="h-24 w-24 rounded-full" />;
    }
    return (
      <img
        alt="User avatar"
        src={previewAvatar || session?.user?.image || 'https://www.ruslan.in/grad.png'}
        className="h-24 w-24 rounded-full border outline-neutral-300 object-fill"
      />
    );
  }, [isPending, session?.user?.image, previewAvatar]);

  return (
    <div className="w-full bg-white rounded-xl dark:bg-black">
      <div className="flex justify-between items-center pt-4">
        <div className="flex items-center w-full gap-2 border-dashed border-neutral-300 dark:border-neutral-700">
          <h1 className="text-xl sm:text-2xl font-semibold tracking-tighter px-4.5 pt-0.5 text-neutral-900 dark:text-neutral-100">
            Settings
          </h1>
        </div>
      </div>

      <div className="w-full p-4">
        <Tabs defaultValue="personal">
          <TabsList className="grid w-fit grid-cols-2 border rounded-[15px] ">
            <TabsTrigger
              value="personal"
              className="font-normal rounded-xl cursor-pointer outline-offset-[-0.75px] data-[state=active]:outline-[0.75px] outline-neutral-300 dark:outline-neutral-800"
            >
              <span className="flex items-center gap-2 tracking-tight">
                <User2 className="h-4 w-4" />
                Personal
              </span>
            </TabsTrigger>
            <TabsTrigger
              value="security"
              className="font-normal rounded-xl cursor-pointer outline-offset-[-0.75px] data-[state=active]:outline-[0.75px] outline-neutral-300 dark:outline-neutral-800"
            >
              <span className="flex items-center gap-2">
                <Lock className="h-4 w-4" />
                Security
              </span>
            </TabsTrigger>
          </TabsList>

          <TabsContent value="personal" className="mt-4 space-y-6">
            <Card className="rounded-xl">
              <CardHeader className="p-5 border-b border-neutral-200 dark:border-neutral-800 rounded-t-xl bg-neutral-50 dark:bg-neutral-900">
                <div>
                  <h2 className="text-lg font-medium tracking-[-0.04em]">Personal Information</h2>
                  <p className="text-sm text-muted-foreground mt-1">
                    Change your personal information that's used across the app.
                  </p>
                </div>
              </CardHeader>
              <CardContent className="p-5 space-y-5">
                <div className="space-y-4">
                  <div className="flex items-center gap-6">
                    {userAvatar}
                    <div>
                      <input
                        type="file"
                        ref={fileInputRef}
                        className="hidden"
                        accept="image/jpeg,image/png,image/gif"
                        onChange={handleAvatarChange}
                      />
                      <Button variant="outline" className="text-sm" onClick={handleAvatarClick}>
                        Change Avatar
                      </Button>
                      <p className="text-xs text-muted-foreground mt-2">
                        JPG, GIF or PNG. 1MB max.
                      </p>
                    </div>
                  </div>

                  <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
                    <FormInput
                      label="First Name"
                      id="first-name"
                      name="firstName"
                      value={formData.firstName}
                      onChange={handleInputChange}
                      isPending={isPending}
                    />

                    <FormInput
                      label="Last Name"
                      id="last-name"
                      name="lastName"
                      value={formData.lastName}
                      onChange={handleInputChange}
                      isPending={isPending}
                    />

                    {isPending ? (
                      <div className="space-y-2">
                        <Label className="text-sm font-medium">Target Language</Label>
                        <Skeleton className="h-10 w-full rounded-xl mt-1" />
                      </div>
                    ) : (
                      <TargetLanguageSelector
                        label="Target Language"
                        value={formData.targetLanguage}
                        onChange={value => handleInputChange('targetLanguage', value)}
                      />
                    )}

                    {isPending ? (
                      <div className="space-y-2">
                        <Label className="text-sm font-medium">Learning City</Label>
                        <Skeleton className="h-10 w-full rounded-xl mt-1" />
                      </div>
                    ) : (
                      <CitySelector
                        label="Learning City"
                        value={formData.learningCity}
                        onChange={value => handleInputChange('learningCity', value)}
                        optional={false}
                        placeholder="Select a city"
                      />
                    )}

                    {isPending ? (
                      <div className="space-y-2">
                        <Label className="text-sm font-medium">Native Language</Label>
                        <Skeleton className="h-10 w-full rounded-xl mt-1" />
                      </div>
                    ) : (
                      <LanguageSelector
                        label="Native Language"
                        value={formData.nativeLanguage}
                        onChange={value => handleInputChange('nativeLanguage', value)}
                        placeholder="Select your native language"
                        showEnglishName={true}
                      />
                    )}

                    {isPending ? (
                      <div className="space-y-2">
                        <Label className="text-sm font-medium">Native Language Country</Label>
                        <Skeleton className="h-10 w-full rounded-xl mt-1" />
                      </div>
                    ) : (
                      <CountrySelector
                        label="Native Language Country"
                        value={formData.nativeLanguageCountry}
                        onChange={value => handleInputChange('nativeLanguageCountry', value)}
                        placeholder="Where you grew up learning your native language"
                      />
                    )}

                    {isPending ? (
                      <div className="space-y-2">
                        <Label className="text-sm font-medium">Birthday</Label>
                        <Skeleton className="h-10 w-full rounded-xl mt-1" />
                      </div>
                    ) : (
                      <DatePickerComponent
                        label="Birthday"
                        optional={true}
                        value={safeParseBirthday(formData.birthday)}
                        onChange={value =>
                          handleInputChange('birthday', value ? value.toString() : '')
                        }
                      />
                    )}

                    <div className="">
                      {isPending ? (
                        <div className="space-y-2">
                          <Label className="text-sm font-medium">Experience Level</Label>
                          <Skeleton className="h-10 w-full rounded-xl mt-1" />
                        </div>
                      ) : (
                        <ExperienceLevelSelector
                          label="Experience Level"
                          value={formData.experienceLevel}
                          onChange={value => handleInputChange('experienceLevel', value)}
                          placeholder="Select your experience level"
                        />
                      )}
                    </div>

                    <div className="sm:col-span-2">
                      <ChallengingWordsSelector
                        label="Challenging Words"
                        value={formData.challengingWords}
                        onChange={value => handleInputChange('challengingWords', value)}
                        isPending={isPending}
                        placeholder="Words you find difficult or confusing (e.g., 'thorough', 'entrepreneur', 'rural')"
                        maxLength={500}
                        className=""
                      />
                    </div>
                  </div>
                </div>
              </CardContent>
              <CardFooter className="bg-neutral-50 dark:bg-neutral-900 rounded-b-xl border-t border-neutral-200 dark:border-neutral-800 p-4">
                <Button size="settings" onClick={saveInformation} disabled={isSaving || isPending}>
                  {isSaving ? 'Saving...' : 'Save Information'}
                </Button>
              </CardFooter>
            </Card>

            <AppearanceSection theme={theme} setTheme={setTheme} />
          </TabsContent>

          <TabsContent value="security" className="mt-4 space-y-6">
            <SecuritySection />
          </TabsContent>
        </Tabs>
      </div>
    </div>
  );
}



================================================
FILE: app/onboarding/layout.js
================================================
'use client';

import GridBackground from '@/components/ui/onboarding/grid-background';
import { Toaster } from '@/components/ui/toaster';
import { OnboardingProvider } from '@/components/ui/onboarding/onboarding-provider';

export default function OnboardingLayout({ children }) {
  return (
    <OnboardingProvider>
      <div className="w-full min-h-screen bg-white dark:bg-neutral-950/[0.99] tracking-[-0.015em] relative overflow-hidden flex items-center justify-center">
        <div className="absolute top-0 z-[0] h-screen w-screen bg-[radial-gradient(100%_50%_at_50%_0%,rgba(0,163,255,0.7)_0,rgba(0,163,255,0.7)_50%,rgba(0,163,255,0)_100%)] mix-blend-color pointer-events-none"></div>
        <div className="absolute top-0 z-[0] h-screen w-screen bg-[radial-gradient(100%_50%_at_50%_100%,rgba(0,163,255,0.7)_0,rgba(0,163,255,0.7)_50%,rgba(0,163,255,0)_100%)] mix-blend-color pointer-events-none"></div>

        <div className="absolute bottom-auto z-[11] left-auto right-0 top-0 h-[500px] w-[500px] translate-x-[50%] translate-y-[30%] rounded-full bg-[rgba(75,168,255,0.63)] opacity-25 blur-[80px] transform-gpu xl:block hidden"></div>
        <div className="absolute top-auto z-[11] left-auto right-0 bottom-0 h-[500px] w-[500px] translate-x-[50%] -translate-y-[30%] rounded-full bg-[#0055ff82] opacity-25 blur-[80px] transform-gpu xl:block hidden"></div>

        <div className="absolute bottom-auto z-[11] right-auto left-0 top-0 h-[500px] w-[500px] -translate-x-[50%] translate-y-[30%] rounded-full bg-[rgba(75,168,255,0.63)] opacity-25 blur-[80px] transform-gpu xl:block hidden"></div>
        <div className="absolute top-auto z-[11] right-auto left-0 bottom-0 h-[500px] w-[500px] -translate-x-[50%] -translate-y-[30%] rounded-full bg-[#0055ff82] opacity-25 blur-[80px] transform-gpu xl:block hidden"></div>

        {/* <div
          className="absolute inset-0 bg-repeat bg-center mix-blend-multiply opacity-35 z-30 pointer-events-none scale-200"
          style={{ backgroundImage: "url('/grain.png')" }}
        ></div> */}

        <div className="absolute top-0 left-0 w-full h-[5vh] overflow-hidden flex items-end justify-center bg-neutral-50">
          <div className="flex h-full items-end gap-2">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`top-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800"
                ></div>
              ))}
          </div>
        </div>

        <div className="flex items-center justify-center my-12 relative w-full h-[90vh] bg-neutral-50/20 backdrop-blur-md border-y border-neutral-200 transform-gpu dark:border-neutral-800 z-20">
          {children}
        </div>

        <div className="absolute bottom-0 left-0 w-full h-[5vh] overflow-hidden flex items-start justify-center bg-neutral-50">
          <div className="flex h-full items-start gap-2">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>

        <Toaster />
      </div>
    </OnboardingProvider>
  );
}



================================================
FILE: app/onboarding/page.jsx
================================================
'use client';

import { useRouter } from 'next/navigation';

export default function OnboardingRedirect() {
  const router = useRouter();

  if (typeof window !== 'undefined') {
    router.replace('/onboarding/welcome');
  }
  return null;
}



================================================
FILE: app/onboarding/getting-to-know-you/page.jsx
================================================
'use client';

import { useOnboarding } from '@/components/ui/onboarding/onboarding-provider';
import { useRouter } from 'next/navigation';
import { Button } from '@/components/ui/base/button';
import KoelBirdRounded from '@/components/ui/base/koel-bird-rounded';
import { useState } from 'react';
import DatePickerComponent from '@/components/ui/base/date';
import { parseDate } from '@internationalized/date';

// Import shared form components
import LanguageSelector from '@/components/forms/language-selector';
import CountrySelector from '@/components/forms/country-selector';

export default function GettingToKnowYouPage() {
  const { onboardingData, updateOnboardingData } = useOnboarding();
  const router = useRouter();
  const [isLoading, setIsLoading] = useState(false);

  const safeParseBirthday = dateString => {
    if (!dateString || typeof dateString !== 'string') return null;
    try {
      // Ensure the string is in YYYY-MM-DD format
      if (dateString.match(/^\d{4}-\d{2}-\d{2}$/)) {
        return parseDate(dateString);
      }
      return null;
    } catch (error) {
      console.warn('Failed to parse birthday:', dateString, error);
      return null;
    }
  };

  const handleNext = () => {
    setIsLoading(true);
    router.push('/onboarding/language-goals');
  };

  const handleBack = () => {
    router.push('/onboarding/welcome');
  };

  const isNextDisabled = !onboardingData.nativeLanguage || !onboardingData.nativeLanguageCountry;

  return (
    <div className="flex min-h-screen flex-col items-center justify-center w-full">
      <div className="flex flex-col items-center justify-center p-8 text-center mx-4  z-40 max-w-2xl w-full ">
        <KoelBirdRounded className="w-[70px] mb-3 h-fit mx-auto" />

        <h3 className="text-2xl font-semibold tracking-tighter mb-2 z-10">Getting to Know You</h3>
        <p className="text-md text-neutral-500 dark:text-neutral-400 mb-10 max-w-md text-balance z-10">
          Please share a few details to help us personalize your experience
        </p>

        <div className="space-y-6 w-full">
          <div className="space-y-4">
            <LanguageSelector
              label="What's your native language?"
              value={onboardingData.nativeLanguage}
              onChange={value => updateOnboardingData('nativeLanguage', value)}
              required={true}
              placeholder="Select your native language"
              showEnglishName={false}
            />

            <CountrySelector
              label="Where did you grow up learning your native language?"
              value={onboardingData.nativeLanguageCountry}
              onChange={value => updateOnboardingData('nativeLanguageCountry', value)}
              required={true}
              placeholder="Select country"
            />

            <DatePickerComponent
              label="What's your birthday?"
              optional={true}
              value={safeParseBirthday(onboardingData.birthday)}
              onChange={value => updateOnboardingData('birthday', value ? value.toString() : '')}
            />
          </div>
        </div>

        <div className="flex gap-3 mt-12 w-full justify-between">
          <Button variant="outline" onClick={handleBack} className="flex-1 gap-1">
            <svg
              width="16"
              height="16"
              viewBox="0 0 24 24"
              fill="none"
              className="rotate-90"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d="M12 5V19M12 19L19 12M12 19L5 12"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
            </svg>
            Back
          </Button>
          <p className="text-sm text-neutral-500 dark:text-neutral-400 mt-2 text-center px-2">
            Step 1 of 3
          </p>
          <Button
            onClick={handleNext}
            disabled={isNextDisabled || isLoading}
            className="flex items-center flex-1 gap-1"
          >
            {isLoading ? (
              <>
                <div className="w-4 h-4 border-2 border-current border-t-transparent rounded-full animate-spin"></div>
                Loading...
              </>
            ) : (
              <>
                Continue
                <svg
                  width="16"
                  height="16"
                  viewBox="0 0 24 24"
                  fill="none"
                  className="-rotate-90"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M12 5V19M12 19L19 12M12 19L5 12"
                    stroke="currentColor"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  />
                </svg>
              </>
            )}
          </Button>
        </div>
      </div>
    </div>
  );
}



================================================
FILE: app/onboarding/language-goals/page.jsx
================================================
'use client';

import { useOnboarding } from '@/components/ui/onboarding/onboarding-provider';
import { useRouter } from 'next/navigation';
import { Label } from '@/components/ui/base/label';
import { Button } from '@/components/ui/base/button';
import { Textarea } from '@/components/ui/base/textarea';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/base/select';
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '@/components/ui/base/command';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/base/popover';
import { CheckIcon, ChevronDownIcon } from 'lucide-react';
import KoelBirdRounded from '@/components/ui/base/koel-bird-rounded';
import {
  DateField,
  DateInput,
  DateSegment,
  TimeField,
  dateInputStyle,
} from '@/components/ui/datefield-rac';
import { ArrowUpRight } from 'lucide-react';
import { useState, useEffect, useId, useMemo } from 'react';
import TargetLanguageSelector from '@/components/forms/target-language-selector';
import ExperienceLevelSelector from '@/components/forms/experience-level-selector';
import ChallengingWordsSelector from '@/components/forms/challenging-words-selector';
import CitySelector from '@/components/forms/city-selector';

export default function LanguageGoalsPage() {
  const { onboardingData, updateOnboardingData } = useOnboarding();
  const router = useRouter();
  const [cities, setCities] = useState([]);
  const [citiesLoading, setCitiesLoading] = useState(true);
  const [citiesError, setCitiesError] = useState(false);
  const [cityOpen, setCityOpen] = useState(false);
  const [citySearchTerm, setCitySearchTerm] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const citySelectId = useId();

  useEffect(() => {
    const loadCities = async () => {
      try {
        setCitiesLoading(true);
        setCitiesError(false);
        const response = await fetch(
          '/world_cities_15000_(including_all_states_and_counties).json',
        );
        if (!response.ok) throw new Error('Failed to load cities');
        const citiesData = await response.json();
        setCities(citiesData);
      } catch (error) {
        console.error('Failed to load cities:', error);
        setCitiesError(true);
      } finally {
        setCitiesLoading(false);
      }
    };

    loadCities();
  }, []);

  const handleNext = () => {
    setIsLoading(true);
    router.push('/onboarding/speech-assessment');
  };

  const handleBack = () => {
    router.push('/onboarding/getting-to-know-you');
  };

  const isNextDisabled = !onboardingData.experienceLevel;

  const languages = [
    { value: 'english', flag: '🇺🇸', name: 'English' },
    { value: 'spanish', flag: '🇪🇸', name: 'Spanish (Coming Soon)', disabled: true },
    { value: 'german', flag: '🇩🇪', name: 'German (Coming Soon)', disabled: true },
    { value: 'russian', flag: '🇷🇺', name: 'Russian (Coming Soon)', disabled: true },
  ];

  const selectedLanguage = languages.find(lang => lang.value === onboardingData.targetLanguage);

  const selectedCity = cities.find(city => {
    if (typeof onboardingData.learningCity === 'string') {
      return city.name === onboardingData.learningCity;
    }
    if (onboardingData.learningCity?.name) {
      return (
        city.name === onboardingData.learningCity.name &&
        city.state === onboardingData.learningCity.state &&
        city.country === onboardingData.learningCity.country
      );
    }
    return false;
  });

  const formatCountry = countryCode => {
    const regionNames = new Intl.DisplayNames(['en'], { type: 'region' });
    return regionNames.of(countryCode.toUpperCase());
  };

  const formatCityDisplay = city => {
    let display = city.name;
    if (city.state && city.state !== city.name) {
      display += `, ${city.state}`;
    }
    if (city.country) {
      display += `, ${formatCountry(city.country)}`;
    }
    return display;
  };

  const filteredCities = useMemo(() => {
    if (!citySearchTerm || citySearchTerm.length < 2) {
      return [];
    }

    const searchLower = citySearchTerm.toLowerCase();
    const results = cities
      .filter(city => {
        const cityName = city.name.toLowerCase();
        const stateName = city.state ? city.state.toLowerCase() : '';
        const countryCode = city.country ? city.country.toLowerCase() : '';

        return (
          cityName.includes(searchLower) ||
          stateName.includes(searchLower) ||
          countryCode.includes(searchLower)
        );
      })
      .sort((a, b) => {
        const aName = a.name.toLowerCase();
        const bName = b.name.toLowerCase();

        const aStartsWith = aName.startsWith(searchLower);
        const bStartsWith = bName.startsWith(searchLower);

        if (aStartsWith && !bStartsWith) return -1;
        if (!aStartsWith && bStartsWith) return 1;

        return aName.localeCompare(bName);
      })
      .slice(0, 30);

    return results;
  }, [cities, citySearchTerm]);

  return (
    <div className="flex min-h-screen flex-col items-center justify-center w-full">
      <div className="flex flex-col items-center justify-center p-8 text-center mx-4 rounded-xl z-40 bg-white/40 border-neutral-200 dark:border-neutral-800 max-w-2xl w-full">
        <KoelBirdRounded className="w-[70px] mb-3 h-fit mx-auto" />

        <h3 className="text-2xl font-semibold tracking-tighter mb-2 z-10">Your Language Goals</h3>
        <p className="text-md text-neutral-500 dark:text-neutral-400 mb-10 max-w-md text-balance z-10">
          Help us understand your goals so we can support your learning journey
        </p>

        <div className="space-y-6 w-full">
          <div className="space-y-4">
            <TargetLanguageSelector
              label="What language do you want to learn?"
              value={onboardingData.targetLanguage}
              onChange={value => updateOnboardingData('targetLanguage', value)}
              required={true}
              placeholder="Select your target language"
            />

            <ExperienceLevelSelector
              label="How many years have you studied this language?"
              value={onboardingData.experienceLevel}
              onChange={value => updateOnboardingData('experienceLevel', value)}
              required={true}
              placeholder="Select your experience level"
            />

            <CitySelector
              label="Where did you spend the longest time learning this language?"
              value={onboardingData.learningCity}
              onChange={value => updateOnboardingData('learningCity', value)}
              required={false}
              placeholder="Select a city"
            />

            <ChallengingWordsSelector
              label="Challenging Words"
              value={onboardingData.challengingWords}
              onChange={value => updateOnboardingData('challengingWords', value)}
              optional={true}
              placeholder="Are there any specific words you find difficult or confusing? (for example, 'thorough', 'entrepreneur', 'rural')"
              maxLength={500}
            />
          </div>
        </div>

        <div className="flex gap-3 mt-8 w-full justify-between">
          <Button variant="outline" onClick={handleBack} className="flex-1 gap-1">
            <svg
              width="16"
              height="16"
              viewBox="0 0 24 24"
              fill="none"
              className="rotate-90"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d="M12 5V19M12 19L19 12M12 19L5 12"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
            </svg>
            Back
          </Button>
          <p className="text-sm text-neutral-500 dark:text-neutral-400 mt-2 text-center px-2">
            Step 2 of 3
          </p>
          <Button
            onClick={handleNext}
            disabled={isNextDisabled || isLoading}
            className="flex items-center flex-1 gap-1"
          >
            {isLoading ? (
              <>
                <div className="w-4 h-4 border-2 border-current border-t-transparent rounded-full animate-spin"></div>
                Loading...
              </>
            ) : (
              <>
                Continue
                <svg
                  width="16"
                  height="16"
                  viewBox="0 0 24 24"
                  fill="none"
                  className="-rotate-90"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M12 5V19M12 19L19 12M12 19L5 12"
                    stroke="currentColor"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  />
                </svg>
              </>
            )}
          </Button>
        </div>
      </div>
    </div>
  );
}



================================================
FILE: app/onboarding/speech-assessment/page.jsx
================================================
'use client';

import { useOnboarding } from '@/components/ui/onboarding/onboarding-provider';
import { useRouter } from 'next/navigation';
import { Label } from '@/components/ui/base/label';
import { Button } from '@/components/ui/base/button';
import KoelBirdRounded from '@/components/ui/base/koel-bird-rounded';
import { Mic, MicOff, Play, Pause, ArrowRight, ArrowLeft, Trash } from 'lucide-react';
import { useState, useRef, useEffect } from 'react';

const phrases = [
  'Thieves who wore warm fleecy woolens blew strong winds past ragged flags, robbed friends who deserved jail, and sold fifty bonds at the booth counter.',
  'They shared chunks of a stale cheese burger while the girl watched with fright from the lodge.',
];

export default function SpeechAssessmentPage() {
  const { onboardingData, updateOnboardingData, completeOnboarding, isCompleting } =
    useOnboarding();
  const router = useRouter();
  const [currentPhrase, setCurrentPhrase] = useState(0);
  const [isRecording, setIsRecording] = useState(false);
  const [isPlaying, setIsPlaying] = useState(false);
  const [recordings, setRecordings] = useState([null, null]);
  const [audioBlobs, setAudioBlobs] = useState([null, null]);
  const [audioDataNumbers, setAudioDataNumbers] = useState([null, null]);
  const [isPlayingFromNumbers, setIsPlayingFromNumbers] = useState(false);
  const mediaRecorderRef = useRef(null);
  const audioContextRef = useRef(null);
  const streamRef = useRef(null);
  const audioRef = useRef(null);
  const analyzerRef = useRef(null);
  const wordIndexRef = useRef(0);
  const currentPhraseRef = useRef(0);

  const phraseWords = phrases.map(phrase => phrase.split(' '));

  // Keep refs in sync with state
  useEffect(() => {
    currentPhraseRef.current = currentPhrase;
  }, [currentPhrase]);

  useEffect(() => {
    return () => {
      if (streamRef.current) {
        streamRef.current.getTracks().forEach(track => track.stop());
      }
      if (audioContextRef.current && audioContextRef.current.state !== 'closed') {
        audioContextRef.current.close();
      }
    };
  }, []);

  const convertAudioToNumbers = async audioBlob => {
    try {
      if (!audioContextRef.current) {
        audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
      }

      const audioContext = audioContextRef.current;

      const arrayBuffer = await audioBlob.arrayBuffer();

      const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);

      const channelData = audioBuffer.getChannelData(0);

      const audioArray = Array.from(channelData);

      return {
        audioData: audioArray,
        sampleRate: audioBuffer.sampleRate,
        duration: audioBuffer.duration,
        numberOfChannels: audioBuffer.numberOfChannels,
        length: audioArray.length,
      };
    } catch (error) {
      console.error('Error converting audio to numbers:', error);
      return null;
    }
  };

  const playAudioFromNumbers = async (audioData, sampleRate) => {
    try {
      if (!audioContextRef.current) {
        audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
      }

      const audioContext = audioContextRef.current;

      const audioBuffer = audioContext.createBuffer(1, audioData.length, sampleRate);
      const channelData = audioBuffer.getChannelData(0);

      for (let i = 0; i < audioData.length; i++) {
        channelData[i] = audioData[i];
      }

      const source = audioContext.createBufferSource();
      source.buffer = audioBuffer;
      source.connect(audioContext.destination);

      setIsPlayingFromNumbers(true);
      source.start();

      source.onended = () => {
        setIsPlayingFromNumbers(false);
      };
    } catch (error) {
      console.error('Error playing audio from numbers:', error);
      setIsPlayingFromNumbers(false);
    }
  };

  const startRecording = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        audio: {
          echoCancellation: true,
          noiseSuppression: true,
          autoGainControl: true,
          sampleRate: 44100,
        },
      });

      streamRef.current = stream;

      const mediaRecorder = new MediaRecorder(stream, {
        mimeType: 'audio/webm;codecs=opus',
      });

      mediaRecorderRef.current = mediaRecorder;

      const chunks = [];

      mediaRecorder.ondataavailable = event => {
        if (event.data.size > 0) {
          chunks.push(event.data);
        }
      };

      mediaRecorder.onstop = async () => {
        const audioBlob = new Blob(chunks, { type: 'audio/webm;codecs=opus' });
        const audioUrl = URL.createObjectURL(audioBlob);

        const newRecordings = [...recordings];
        const newAudioBlobs = [...audioBlobs];
        newRecordings[currentPhrase] = audioUrl;
        newAudioBlobs[currentPhrase] = audioBlob;
        setRecordings(newRecordings);
        setAudioBlobs(newAudioBlobs);

        const audioData = await convertAudioToNumbers(audioBlob);
        if (audioData) {
          const newAudioDataNumbers = [...audioDataNumbers];
          newAudioDataNumbers[currentPhrase] = audioData;
          setAudioDataNumbers(newAudioDataNumbers);

          console.log(`Speech Assessment - Phrase ${currentPhrase + 1} Audio Data:`, {
            phraseIndex: currentPhrase,
            phraseText: phrases[currentPhrase],
            audioMetadata: {
              sampleRate: audioData.sampleRate,
              duration: audioData.duration,
              numberOfChannels: audioData.numberOfChannels,
              dataLength: audioData.length,
            },
            audioPreview: audioData.audioData.slice(0, 100),
            speechAssessmentData: {
              userId: 'user-id-placeholder',
              phraseIndex: currentPhrase,
              audioData: audioData.audioData,
              sampleRate: audioData.sampleRate,
              duration: audioData.duration,
              timestamp: new Date().toISOString(),
            },
          });
        }

        if (streamRef.current) {
          streamRef.current.getTracks().forEach(track => track.stop());
          streamRef.current = null;
        }
      };

      mediaRecorder.start();
      setIsRecording(true);
    } catch (error) {
      console.error('Error starting recording:', error);
      alert('Could not access microphone. Please check permissions.');
    }
  };

  const stopRecording = () => {
    if (mediaRecorderRef.current && mediaRecorderRef.current.state === 'recording') {
      mediaRecorderRef.current.stop();
      setIsRecording(false);
    }
  };

  const playRecording = () => {
    const audioUrl = recordings[currentPhrase];
    if (audioUrl && audioRef.current) {
      audioRef.current.src = audioUrl;
      audioRef.current.play();
      setIsPlaying(true);
    }
  };

  const pauseRecording = () => {
    if (audioRef.current) {
      audioRef.current.pause();
      setIsPlaying(false);
    }
  };

  const resetRecording = () => {
    const newRecordings = [...recordings];
    const newAudioBlobs = [...audioBlobs];
    const newAudioDataNumbers = [...audioDataNumbers];

    newRecordings[currentPhrase] = null;
    newAudioBlobs[currentPhrase] = null;
    newAudioDataNumbers[currentPhrase] = null;

    setRecordings(newRecordings);
    setAudioBlobs(newAudioBlobs);
    setAudioDataNumbers(newAudioDataNumbers);

    if (audioRef.current) {
      audioRef.current.pause();
      audioRef.current.currentTime = 0;
    }
    setIsPlaying(false);
    setIsPlayingFromNumbers(false);
    wordIndexRef.current = 0;
  };

  const handleNext = () => {
    updateOnboardingData('speechAssessment', {
      recordings: audioBlobs.filter(blob => blob !== null),
      completedPhrases: recordings.filter(recording => recording !== null).length,
      timestamp: new Date().toISOString(),
    });

    completeOnboarding();
  };

  const handleBack = () => {
    router.push('/onboarding/language-goals');
  };

  const allRecorded = recordings.every(recording => recording !== null);

  return (
    <div className="flex min-h-screen flex-col items-center justify-center w-full">
      <div className="flex flex-col items-center justify-center p-8 text-center mx-4 rounded-xl z-40 bg-white/40 border-neutral-200 dark:border-neutral-800 max-w-2xl w-full">
        <KoelBirdRounded className="w-[70px] mb-3 h-fit mx-auto" />

        <h3 className="text-2xl font-semibold tracking-tighter mb-2 z-10">Speech Assessment</h3>
        <p className="text-md text-neutral-500 dark:text-neutral-400 mb-6 max-w-md text-balance z-10">
          Record yourself reading these phrases to help us understand your speech patterns
        </p>

        <div className="flex gap-2 mb-6">
          {phrases.map((_, index) => (
            <button
              key={index}
              onClick={() => {
                if (!isRecording) {
                  setCurrentPhrase(index);
                  wordIndexRef.current = 0;
                }
              }}
              disabled={isRecording}
              className={`w-8 h-8 rounded-full border-2 flex items-center justify-center text-sm font-medium transition-colors ${
                recordings[index]
                  ? 'border-emerald-600 bg-emerald-600 text-white'
                  : index === currentPhrase
                    ? 'border-sky-700 bg-sky-700 text-white'
                    : isRecording
                      ? 'border-neutral-200 text-neutral-300 cursor-not-allowed'
                      : 'border-neutral-300 text-neutral-500 hover:border-neutral-400'
              }`}
            >
              {index + 1}
            </button>
          ))}
        </div>

        <div className="space-y-6 w-full">
          <div className="space-y-4">
            <div className="space-y-3 text-left">
              <Label className="text-lg font-medium tracking-tight">
                Phrase {currentPhrase + 1} of {phrases.length}
              </Label>
              <div
                className={`p-4 rounded-2xl mt-2 w-full overflow-hidden transition-colors duration-300 ${
                  recordings[currentPhrase]
                    ? 'bg-emerald-50 dark:bg-emerald-900/20 border-emerald-500 dark:border-emerald-700 border-2'
                    : 'dark:bg-neutral-800 border'
                }`}
              >
                <p
                  className={`text-xl leading-relaxed break-words whitespace-normal tracking-tight transition-colors duration-300 ${
                    recordings[currentPhrase]
                      ? 'text-emerald-700 dark:text-emerald-300'
                      : 'text-neutral-700 dark:text-neutral-300'
                  }`}
                >
                  {phraseWords[currentPhrase].map((word, index) => (
                    <>
                      {index > 0 && ' '}
                      <span key={index} className={``}>
                        {word}
                      </span>
                    </>
                  ))}
                </p>
              </div>
            </div>

            <div className="flex flex-col items-center gap-4">
              <div className="flex gap-3 justify-between w-full">
                {!recordings[currentPhrase] ? (
                  <Button
                    onClick={isRecording ? stopRecording : startRecording}
                    className={`flex items-center gap-2 ${
                      isRecording ? 'bg-red-600 hover:bg-red-700 text-white' : ' text-white'
                    }`}
                  >
                    {isRecording ? (
                      <>
                        <MicOff className="w-4 h-4" />
                        Stop Recording
                      </>
                    ) : (
                      <>
                        <Mic className="w-4 h-4" />
                        Start Recording
                      </>
                    )}
                  </Button>
                ) : (
                  <div className="flex gap-2">
                    <Button
                      onClick={isPlaying ? pauseRecording : playRecording}
                      variant="outline"
                      className="flex items-center gap-2"
                    >
                      {isPlaying ? (
                        <>
                          <Pause className="w-4 h-4" />
                          Pause
                        </>
                      ) : (
                        <>
                          <Play className="w-4 h-4" />
                          Play
                        </>
                      )}
                    </Button>
                    <Button
                      onClick={resetRecording}
                      variant="outline"
                      className="flex items-center gap-2"
                    >
                      <Trash className="w-4 h-4" />
                      Reset
                    </Button>
                  </div>
                )}
                {phrases.length > 1 && (
                  <div className="flex gap-2">
                    <Button
                      onClick={() => {
                        if (!isRecording) {
                          const newPhraseIndex = Math.max(0, currentPhrase - 1);
                          setCurrentPhrase(newPhraseIndex);
                          wordIndexRef.current = 0;
                        }
                      }}
                      disabled={currentPhrase === 0 || isRecording}
                      variant="outline"
                      className="flex items-center gap-1"
                    >
                      <ArrowLeft className="w-4 h-4" />
                    </Button>
                    <Button
                      onClick={() => {
                        if (!isRecording) {
                          const newPhraseIndex = Math.min(phrases.length - 1, currentPhrase + 1);
                          setCurrentPhrase(newPhraseIndex);
                          wordIndexRef.current = 0;
                        }
                      }}
                      disabled={currentPhrase === phrases.length - 1 || isRecording}
                      variant={recordings[currentPhrase] ? 'default' : 'outline'}
                      className="flex items-center gap-1"
                    >
                      <ArrowRight className="w-4 h-4" />
                    </Button>
                  </div>
                )}
              </div>

              {isRecording && (
                <div className="space-y-2">
                  <div className="flex items-center gap-2 text-red-600">
                    <div className="w-3 h-3 bg-red-600 rounded-full animate-pulse"></div>
                    <span className="text-sm tracking-tight">Recording...</span>
                  </div>
                </div>
              )}

              {recordings[currentPhrase] && !isRecording && (
                <div className="flex items-center gap-2 text-emerald-600">
                  <div className="w-3 h-3 bg-emerald-600 rounded-full"></div>
                  <span className="text-sm tracking-tight">Recording Complete</span>
                </div>
              )}
            </div>

            {/* Developer debuging - Keeping it here for now in case we need it later */}
            {/* {audioDataNumbers[currentPhrase] && (
              <div className="space-y-3 mt-6 p-4 bg-neutral-50 dark:bg-neutral-800 rounded-lg border">
                <div className="flex items-center justify-between">
                  <Label className="text-sm font-medium text-neutral-700 dark:text-neutral-300">
                    🐛 Debug: Audio Numbers
                  </Label>
                  <Button
                    onClick={() =>
                      playAudioFromNumbers(
                        audioDataNumbers[currentPhrase].audioData,
                        audioDataNumbers[currentPhrase].sampleRate,
                      )
                    }
                    disabled={isPlayingFromNumbers}
                    variant="outline"
                    size="sm"
                    className="flex items-center gap-1 text-xs"
                  >
                    {isPlayingFromNumbers ? (
                      <>
                        <div className="w-2 h-2 bg-blue-500 rounded-full animate-pulse"></div>
                        Playing...
                      </>
                    ) : (
                      <>
                        <Play className="w-3 h-3" />
                        Play from Numbers
                      </>
                    )}
                  </Button>
                </div>

                <div className="space-y-2">
                  <div className="text-xs text-neutral-600 dark:text-neutral-400">
                    <span className="font-medium">Sample Rate:</span>{' '}
                    {audioDataNumbers[currentPhrase].sampleRate}Hz |
                    <span className="font-medium"> Duration:</span>{' '}
                    {audioDataNumbers[currentPhrase].duration.toFixed(2)}s |
                    <span className="font-medium"> Length:</span>{' '}
                    {audioDataNumbers[currentPhrase].length.toLocaleString()} samples
                  </div>

                  <div className="space-y-1">
                    <div className="text-xs text-neutral-600 dark:text-neutral-400 font-medium">
                      First 20 numbers:
                    </div>
                    <div className="bg-white dark:bg-neutral-900 p-2 rounded text-xs font-mono border max-h-20 overflow-y-auto">
                      [
                      {audioDataNumbers[currentPhrase].audioData
                        .slice(0, 20)
                        .map(n => n.toFixed(6))
                        .join(', ')}
                      ...]
                    </div>
                  </div>

                  <div className="space-y-1">
                    <div className="text-xs text-neutral-600 dark:text-neutral-400 font-medium">
                      Statistics:
                    </div>
                    <div className="text-xs text-neutral-600 dark:text-neutral-400">
                      Min:{' '}
                      {audioDataNumbers[currentPhrase].audioData
                        .reduce((min, val) => Math.min(min, val), Infinity)
                        .toFixed(6)}{' '}
                      | Max:{' '}
                      {audioDataNumbers[currentPhrase].audioData
                        .reduce((max, val) => Math.max(max, val), -Infinity)
                        .toFixed(6)}{' '}
                      | Avg:{' '}
                      {(
                        audioDataNumbers[currentPhrase].audioData.reduce((a, b) => a + b, 0) /
                        audioDataNumbers[currentPhrase].audioData.length
                      ).toFixed(6)}
                    </div>
                  </div>
                </div>
              </div>
            )} */}
          </div>
        </div>

        <div className="flex gap-3 mt-8 w-full justify-between">
          <Button variant="outline" onClick={handleBack} className="flex-1 gap-1">
            <svg
              width="16"
              height="16"
              viewBox="0 0 24 24"
              fill="none"
              className="rotate-90"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d="M12 5V19M12 19L19 12M12 19L5 12"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
            </svg>
            Back
          </Button>
          <p className="text-sm text-neutral-500 dark:text-neutral-400 mt-2 text-center px-2">
            Step 3 of 3
          </p>
          <Button
            onClick={handleNext}
            disabled={!allRecorded || isCompleting}
            className="flex items-center flex-1 gap-1"
          >
            {isCompleting ? (
              <>
                <div className="w-4 h-4 border-2 border-current border-t-transparent rounded-full animate-spin"></div>
                Completing...
              </>
            ) : (
              <>
                Complete Setup
                <svg
                  width="16"
                  height="16"
                  viewBox="0 0 24 24"
                  fill="none"
                  className="-rotate-90"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M12 5V19M12 19L19 12M12 19L5 12"
                    stroke="currentColor"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  />
                </svg>
              </>
            )}
          </Button>
        </div>

        <audio ref={audioRef} onEnded={() => setIsPlaying(false)} style={{ display: 'none' }} />
      </div>
    </div>
  );
}



================================================
FILE: app/onboarding/welcome/page.jsx
================================================
'use client';

import { Button } from '@/components/ui/base/button';
import KoelBirdRounded from '@/components/ui/base/koel-bird-rounded';
import { ArrowRight } from 'lucide-react';
import { useRouter } from 'next/navigation';
import { useState } from 'react';

// Progress Indicator Component
const ProgressBubbles = ({ currentStep, totalSteps }) => {
  const steps = Array.from({ length: totalSteps }, (_, i) => i + 1);

  return (
    <div className="flex items-center justify-center gap-3 mb-8">
      {steps.map(step => (
        <div
          key={step}
          className={`w-2 h-2 rounded-full transition-all duration-300 ease-out ${
            step < currentStep
              ? 'bg-sky-600 scale-100'
              : step === currentStep
                ? 'bg-sky-600 scale-125 shadow-lg shadow-sky-600/30'
                : 'bg-neutral-300 dark:bg-neutral-600 scale-100'
          }`}
        />
      ))}
    </div>
  );
};

export default function WelcomePage() {
  const router = useRouter();
  const [isLoading, setIsLoading] = useState(false);

  const handleNext = () => {
    setIsLoading(true);
    router.push('/onboarding/getting-to-know-you');
  };

  return (
    <div className="flex min-h-screen flex-col items-center justify-center overflow-hidden ">
      <div className="flex flex-col items-center justify-center py-8 px-4 text-center mx-4 border-neutral-200 dark:border-neutral-800 z-10  rounded-full">
        <div className="flex items-center tracking-tight w-full justify-between">
          <KoelBirdRounded className="w-[100px] h-fit mx-auto animate-in animate-in-1" />
        </div>

        <h3 className="text-2xl font-semibold tracking-[-0.04em] mb-2 z-10 animate-in animate-in-2">
          Welcome to Koel Labs
        </h3>
        <p className="text-md text-neutral-500 dark:text-neutral-400 mb-4 max-w-md text-balance z-10 animate-in animate-in-3">
          Koel Labs helps you improve your language skills with personalized feedback and practice.
        </p>
        <Button
          variant="outline"
          className="flex items-center gap-2 z-10 animate-in animate-in-4"
          onClick={handleNext}
          disabled={isLoading}
        >
          {isLoading ? (
            <>
              <div className="w-4 h-4 border-2 border-current border-t-transparent rounded-full animate-spin"></div>
              Loading...
            </>
          ) : (
            <>
              Start Learning
              <svg
                width="16"
                height="16"
                viewBox="0 0 24 24"
                fill="none"
                className="-rotate-90"
                xmlns="http://www.w3.org/2000/svg"
              >
                <path
                  d="M12 5V19M12 19L19 12M12 19L5 12"
                  stroke="currentColor"
                  strokeWidth="2"
                  strokeLinecap="round"
                  strokeLinejoin="round"
                />
              </svg>
            </>
          )}
        </Button>
      </div>
    </div>
  );
}



================================================
FILE: app/previews/page.tsx
================================================
'use server';

import Header from '@/components/ui/header';
import CTA from '@/components/sections/cta';
import Footer from '@/components/sections/footer';
import PreviewsHero from '@/app/previews/sections-previews/previews-hero';
import Leaderboard from '@/app/previews/sections-previews/leaderboard';

export default async function PreviewsPage() {
  return (
    <div className="flex-col flex w-screen relative scroll-smooth">
      <div
        data-cursor-opacity="0.3"
        data-cursor-size="240"
        className="z-9999 sticky top-0 mx-auto w-full"
      >
        <Header />
      </div>
      <PreviewsHero />
      <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-t">
        <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
          {Array(500)
            .fill(0)
            .map((_, i) => (
              <div
                key={`bottom-${i}`}
                className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
              ></div>
            ))}
        </div>
      </div>
      <div
        data-cursor-opacity="0.8"
        data-cursor-size="240"
        data-cursor-color="#2A4BCC"
        className="z-0 relative"
      >
        <Leaderboard />
        <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-b">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
      </div>

      <div className="w-full relative">
        <CTA />
      </div>
      <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
        <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
          {Array(500)
            .fill(0)
            .map((_, i) => (
              <div
                key={`bottom-${i}`}
                className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
              ></div>
            ))}
        </div>
      </div>

      <Footer />
    </div>
  );
}



================================================
FILE: app/previews/sections-previews/leaderboard.tsx
================================================
'use client';
import React from 'react';
import Link from 'next/link';
import { ArrowUpRight, ChevronDown, ChevronsUpDown, ChevronUp } from 'lucide-react';

const leaderboard = [
  {
    model: 'Koel Labs XLSR English 01',
    average_per: '20.59%',
    average_fer: '3.31%',
    link: 'https://huggingface.co/KoelLabs/xlsr-english-01',
    submission_date: '2025-09-03',
    koel_labs: true,
  },
  {
    model: 'Facebook Wav2Vec2 53 Espeak',
    average_per: '114.40%',
    average_fer: '7.68%',
    link: 'https://github.com/facebookresearch/fairseq/tree/main/examples/wav2vec#wav2vec-20',
    submission_date: '2025-09-03',
  },
  {
    model: 'Facebook Wav2Vec2 60 Espeak',
    average_per: '116.98%',
    average_fer: '7.96%',
    link: 'https://github.com/facebookresearch/fairseq/tree/main/examples/wav2vec#wav2vec-20',
    submission_date: '2025-09-03',
  },
  {
    model: 'MrRubino XLSR 53 L2-Arctic',
    average_per: '58.83%',
    average_fer: '8.12%',
    link: 'https://doi.org/10.1109/ichi61247.2024.00045',
    submission_date: '2025-09-07',
  },
  {
    model: 'Vitouphy XLSR TIMIT',
    average_per: '59.91%',
    average_fer: '8.55%',
    link: 'https://www.kaggle.com/code/vitouphy/phoneme-recognition-with-wav2vec2',
    submission_date: '2025-09-03',
  },
  {
    model: 'Ginic XLSR 53 Buckeye',
    average_per: '42.12%',
    average_fer: '8.89%',
    link: 'https://github.com/ginic/multipa',
    submission_date: '2025-09-03',
  },
  {
    model: 'Facebook XLSR 53 Phon',
    average_per: '50.01%',
    average_fer: '9.35%',
    link: 'N/A',
    submission_date: '2025-09-07',
  },
  {
    model: 'DahmL XLSR MFA',
    average_per: '122.82%',
    average_fer: '10.05%',
    link: 'N/A',
    submission_date: '2025-09-08',
  },
  {
    model: 'Koel Labs B0',
    average_per: '44.36%',
    average_fer: '10.30%',
    link: 'https://huggingface.co/KoelLabs/xlsr-timit-b0',
    submission_date: '2025-09-03',
    koel_labs: true,
  },
  {
    model: 'Facebook XLSR 53 BABEL',
    average_per: '54.83%',
    average_fer: '10.89%',
    link: 'http://www.lrec-conf.org/lrec1998/midwich.reading.ac.uk/research/speechlab/babel/index.html',
    submission_date: '2025-09-07',
  },
  {
    model: 'Speech31 XLSR English IPA',
    average_per: '117.12%',
    average_fer: '12.37%',
    link: 'N/A',
    submission_date: '2025-09-03',
  },
  {
    model: 'Speech31 Wav2Vec2 TIMIT-IPA3',
    average_per: '68.59%',
    average_fer: '12.64%',
    link: 'N/A',
    submission_date: '2025-09-03',
  },
  {
    model: 'Chihiro Taguchi XLSR japlmthufielta',
    average_per: '73.07%',
    average_fer: '12.89%',
    link: 'N/A',
    submission_date: '2025-09-03',
  },
  {
    model: 'Speech31 WavLM English IPA',
    average_per: '118.56%',
    average_fer: '13.29%',
    link: 'N/A',
    submission_date: '2025-09-03',
  },
  {
    model: 'Snu Nia Wav2Vec2 TIMIT',
    average_per: '141.47%',
    average_fer: '13.46%',
    link: 'N/A',
    submission_date: '2025-09-03',
  },
  {
    model: 'Speech31 TIMIT-IPA2',
    average_per: '141.47%',
    average_fer: '13.46%',
    link: 'N/A',
    submission_date: '2025-09-03',
  },
  {
    model: 'Speech31 Hubert English IPA',
    average_per: '109.03%',
    average_fer: '14.16%',
    link: 'N/A',
    submission_date: '2025-09-04',
  },
  {
    model: 'SNU-SLP Lab XLSR 53 TIMIT',
    average_per: '71.75%',
    average_fer: '14.71%',
    link: 'N/A',
    submission_date: '2025-09-08',
  },
  {
    model: 'Jubliano XLSR International 1.5',
    average_per: '83.61%',
    average_fer: '16.46%',
    link: 'N/A',
    submission_date: '2025-09-03',
  },
  {
    model: 'Vikramanantha Wav2Vec2-base LJSpeech Gruut',
    average_per: '141.09%',
    average_fer: '22.98%',
    link: 'https://huggingface.co/bookbot/wav2vec2-ljspeech-gruut/tree/main',
    submission_date: '2025-09-07',
  },
  {
    model: 'Excalibur12 Wav2Vec2 TIMIT Simplified',
    average_per: '283.05%',
    average_fer: '57.73%',
    link: 'N/A',
    submission_date: '2025-09-07',
  },
  {
    model: 'Excalibur12 Wav2Vec2 lv60 TIMIT',
    average_per: '289.38%',
    average_fer: '59.85%',
    link: 'N/A',
    submission_date: '2025-09-07',
  },
];

function formatDate(date: string) {
  return new Date(date).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
  });
}

function tag(status: string) {
  return (
    <span className="bg-white transition-all inline-flex items-center px-2 w-full py-1.5 border text-sm leading-4 font-medium tracking-tight rounded-xl text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 sm:w-fit flex-row justify-between hover:shadow-sm group">
      {status}
    </span>
  );
}

type SortKey =
  | 'model'
  | 'average_per'
  | 'average_per_fer'
  | 'average_fer'
  | 'link'
  | 'submission_date';
type SortDirection = 'asc' | 'desc';

function SortIndicator({ direction }: { direction: SortDirection | null }) {
  if (!direction)
    return (
      <span className="">
        <ChevronsUpDown className="size-4" />
      </span>
    );
  return direction === 'asc' ? (
    <span className="">
      <ChevronUp className="size-4" />
    </span>
  ) : (
    <span className="">
      <ChevronDown className="size-4" />
    </span>
  );
}

function tagLink(link: string) {
  if (link == 'N/A') {
    return (
      <span className="bg-white text-neutral-500 transition-all inline-flex items-center px-2 w-full py-1.5 border text-sm leading-4 font-medium tracking-tight rounded-xl focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 sm:w-fit flex-row justify-between hover:shadow-sm group">
        N/A
      </span>
    );
  }

  return (
    <a href={link} target="_blank">
      <span className="bg-white transition-all inline-flex items-center px-2 w-full py-1.5 border text-sm leading-4 font-medium tracking-tight rounded-xl text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 sm:w-fit flex-row justify-between hover:shadow-sm group">
        {link == 'N/A' ? 'N/A' : 'Link'}
        <ArrowUpRight className="size-4 -mb-px ml-0.5" />
      </span>
    </a>
  );
}

export default function Leaderboard() {
  const [sortConfig, setSortConfig] = React.useState<{
    key: SortKey;
    direction: SortDirection;
  } | null>(null);

  const requestSort = (key: SortKey) => {
    setSortConfig(prev => {
      if (prev && prev.key === key) {
        return { key, direction: prev.direction === 'asc' ? 'desc' : 'asc' };
      }
      return { key, direction: 'asc' };
    });
  };

  const getDirectionFor = (key: SortKey): SortDirection | null =>
    sortConfig?.key === key ? sortConfig.direction : null;

  const sortedLeaderboard = React.useMemo(() => {
    if (!sortConfig) return leaderboard;
    const items = leaderboard.map((item, idx) => ({ ...item, __i: idx }));
    items.sort((a: any, b: any) => {
      let cmp = 0;
      switch (sortConfig.key) {
        case 'model':
        case 'link':
          cmp = String(a[sortConfig.key]).localeCompare(String(b[sortConfig.key]));
          break;
        case 'average_per':
        case 'average_per_fer':
          const aNum = parseFloat(String(a[sortConfig.key].average_per).replace('%', ''));
          const bNum = parseFloat(String(b[sortConfig.key]).replace('%', ''));
          cmp = aNum - bNum;
          break;
        case 'average_fer': {
          const aNum = parseFloat(String(a[sortConfig.key]).replace('%', ''));
          const bNum = parseFloat(String(b[sortConfig.key]).replace('%', ''));
          cmp = aNum - bNum;
          break;
        }
        case 'submission_date':
          cmp = new Date(a.submission_date).getTime() - new Date(b.submission_date).getTime();
          break;
      }
      if (cmp === 0) cmp = a.__i - b.__i;
      return sortConfig.direction === 'asc' ? cmp : -cmp;
    });
    return items;
  }, [sortConfig]);
  return (
    <div id="models" className="">
      <svg
        width="75"
        height="905"
        viewBox="0 0 75 905"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
        className="absolute top-4 left-0 z-[1] hidden 2xl:block"
      >
        <g clipPath="url(#clip0_3877_301)">
          <path
            d="M69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433C-69.6808 97.3525 69.9825 -0.460876 69.9963 96.9968C70.0013 132.346 70.0002 294.846 69.9986 452.469C70.0002 610.092 70.0014 772.592 69.9964 807.941Z"
            fill="#ffffff"
          />
          <path
            d="M69.9963 196.941C69.9963 360.607 70.0045 750.741 69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433M-69.8022 -0.0624878C-69.8022 -0.0201653 -69.8022 0.0220944 -69.8022 0.0643433M69.9964 707.997C69.9964 544.33 70.0044 154.197 69.9963 96.9968C69.9825 -0.460854 -69.6808 97.3525 -69.8022 0.0643433"
            stroke="#E5E5E5"
          />
        </g>
        <defs>
          <clipPath id="clip0_3877_301">
            <rect
              width="75.0001"
              height="905"
              fill="white"
              transform="translate(75 905) rotate(180)"
            />
          </clipPath>
        </defs>
      </svg>

      <svg
        width="75"
        height="905"
        viewBox="0 0 75 905"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
        className="absolute top-4 right-0 z-[1] rotate-180 hidden 2xl:block"
      >
        <g clipPath="url(#clip0_3877_301)">
          <path
            d="M69.9963 196.941C69.9963 360.607 70.0045 750.741 69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433M-69.8022 -0.0624878C-69.8022 -0.0201653 -69.8022 0.0220944 -69.8022 0.0643433M69.9964 707.997C69.9964 544.33 70.0044 154.197 69.9963 96.9968C69.9825 -0.460854 -69.6808 97.3525 -69.8022 0.0643433"
            stroke="#E5E5E5"
          />
        </g>
        <defs>
          <clipPath id="clip0_3877_301">
            <rect
              width="75.0001"
              height="905"
              fill="white"
              transform="translate(75 905) rotate(180)"
            />
          </clipPath>
        </defs>
      </svg>

      <div className="mx-auto">
        <div className="mx-auto absolute h-full flex justify-between z-[-1]"></div>

        <section
          aria-labelledby="features-heading"
          className="mx-auto w-full h-fit bg-neutral-50/20 backdrop-blur-md border-y border-neutral-200 overflow-hidden"
        >
          <div
            data-cursor-opacity="0.8"
            data-cursor-size="240"
            data-cursor-color="#2A4BCC"
            className="bg-white py-24 sm:py-32"
          >
            <div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8 z-[1000] relative">
              <p className="text-base/7 font-semibold text-sky-600 relative z-10">Leaderboard</p>
              <h2
                id="features-heading"
                className="mt-2 text-balance text-4xl font-semibold tracking-tighter text-gray-950 sm:text-5xl relative z-10"
              >
                Setting a new standard in phonetic transcription
              </h2>
              {/* <ul
                role="list"
                data-cursor-opacity="1"
                data-cursor-size="340"
                className="mt-12 grid lg:p-2 z-10 grid-cols-1 lg:grid-cols-2 relative gap-4 bg-white overflow-hidden group"
              >
                <p className="leading-relaxed">
                  Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quos. Quasi
                  voluptatibus atque eum quam velit? Sequi, autem cumque consequatur laborum. Ipsum
                  dolor sit amet consectetur adipisicing elit. Quisquam, quos.
                </p>
                <p className="leading-relaxed">
                  Quisquam, quos. Quasi voluptatibus atque eum quam velit? Sequi, autem cumque
                  consequatur laborum. Ipsum dolor sit amet consectetur adipisicing elit. Quisquam,
                  quos. Quasi voluptatibus atque eum quam velit? Sequi, autem cumque consequatur
                  laborum.
                </p>
              </ul> */}

              <div className="p-2 mt-12 border rounded-[24px] bg-white">
                <ul
                  role="list"
                  className="grid grid-cols-1 gap-10 sm:gap-20 z-10 relative overflow-x-scroll rounded-2xl border"
                >
                  <table className="border-collapse overflow-x-scroll">
                    <thead className="bg-neutral-100 border-b">
                      <tr className="*:font-semibold *:tracking-tight *:py-3 *:px-4 *:border-r last:border-r-0! *:min-w-[150px] sm:*:min-w-[100px]">
                        <th
                          className="text-center sm:text-left"
                          aria-sort={
                            getDirectionFor('model')
                              ? getDirectionFor('model') === 'asc'
                                ? 'ascending'
                                : 'descending'
                              : 'none'
                          }
                        >
                          <button
                            type="button"
                            onClick={() => requestSort('model')}
                            className="inline-flex items-center gap-1 cursor-pointer select-none"
                          >
                            <span>Model</span>
                            <SortIndicator direction={getDirectionFor('model')} />
                          </button>
                        </th>
                        <th
                          className="text-center hidden sm:table-cell"
                          aria-sort={
                            getDirectionFor('average_per')
                              ? getDirectionFor('average_per') === 'asc'
                                ? 'ascending'
                                : 'descending'
                              : 'none'
                          }
                        >
                          <button
                            type="button"
                            onClick={() => requestSort('average_per')}
                            className="inline-flex items-center gap-1 cursor-pointer select-none justify-center w-full"
                          >
                            <span>Average PER</span>
                            <SortIndicator direction={getDirectionFor('average_per')} />
                          </button>
                        </th>
                        <th
                          className="text-center hidden sm:table-cell"
                          aria-sort={
                            getDirectionFor('average_fer')
                              ? getDirectionFor('average_fer') === 'asc'
                                ? 'ascending'
                                : 'descending'
                              : 'none'
                          }
                        >
                          <button
                            type="button"
                            onClick={() => requestSort('average_fer')}
                            className="inline-flex items-center gap-1 cursor-pointer select-none justify-center w-full"
                          >
                            <span>Average FER</span>
                            <SortIndicator direction={getDirectionFor('average_fer')} />
                          </button>
                        </th>
                        <th
                          className="text-center w-[110px] hidden sm:table-cell"
                          aria-sort={
                            getDirectionFor('link')
                              ? getDirectionFor('link') === 'asc'
                                ? 'ascending'
                                : 'descending'
                              : 'none'
                          }
                        >
                          <button
                            type="button"
                            onClick={() => requestSort('link')}
                            className="inline-flex items-center gap-1 cursor-pointer select-none justify-center w-full"
                          >
                            <span>Link</span>
                            <SortIndicator direction={getDirectionFor('link')} />
                          </button>
                        </th>
                        <th
                          className="text-center w-[160px] hidden sm:table-cell border-0!"
                          aria-sort={
                            getDirectionFor('submission_date')
                              ? getDirectionFor('submission_date') === 'asc'
                                ? 'ascending'
                                : 'descending'
                              : 'none'
                          }
                        >
                          <button
                            type="button"
                            onClick={() => requestSort('submission_date')}
                            className="inline-flex items-center gap-1 cursor-pointer select-none justify-center w-full"
                          >
                            <span>Submission</span>
                            <SortIndicator direction={getDirectionFor('submission_date')} />
                          </button>
                        </th>
                        <th
                          className="text-center sm:hidden table-cell min-w-[165px]!"
                          aria-sort={
                            getDirectionFor('average_per_fer')
                              ? getDirectionFor('average_per_fer') === 'asc'
                                ? 'ascending'
                                : 'descending'
                              : 'none'
                          }
                        >
                          <button
                            type="button"
                            onClick={() => requestSort('average_per_fer')}
                            className="inline-flex items-center gap-1 cursor-pointer select-none justify-center w-full"
                          >
                            <span>PER / FER</span>
                            <SortIndicator direction={getDirectionFor('average_per_fer')} />
                          </button>
                        </th>
                      </tr>
                    </thead>
                    <tbody>
                      {sortedLeaderboard.map((item, index) => (
                        <tr
                          key={item.model}
                          className={`border-y h-[100px] sm:h-auto last:border-b-0 ${
                            item.koel_labs
                              ? 'bg-sky-100 outline outline-sky-200 z-10'
                              : index % 2 === 0
                                ? 'bg-white'
                                : 'bg-neutral-50'
                          }`}
                        >
                          <td
                            className={`text-left py-3 px-4 border-r ${item.koel_labs ? 'border-sky-200' : 'border-neutral-200'}`}
                          >
                            {item.model}
                          </td>
                          <td
                            className={`text-center py-3 px-4 border-r hidden sm:table-cell ${item.koel_labs ? 'border-sky-200' : 'border-neutral-200'}`}
                          >
                            {item.average_per}
                          </td>
                          <td
                            className={`text-center py-3 px-4 border-r hidden sm:table-cell ${item.koel_labs ? 'border-sky-200' : 'border-neutral-200'}`}
                          >
                            {item.average_fer}
                          </td>
                          <td
                            className={`text-center py-3 px-4 border-r hidden sm:table-cell ${item.koel_labs ? 'border-sky-200' : 'border-neutral-200'}`}
                          >
                            {tagLink(item.link)}
                          </td>
                          <td className="text-center py-3 px-4 hidden sm:table-cell">
                            {tag(formatDate(item.submission_date))}
                          </td>
                          <td className="text-center sm:hidden table-cell">
                            {item.average_per} / {item.average_fer}
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </ul>
              </div>
              <p className="text-center text-sm text-neutral-500 mt-8">
                Last updated: November 1, 2025 from{' '}
                <a
                  href="https://huggingface.co/spaces/KoelLabs/IPA-Transcription-EN"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-sky-600 underline"
                >
                  https://huggingface.co/spaces/KoelLabs/IPA-Transcription-EN
                </a>
              </p>
            </div>
          </div>
        </section>
      </div>
    </div>
  );
}



================================================
FILE: app/previews/sections-previews/previews-hero.tsx
================================================
'use client';
import React from 'react';
import { ArrowUpRight } from 'lucide-react';

import { Button } from '@/components/ui/base/button';
import Link from 'next/link';

const previews = [
  {
    title: 'Phrase Segmentation',
    status: 'In Beta',
    description:
      'Phrase Segmentation, our demonstration tool for how phonetic transcription models will eventually interact with users in conjunction with language learning materials, is now available in closed beta.  ',
    image: '/images/card-two.svg',
  },
  {
    title: 'Phonetic Models',
    status: 'Available',
    description:
      'XLSR-English-01, the state-of-the-art model for phonetic transcription, is available on Huggingface, alongside our other models, various datasets, and our IPA transcription leaderboard.',
    image: '/images/card-one-center.svg',
    link: 'https://huggingface.co/KoelLabs/xlsr-english-01',
  },
  {
    title: 'Speech Analysis',
    status: 'Upcoming',
    description:
      'A robust and open speech analysis tool, powered by our own models, to allow for real-time feedback to users about speech, based on an actor reference, not a restricted, arbitrary standard.',
    image: '/images/card-three.svg',
  },
];

export default function PreviewsHero() {
  return (
    <div className="relative min-h-[900px] h-full overflow-hidden">
      <div className="absolute right-0 -top-20 w-full h-[500px] bg-gradient-to-b from-white via-10% via-white to-transparent z-[12]"></div>

      <div className="absolute left-0 bottom-0 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[12] hidden 2xl:block">
        <div className="rounded-full w-full h-full border bg-white"></div>
      </div>

      <div className="absolute right-0 bottom-0 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[12] hidden 2xl:block">
        <div className="rounded-full w-full h-full border bg-white"></div>
      </div>
      {/* <div className="absolute right-0 -top-20 w-full h-[110%] bg-gradient-to-b from-[#0086FF] to-[#2A4BCC] z-[2] mix-blend-color pointer-events-none"></div> */}
      {/* <div className="absolute left-0 -top-20 w-[60px] h-[110%] bg-gradient-to-b from-[#0086FF] to-[#2A4BCC] z-[2] mix-blend-color"></div> */}

      <div className="absolute right-0 -top-20 w-[50.5px] h-[110%] overflow-hidden items-start justify-center bg-neutral-50 border-x z-[11] hidden 2xl:flex shadow-xl">
        <div className="flex-col h-full items-start gap-[8px] mt-[2px] flex">
          {Array(145)
            .fill(0)
            .map((_, i) => (
              <div
                key={`right-${i}`}
                className="h-px w-[50.5px] bg-neutral-200 dark:bg-neutral-800"
              ></div>
            ))}
        </div>
      </div>
      <div className="absolute left-0 -top-20 w-[50.5px] h-[110%] overflow-hidden items-start justify-center bg-neutral-50 border-x z-[11] hidden 2xl:flex shadow-xl">
        <div className="flex-col h-full items-start gap-[8px] mt-[2px] flex">
          {Array(145)
            .fill(0)
            .map((_, i) => (
              <div
                key={`right-${i}`}
                className="h-px w-[50.5px] bg-neutral-200 dark:bg-neutral-800"
              ></div>
            ))}
        </div>
      </div>
      <div className="mx-auto md:px-6 pt-0 lg:px-8 py-32 pb-0">
        <div className="mx-auto p-4 max-w-4xl py-32 z-[90] relative">
          <section aria-labelledby="hero-heading" className="text-center relative">
            {/* <div className="flex flex-row justify-center items-center my-8"></div> */}
            <div className="hidden sm:mb-8 sm:flex sm:justify-center relative z-10 max-w-lg mx-auto">
              <div className="relative rounded-full px-2 py-0.5 pr-4.5 text-sm/6 text-gray-600 border-y border-l rounded-r-none w-fit">
                We've released a series of blogs about Wav2Vec2{' '}
              </div>
              <a
                href="/blog"
                className="font-semibold text-[#154063] rounded-full shadow-xs bg-white -ml-3 pl-2.5 border-l-none border text-sm/6 px-2 py-0.5 inset-0"
              >
                <span aria-hidden="true" className="absolute inset-0 tracking-tight" />
                Read more <ArrowUpRight className="w-4 h-4 inline-block -ml-0.5" strokeWidth={3} />
              </a>
            </div>
            <h1
              id="hero-heading"
              className="text-balance text-4xl font-semibold tracking-tighter text-gray-950 sm:text-6xl relative sm:block hidden"
            >
              Making Speech Technology Understand You Better
            </h1>
            <h1
              id="hero-heading"
              className="text-balance text-[2.2rem] leading-[1.15] text-4xl font-semibold tracking-tighter text-gray-950 relative sm:hidden block"
            >
              Making Speech Tech Understand You Better
            </h1>

            <p className="mt-6 sm:text-lg leading-8 text-neutral-600 max-w-xl mx-auto text-pretty">
              Get the very first look at our research previews, straight from the future of speech
              technology and language learning.
            </p>
            <div className="mt-4 flex flex-col gap-2 sm:flex-row items-center justify-center gap-x-4 w-full">
              <Link href="/research" className="w-full sm:w-auto">
                <Button
                  variant="outline"
                  className="active:scale-[97%] transition-all duration-50 w-full sm:w-auto"
                >
                  Join the waitlist
                </Button>
              </Link>
              <Link href="/research" className="w-full sm:w-auto">
                <Button className="active:scale-[97%] transition-all duration-50 w-full sm:w-auto">
                  Read our research
                </Button>
              </Link>
            </div>
          </section>
        </div>

        {/* <div className="absolute -bottom-2  h-[65px] w-[90%] bg-gradient-to-b from-[#0086FF] to-[#2A4BCC] z-[3] mix-blend-color"></div> */}

        {/* <div className="absolute bottom-0 left-0 w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-t">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div> */}
        <div className="mx-auto absolute opacity-25 sm:opacity-100 top-0 left-0 right-0 bottom-0 lg:max-w-[1264px] flex justify-between z-[-1] h-[1300px]">
          <div className="h-full"></div>
          <div className="w-[1px] h-full bg-gradient-to-b from-white via-30% via-neutral-200 to-neutral-200"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="w-[1px] h-full bg-gradient-to-b from-white via-30% via-neutral-200 to-neutral-200"></div>
          <div className="h-full"></div>
        </div>
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="141"
          height="906"
          fill="none"
          className="absolute -bottom-28 xl:right-0 hidden 2xl:block z-[-3]"
          viewBox="0 0 141 906"
        >
          <path
            stroke="#E5E5E5"
            d="M140.505 0C140.505 97.5.721-.44.707 97.06c-.008 57.199 0 447.333 0 610.999m139.798 197.003c0-97.5-139.784.441-139.798-97.059-.008-57.2 0-447.333 0-611"
          ></path>
        </svg>
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="141"
          height="906"
          fill="none"
          className="absolute rotate-180 -bottom-28 xl:left-0 hidden 2xl:block z-[-3]"
          viewBox="0 0 141 906"
        >
          <path
            stroke="#E5E5E5"
            d="M140.505 0C140.505 97.5.721-.44.707 97.06c-.008 57.199 0 447.333 0 610.999m139.798 197.003c0-97.5-139.784.441-139.798-97.059-.008-57.2 0-447.333 0-611"
          ></path>
        </svg>

        <div className="bg-gradient-to-b from-transparent to-white via-white via-50% h-1/3 w-full absolute -bottom-0 left-0 z-[5] pointer-events-none"></div>

        <div className="flex justify-center sm:overflow-visible overflow-hidden mb-[127px] mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8 z-[4] relative gap-4">
          {previews.map(preview => (
            <div
              key={preview.title}
              className="relative shadow-xl min-w-[330px] mt-8 sm:mt-0 rounded-3xl first:-rotate-12 last:rotate-12 scale-110 first:translate-y-12 last:translate-y-12 first:translate-x-24 last:-translate-x-24 last:hover:translate-y-6 last:hover:-translate-x-12 even:hover:-translate-y-12 first:hover:translate-y-6 first:hover:translate-x-12 transition-all duration-350"
            >
              <li
                key={preview.title}
                className="flex flex-col gap-2 border border-neutral-200 rounded-3xl p-2 relative group/item bg-white"
                data-cursor-size="2"
              >
                {preview.link ? (
                  <a
                    href={preview.link}
                    target="_blank"
                    rel="noopener noreferrer"
                    className="w-full h-full absolute top-0 left-0 z-[999]"
                  />
                ) : null}

                <div className="p-4 pb-2 rounded-2xl bg-white border border-neutral-200">
                  <div className="flex flex-row gap-2 items-center justify-between pb-2">
                    <h3 className="text-lg font-medium tracking-[-0.03em] text-black">
                      {preview.title}
                    </h3>

                    <span className="transition-all inline-flex items-center px-2 py-1.5 border text-sm leading-4 font-medium tracking-tight rounded-xl text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500 w-fit flex-row justify-between hover:shadow-sm group">
                      <div
                        className={`h-2 w-2 rounded-full relative transition-all mr-1`}
                        style={{
                          backgroundColor:
                            preview.status === 'Available'
                              ? '#3779B5'
                              : preview.status === 'In Beta'
                                ? '#154063'
                                : 'black',
                        }}
                      ></div>
                      {preview.status}
                    </span>
                  </div>
                </div>
                <div
                  className=" rounded-2xl bg-white border border-neutral-200 aspect-square relative overflow-hidden"
                  data-cursor-size="320"
                >
                  <div className="h-[200%] w-[100%] bg-sky-700 rounded-full absolute -top-1/4 left-1/3 mix-blend-color blur-2xl  hidden group-hover/item:block"></div>
                  <div className="h-[200%] w-[100%] bg-[#2A4BCC] rounded-full absolute -bottom-1/4 -left-2/3 blur-2xl  mix-blend-color hidden group-hover/item:block"></div>

                  <img
                    src={preview.image}
                    alt={preview.title}
                    className="w-full h-full object-cover"
                  />
                </div>
              </li>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}



================================================
FILE: app/previews/sections-previews/previews-models.tsx
================================================
'use client';

import React, { useEffect, useRef, useState } from 'react';
import { Button } from '@/components/ui/base/button';
import { Mic, StopCircle, Loader2 } from 'lucide-react';
import { FeedbackGiver } from '@/server/src/static/FeedbackGiver.js';

export default function PreviewsModels() {
  const [isRecording, setIsRecording] = useState(false);
  const [isMicInitializing, setIsMicInitializing] = useState(false);
  const [transcription, setTranscription] = useState('');
  const feedbackGiverRef = useRef<any>(null);

  // Create a long placeholder sentence to keep SpeechRecognition happy while we stream IPA
  const PLACEHOLDER_WORDS: any = Array.from({ length: 64 }, (_, i) => [`word${i + 1}`, []]);

  const start = async () => {
    try {
      if (isRecording) return;
      setIsMicInitializing(true);
      setTranscription('');

      const serverHost =
        process.env.NEXT_PUBLIC_SERVER_HOST && process.env.NEXT_PUBLIC_SERVER_HOST.length > 0
          ? process.env.NEXT_PUBLIC_SERVER_HOST
          : `${window.location.hostname}:8080`;

      feedbackGiverRef.current = new FeedbackGiver(
        PLACEHOLDER_WORDS,
        (newTranscription: any) => {
          const text = Array.isArray(newTranscription)
            ? newTranscription.join(' ')
            : String(newTranscription ?? '');
          setTranscription(text);
        },
        () => {},
        undefined, // ensure worklet loads from Next.js origin (/WavWorklet.js)
        serverHost,
      );

      await feedbackGiverRef.current.start();
      setIsRecording(true);
    } catch (e) {
      console.error('Error starting mic preview:', e);
    } finally {
      setIsMicInitializing(false);
    }
  };

  const stop = async () => {
    try {
      if (!isRecording) return;
      if (feedbackGiverRef.current) {
        await feedbackGiverRef.current.stop();
      }
    } catch (e) {
      console.error('Error stopping mic preview:', e);
    } finally {
      setIsRecording(false);
    }
  };

  useEffect(() => {
    return () => {
      if (feedbackGiverRef.current) {
        feedbackGiverRef.current.stop();
      }
    };
  }, []);

  return (
    <div id="models" className="">
      <div className="mx-auto">
        <section
          aria-labelledby="features-heading"
          className="mx-auto w-full h-fit bg-neutral-50/20 backdrop-blur-md border-y border-neutral-200 overflow-hidden"
        >
          <div
            data-cursor-opacity="0.8"
            data-cursor-size="240"
            data-cursor-color="#2A4BCC"
            className="bg-white py-24 sm:py-32"
          >
            <div className="mx-auto max-w-2xl px-6 lg:max-w-5xl lg:px-8 z-[1000] relative">
              <p className="text-base/7 font-semibold text-blue-600 relative z-10">Model Preview</p>
              <h2
                id="features-heading"
                className="mt-2 text-pretty text-4xl font-semibold tracking-tighter text-gray-950 sm:text-5xl relative z-10"
              >
                Speak and see the raw IPA transcript
              </h2>

              <div className="mt-10 grid grid-cols-1 gap-6 lg:grid-cols-2">
                <div className="flex flex-col gap-4">
                  <div className="flex items-center gap-3">
                    {isRecording ? (
                      <Button
                        className="border px-4 py-2 rounded-md items-center tracking-tight flex justify-center transition-all duration-150 border-[#FECACA] bg-[#FEE2E2] text-[#991B1B] dark:bg-[#451A1A] dark:text-[#FECACA] hover:bg-[#FEE2E2]/80"
                        onClick={stop}
                        disabled={isMicInitializing}
                      >
                        <StopCircle className="mr-2 size-4" /> Stop
                      </Button>
                    ) : (
                      <Button
                        className={`border px-4 py-2 rounded-md items-center tracking-tight flex justify-center transition-all duration-150 ${
                          isMicInitializing
                            ? 'text-neutral-400 bg-neutral-100 border-neutral-200 cursor-not-allowed'
                            : 'text-[#1B997B] bg-[#C7E9DE] border-[#9DD8C5] hover:bg-[#C7E9DE]/80'
                        }`}
                        onClick={start}
                        disabled={isMicInitializing}
                      >
                        {isMicInitializing ? (
                          <>
                            <Loader2 className="mr-2 size-4 animate-spin" /> Initializing
                            Microphone...
                          </>
                        ) : (
                          <>
                            <Mic className="mr-2 size-4" /> Start
                          </>
                        )}
                      </Button>
                    )}
                  </div>

                  <p className="text-sm text-neutral-600">
                    This demo streams your speech to our model and shows the raw IPA tokens in real
                    time.
                  </p>
                </div>

                <div className="bg-white border border-neutral-200 rounded-2xl p-4 min-h-[160px]">
                  <h3 className="text-sm font-medium text-neutral-700 mb-2">Live IPA transcript</h3>
                  <div className="text-lg tracking-tight text-neutral-900 break-words whitespace-pre-wrap">
                    {transcription || '—'}
                  </div>
                </div>
              </div>
            </div>
          </div>
        </section>
      </div>
    </div>
  );
}



================================================
FILE: app/pricing/page.tsx
================================================
'use client';

import { useState, Fragment } from 'react';
import { Radio, RadioGroup } from '@headlessui/react';
import Header from '@/components/ui/header';
import { Button } from '@/components/ui/base/button';
import React from 'react';
import { Check, Minus, X } from 'lucide-react';
import { Dashboard } from '@/components/ui/dashboard';
import NotFound from '@/app/not-found';
const frequencies = [
  { value: 'monthly', label: 'Monthly', priceSuffix: '/month' },
  { value: 'annually', label: 'Annually', priceSuffix: '/month billed yearly' },
];
const tiers = [
  {
    name: 'Free',
    id: 'tier-free',
    clickMessage: 'Start Practicing',
    href: '#',
    price: { monthly: '$0', annually: '$0' },
    description:
      'Get started with our free plan, no credit card required. The perfect way to get started.',
    features: [
      'Import up to 10 of your favorite clips',
      'Real-time insights and feedback',
      'Basic analytics on your sessions',
      'Professional tips and tricks',
    ],
    notIncluded: [
      'Limited to 10 minutes of practice per day',
      'Maximum of 1 hour analyzed per month',
    ],
    mostPopular: false,
  },
  {
    name: 'Premium',
    id: 'tier-premium',

    href: '#',
    price: { monthly: '$5.99', annually: '$4.99' },
    description:
      'Everything you need to take your practice to the next level, with advanced analytics and higher limits.',
    features: [
      'Import up to 500 of your favorite clips',
      'Real-time insights and feedback',
      'Advanced analytics on your practice sessions and growth',
      'Unlimited practice time per day',
      'Access to new features first',
    ],
    mostPopular: true,
  },
  {
    name: 'Institution',
    id: 'tier-institution',
    clickMessage: 'Get in Touch',
    href: '#',
    price: { monthly: '', annually: '' },
    description: 'Custom plans for schools, teams, and organizations.',
    features: [
      'Unlimited clip imports',
      'SSO and user management',
      'Real-time insights and feedback',
      "Advanced analytics on student's practice sessions and growth",
      'Dedicated support and infrastructure',
    ],
    mostPopular: false,
  },
];
const sections = [
  {
    name: 'Features',
    features: [
      { name: 'Integrations', tiers: { Basic: true, Essential: true, Premium: true } },
      { name: 'Shared links', tiers: { Basic: true, Essential: true, Premium: true } },
      { name: 'Importing and exporting', tiers: { Essential: true, Premium: true } },
      { name: 'Team members', tiers: { Essential: 'Up to 20 users', Premium: 'Up to 50 users' } },
    ],
  },
  {
    name: 'Reporting',
    features: [
      { name: 'Advanced analytics', tiers: { Basic: true, Essential: true, Premium: true } },
      { name: 'Basic reports', tiers: { Essential: true, Premium: true } },
      { name: 'Professional reports', tiers: { Premium: true } },
      { name: 'Custom report builder', tiers: { Premium: true } },
    ],
  },
  {
    name: 'Support',
    features: [
      { name: '24/7 online support', tiers: { Basic: true, Essential: true, Premium: true } },
      { name: 'Quarterly product workshops', tiers: { Essential: true, Premium: true } },
      { name: 'Priority phone support', tiers: { Essential: true, Premium: true } },
      { name: '1:1 onboarding tour', tiers: { Premium: true } },
    ],
  },
];

function classNames(...classes) {
  return classes.filter(Boolean).join(' ');
}

export default function Page() {
  const [frequency, setFrequency] = useState(frequencies[0]);
  return (
    // <Dashboard />
    <NotFound />
    // <div className="flex-col flex w-screen relative scroll-smooth">

    //   {/* <div className="z-2 sticky top-0 mx-auto w-full">
    //     <Header />
    //   </div>
    //   <div className="min-h-screen">
    //     <div className="color-bg h-full w-11/12 left-0 right-0 mx-auto absolute z-0 blur-[64px] transform-gpu opacity-10 top-48"></div>
    //     <div className=" py-24 sm:py-32 z-1 relative">
    //       <div className="mx-auto max-w-7xl px-6 lg:px-8">
    //         <div className="mx-auto max-w-4xl text-center">
    //           <h2 className="text-base font-semibold leading-7 text-transparent bg-clip-text bg-linear-to-br from-black to-sky-600">
    //             Pricing
    //           </h2>
    //           <p className="text-4xl font-bold tracking-[-0.04em] text-neutral-900 sm:text-5xl">
    //             Simple Pricing for Everyone.
    //           </p>
    //         </div>
    //         <p className="mx-auto mt-6 max-w-2xl text-center text-lg leading-8 text-neutral-600">
    //           Choose the plan that best fits your needs, goals, and budget.
    //         </p>
    //         <div className="mt-16 flex justify-center">
    //           <fieldset aria-label="Payment frequency">
    //             <RadioGroup
    //               value={frequency}
    //               onChange={setFrequency}
    //               className="grid grid-cols-2 gap-x-1 rounded-full p-1 text-center text-xs font-semibold leading-5 ring-1 ring-inset ring-neutral-200 bg-white"
    //             >
    //               {frequencies.map(option => (
    //                 <Radio
    //                   key={option.value}
    //                   value={option}
    //                   className="cursor-pointer rounded-full px-2.5 py-1 text-neutral-500 data-checked:bg-linear-to-br data-checked:from-black data-checked:to-sky-800 data-checked:text-white"
    //                 >
    //                   {option.label}
    //                 </Radio>
    //               ))}
    //             </RadioGroup>
    //           </fieldset>
    //         </div>
    //         <div className="isolate mx-auto mt-10 grid max-w-md grid-cols-1 gap-8 lg:mx-0 lg:max-w-none lg:grid-cols-3 relative">
    //           {tiers.map(tier => (
    //             <div
    //               key={tier.id}
    //               className={classNames(
    //                 tier.mostPopular
    //                   ? 'ring-2 ring-sky-800 bg-linear-to-b shadow-sky-950/50'
    //                   : 'ring-1 ring-neutral-200 mt-8',
    //                 'rounded-3xl p-8 xl:p-10 bg-white shadow-lg flex flex-col justify-between',
    //               )}
    //             >
    //               <div>
    //                 <div className="flex items-center justify-between gap-x-4">
    //                   <h3
    //                     id={tier.id}
    //                     className={classNames(
    //                       tier.mostPopular ? 'text-sky-800' : 'text-neutral-900',
    //                       'text-lg font-semibold leading-8',
    //                     )}
    //                   >
    //                     {tier.name}
    //                   </h3>
    //                   {tier.mostPopular ? (
    //                     <p className="rounded-full bg-sky-900/10 px-2.5 py-1 text-xs font-semibold leading-5 text-sky-800">
    //                       Most popular
    //                     </p>
    //                   ) : null}
    //                 </div>
    //                 <p className="mt-4 text-sm leading-6 text-neutral-600">{tier.description}</p>
    //                 <p className="mt-6 flex items-baseline gap-x-1">
    //                   <span className="text-4xl font-bold tracking-tight text-neutral-900">
    //                     {tier.name === 'Institution' ? 'Contact Us' : tier.price[frequency.value]}
    //                   </span>
    //                   <span className="text-sm font-semibold leading-6 text-neutral-600">
    //                     {tier.name === 'Institution' ? '' : frequency.priceSuffix}
    //                   </span>
    //                 </p>
    //                 <ul
    //                   role="list"
    //                   className="mt-8 space-y-3 text-sm leading-6 text-neutral-600 xl:mt-10"
    //                 >
    //                   {tier.features.map(feature => (
    //                     <li key={feature} className="flex gap-x-3">
    //                       <Check aria-hidden="true" className="h-6 w-5 flex-none text-sky-600" />
    //                       {feature}
    //                     </li>
    //                   ))}
    //                   {tier.notIncluded?.map(
    //                     feature =>
    //                       (
    //                         <li key={feature} className="flex gap-x-3 text-neutral-600">
    //                           <X aria-hidden="true" className="h-6 w-5 flex-none" />
    //                           {feature}
    //                         </li>
    //                       ) || null,
    //                   )}
    //                 </ul>
    //               </div>
    //               <a
    //                 href={tier.href}
    //                 aria-describedby={tier.id}
    //                 className={classNames(
    //                   tier.mostPopular
    //                     ? 'border bg-linear-to-br border-double outline-white/50 outline outline-[0.1px] outline-offset-[-2px] border-black from-sky-800 to-blue-950 dark:outline-black/50 dark:from-sky-600 dark:to-blue-800 text-white shadow-sm shadow-sky-950 hover:shadow-sky-700'
    //                     : 'text-black ring-1 ring-inset ring-sky-800/50 hover:ring-sky-900/60',
    //                   'mt-8 transition-all hover:-translate-y-0.5 hover:shadow-sm block rounded-md px-3 py-2 text-center text-sm font-semibold leading-6 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600',
    //                 )}
    //               >
    //                 {tier.clickMessage || 'Try for Free'}
    //               </a>
    //             </div>
    //           ))}
    //         </div>

    //         <div className="mx-auto mt-12 max-w-md space-y-8 sm:mt-16 lg:hidden">
    //           {tiers.map(tier => (
    //             <section
    //               key={tier.id}
    //               className={classNames(
    //                 tier.mostPopular
    //                   ? 'rounded-xl bg-gray-400/5 ring-1 ring-inset ring-gray-200'
    //                   : '',
    //                 'p-8',
    //               )}
    //             >
    //               <h3 id={tier.id} className="text-sm font-semibold leading-6 text-gray-900">
    //                 {tier.name}
    //               </h3>
    //               <p className="mt-2 flex items-baseline gap-x-1 text-gray-900">
    //                 <span className="text-4xl font-bold">{tier.priceMonthly}</span>
    //                 <span className="text-sm font-semibold">/month</span>
    //               </p>
    //               <a
    //                 href={tier.href}
    //                 aria-describedby={tier.id}
    //                 className={classNames(
    //                   tier.mostPopular
    //                     ? 'bg-indigo-600 text-white hover:bg-indigo-500'
    //                     : 'text-indigo-600 ring-1 ring-inset ring-indigo-200 hover:ring-indigo-300',
    //                   'mt-8 block rounded-md px-3 py-2 text-center text-sm font-semibold leading-6 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600',
    //                 )}
    //               >
    //                 Buy plan
    //               </a>
    //               <ul role="list" className="mt-10 space-y-4 text-sm leading-6 text-gray-900">
    //                 {sections.map(section => (
    //                   <li key={section.name}>
    //                     <ul role="list" className="space-y-4">
    //                       {section.features.map(feature =>
    //                         feature.tiers[tier.name] ? (
    //                           <li key={feature.name} className="flex gap-x-3">
    //                             <Check
    //                               aria-hidden="true"
    //                               className="h-6 w-5 flex-none text-indigo-600"
    //                             />
    //                             <span>
    //                               {feature.name}{' '}
    //                               {typeof feature.tiers[tier.name] === 'string' ? (
    //                                 <span className="text-sm leading-6 text-gray-500">
    //                                   ({feature.tiers[tier.name]})
    //                                 </span>
    //                               ) : null}
    //                             </span>
    //                           </li>
    //                         ) : null,
    //                       )}
    //                     </ul>
    //                   </li>
    //                 ))}
    //               </ul>
    //             </section>
    //           ))}
    //         </div>

    //         <div className="isolate mt-20 hidden lg:block">
    //           <div className="relative -mx-8">
    //             {tiers.some(tier => tier.mostPopular) ? (
    //               <div className="absolute inset-x-4 inset-y-0 -z-10 flex">
    //                 <div
    //                   style={{
    //                     marginLeft: `${(tiers.findIndex(tier => tier.mostPopular) + 1) * 25}%`,
    //                   }}
    //                   aria-hidden="true"
    //                   className="flex w-1/4 px-4"
    //                 >
    //                   <div className="w-full rounded-t-xl border-x border-t border-gray-900/10 bg-gray-400/5" />
    //                 </div>
    //               </div>
    //             ) : null}
    //             <table className="w-full table-fixed border-separate border-spacing-x-8 text-left">
    //               <caption className="sr-only">Pricing plan comparison</caption>
    //               <colgroup>
    //                 <col className="w-1/4" />
    //                 <col className="w-1/4" />
    //                 <col className="w-1/4" />
    //                 <col className="w-1/4" />
    //               </colgroup>
    //               <thead>
    //                 <tr>
    //                   <td />
    //                   {tiers.map(tier => (
    //                     <th key={tier.id} scope="col" className="px-6 pt-6 xl:px-8 xl:pt-8">
    //                       <div className="text-sm font-semibold leading-7 text-gray-900">
    //                         {tier.name}
    //                       </div>
    //                     </th>
    //                   ))}
    //                 </tr>
    //               </thead>
    //               <tbody>
    //                 <tr>
    //                   <th scope="row">
    //                     <span className="sr-only">Price</span>
    //                   </th>
    //                   {tiers.map(tier => (
    //                     <td key={tier.id} className="px-6 pt-2 xl:px-8">
    //                       <div className="flex items-baseline gap-x-1 text-gray-900">
    //                         <span className="text-4xl font-bold">{tier.priceMonthly}</span>
    //                         <span className="text-sm font-semibold leading-6">/month</span>
    //                       </div>
    //                       <a
    //                         href={tier.href}
    //                         className={classNames(
    //                           tier.mostPopular
    //                             ? 'bg-indigo-600 text-white hover:bg-indigo-500'
    //                             : 'text-indigo-600 ring-1 ring-inset ring-indigo-200 hover:ring-indigo-300',
    //                           'mt-8 block rounded-md px-3 py-2 text-center text-sm font-semibold leading-6 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600',
    //                         )}
    //                       >
    //                         Buy plan
    //                       </a>
    //                     </td>
    //                   ))}
    //                 </tr>
    //                 {sections.map((section, sectionIdx) => (
    //                   <Fragment key={section.name}>
    //                     <tr>
    //                       <th
    //                         scope="colgroup"
    //                         colSpan={4}
    //                         className={classNames(
    //                           sectionIdx === 0 ? 'pt-8' : 'pt-16',
    //                           'pb-4 text-sm font-semibold leading-6 text-gray-900',
    //                         )}
    //                       >
    //                         {section.name}
    //                         <div className="absolute inset-x-8 mt-4 h-px bg-gray-900/10" />
    //                       </th>
    //                     </tr>
    //                     {section.features.map(feature => (
    //                       <tr key={feature.name}>
    //                         <th
    //                           scope="row"
    //                           className="py-4 text-sm font-normal leading-6 text-gray-900"
    //                         >
    //                           {feature.name}
    //                           <div className="absolute inset-x-8 mt-4 h-px bg-gray-900/5" />
    //                         </th>
    //                         {tiers.map(tier => (
    //                           <td key={tier.id} className="px-6 py-4 xl:px-8">
    //                             {typeof feature.tiers[tier.name] === 'string' ? (
    //                               <div className="text-center text-sm leading-6 text-gray-500">
    //                                 {feature.tiers[tier.name]}
    //                               </div>
    //                             ) : (
    //                               <>
    //                                 {feature.tiers[tier.name] === true ? (
    //                                   <Check
    //                                     aria-hidden="true"
    //                                     className="mx-auto h-5 w-5 text-indigo-600"
    //                                   />
    //                                 ) : (
    //                                   <Minus
    //                                     aria-hidden="true"
    //                                     className="mx-auto h-5 w-5 text-gray-400"
    //                                   />
    //                                 )}

    //                                 <span className="sr-only">
    //                                   {feature.tiers[tier.name] === true
    //                                     ? 'Included'
    //                                     : 'Not included'}{' '}
    //                                   in {tier.name}
    //                                 </span>
    //                               </>
    //                             )}
    //                           </td>
    //                         ))}
    //                       </tr>
    //                     ))}
    //                   </Fragment>
    //                 ))}
    //               </tbody>
    //             </table>
    //           </div>
    //         </div>
    //       </div>
    //     </div>
    //   </div> */}
    // </div>
  );
}



================================================
FILE: app/research/page.tsx
================================================
'use server';
import React from 'react';
import CTA from '@/components/sections/cta';
import Footer from '@/components/sections/footer';
import Header from '@/components/ui/header';
import Image from 'next/image';

export default async function ResearchPage() {
  return (
    <div className="flex-col flex w-screen relative scroll-smooth">
      <div className="z-2 sticky top-0 mx-auto w-full">
        <Header />
      </div>
      <div className="flex-col flex w-screen relative scroll-smooth z-0">
        <div className="absolute top-0 left-0 w-full h-36 bg-gradient-to-b from-white via-10% via-white to-transparent z-[12]"></div>
        <div className="mx-auto max-w-7xl border-x w-full h-36 sm:h-64 flex flex-col justify-end items-start z-10">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="2037"
            height="257"
            fill="none"
            viewBox="0 0 2037 257"
            className="h-24 w-[300px] ml-5 sm:w-[400px] sm:ml-8 md:w-[600px] md:ml-6 lg:w-[800px] lg:ml-0 xl:w-[1024px] xl:-ml-27 sm:mb-3"
          >
            <path
              fill="#000"
              d="M975.811 208.033q-13.637 0-24.41-7.006-10.774-7.008-17.027-20.342-6.253-13.335-6.253-32.396 0-19.287 6.328-32.547 6.404-13.336 17.253-20.116 10.85-6.855 24.184-6.856 10.171 0 16.726 3.466 6.557 3.39 10.398 8.212c2.56 3.164 4.55 6.152 5.95 8.965h1.13V90.277h27.35V206h-26.82v-18.232h-1.66c-1.4 2.812-3.44 5.801-6.1 8.965q-3.992 4.671-10.55 7.986-6.554 3.315-16.499 3.315m7.609-22.376q8.664 0 14.767-4.671 6.109-4.746 9.273-13.184c2.11-5.626 3.16-12.18 3.16-19.664s-1.05-13.988-3.16-19.513c-2.06-5.525-5.13-9.819-9.198-12.883q-6.027-4.596-14.842-4.596-9.116 0-15.218 4.746t-9.192 13.11q-3.088 8.363-3.089 19.136 0 10.85 3.089 19.362 3.165 8.439 9.267 13.335 6.178 4.822 15.143 4.822m128.14-95.38v21.095h-66.53V90.277zm-50.1-27.725h27.27v108.64c0 3.666.55 6.479 1.66 8.438 1.15 1.909 2.66 3.215 4.52 3.918q2.79 1.054 6.18 1.054c1.71 0 3.26-.125 4.67-.376 1.46-.251 2.56-.477 3.31-.678l4.6 21.321c-1.46.502-3.54 1.055-6.25 1.657-2.67.603-5.93.955-9.8 1.055-6.83.201-12.98-.829-18.46-3.089-5.47-2.31-9.82-5.876-13.03-10.698-3.16-4.822-4.72-10.849-4.67-18.082zM1162.74 206V51.703h27.95v70.895h1.89l60.19-70.895h34.13l-59.67 69.237 60.2 85.059h-33.6l-46.04-66.149-17.1 20.192v45.957zm171.63 2.26c-11.3 0-21.1-2.486-29.38-7.458q-12.435-7.459-19.29-20.87-6.78-13.41-6.78-31.341 0-17.93 6.78-31.417 6.855-13.486 19.29-20.944c8.28-4.973 18.08-7.459 29.38-7.459s21.09 2.486 29.38 7.46c8.29 4.972 14.69 11.953 19.21 20.943 4.57 8.991 6.86 19.463 6.86 31.417s-2.29 22.401-6.86 31.341c-4.52 8.941-10.92 15.897-19.21 20.87-8.29 4.972-18.08 7.458-29.38 7.458m.15-21.848c6.13 0 11.25-1.683 15.37-5.048 4.12-3.416 7.18-7.986 9.19-13.712q3.09-8.59 3.09-19.136 0-10.623-3.09-19.212c-2.01-5.776-5.07-10.372-9.19-13.787s-9.24-5.123-15.37-5.123c-6.28 0-11.5 1.707-15.67 5.123q-6.18 5.123-9.27 13.787c-2.01 5.726-3.01 12.13-3.01 19.212 0 7.031 1 13.41 3.01 19.136q3.09 8.59 9.27 13.712c4.17 3.365 9.39 5.048 15.67 5.048m116.95 21.848q-17.4 0-30.06-7.232c-8.39-4.872-14.84-11.753-19.36-20.644-4.53-8.94-6.79-19.462-6.79-31.567 0-11.904 2.26-22.351 6.79-31.342 4.57-9.04 10.94-16.072 19.13-21.095q12.285-7.61 28.86-7.609 10.695 0 20.19 3.466c6.38 2.26 12 5.776 16.87 10.547 4.93 4.772 8.79 10.849 11.61 18.232 2.81 7.334 4.22 16.073 4.22 26.219v8.363h-94.86v-18.383h68.71q-.075-7.836-3.39-13.938c-2.21-4.119-5.3-7.359-9.26-9.719-3.92-2.361-8.49-3.541-13.72-3.541-5.57 0-10.47 1.356-14.69 4.068q-6.33 3.993-9.87 10.548-3.465 6.479-3.54 14.239v16.047q0 10.096 3.69 17.329 3.69 7.157 10.32 10.999c4.42 2.512 9.6 3.767 15.52 3.767 3.97 0 7.56-.552 10.78-1.657 3.21-1.155 6-2.838 8.36-5.048s4.14-4.947 5.35-8.212l25.47 2.863c-1.61 6.73-4.68 12.607-9.2 17.629-4.47 4.973-10.19 8.84-17.17 11.603-6.99 2.712-14.97 4.068-23.96 4.068m89.07-156.556V206h-27.27V51.703zM1596.96 206V51.703h27.95v130.865h67.96v23.431zm139.53 2.336c-7.33 0-13.94-1.306-19.81-3.918-5.83-2.662-10.45-6.58-13.87-11.753q-5.04-7.76-5.04-19.137c0-6.529 1.2-11.928 3.61-16.198q3.615-6.403 9.87-10.246c4.17-2.561 8.87-4.495 14.09-5.801a114 114 0 0 1 16.35-2.938q10.17-1.055 16.5-1.884c4.22-.603 7.28-1.507 9.19-2.712q2.94-1.883 2.94-5.801v-.452c0-5.676-1.68-10.071-5.05-13.185-3.36-3.114-8.21-4.671-14.54-4.671q-10.02 0-15.9 4.37c-3.86 2.913-6.48 6.354-7.83 10.321l-25.47-3.616c2.01-7.032 5.33-12.908 9.95-17.629q6.93-7.158 16.95-10.699c6.68-2.41 14.06-3.616 22.15-3.616q8.37 0 16.65 1.96c5.53 1.305 10.57 3.464 15.14 6.478 4.57 2.963 8.24 7.007 11 12.13 2.82 5.123 4.22 11.527 4.22 19.211v77.45h-26.22v-15.897h-.9c-1.66 3.215-3.99 6.228-7.01 9.041q-4.44 4.145-11.22 6.705-6.705 2.487-15.75 2.487m7.08-20.041c5.48 0 10.22-1.08 14.24-3.24q6.03-3.314 9.27-8.739c2.21-3.616 3.31-7.559 3.31-11.828V150.85c-.85.703-2.31 1.356-4.37 1.959q-3 .904-6.78 1.582c-2.51.452-4.99.854-7.45 1.206-2.47.351-4.6.652-6.41.904q-6.105.828-10.92 2.712c-3.22 1.256-5.75 3.013-7.61 5.274q-2.79 3.315-2.79 8.588c0 5.023 1.83 8.815 5.5 11.377q5.505 3.842 14.01 3.842m69.92 17.705V51.703h27.28v57.71h1.13c1.4-2.813 3.39-5.801 5.95-8.965 2.56-3.215 6.02-5.952 10.39-8.212 4.37-2.31 9.95-3.466 16.73-3.466q13.41 0 24.18 6.856c7.24 4.52 12.96 11.226 17.18 20.116 4.27 8.84 6.41 19.689 6.41 32.547 0 12.707-2.09 23.506-6.26 32.396s-9.84 15.67-17.03 20.342c-7.18 4.671-15.31 7.006-24.41 7.006-6.63 0-12.12-1.105-16.49-3.315s-7.89-4.872-10.55-7.986c-2.61-3.164-4.65-6.153-6.1-8.965h-1.59v18.232zm26.75-57.861c0 7.484 1.05 14.038 3.16 19.664q3.24 8.438 9.27 13.184c4.07 3.114 8.99 4.671 14.77 4.671 6.02 0 11.07-1.607 15.14-4.822 4.07-3.264 7.13-7.709 9.19-13.335 2.11-5.675 3.16-12.129 3.16-19.362 0-7.183-1.03-13.561-3.08-19.136-2.06-5.576-5.13-9.945-9.2-13.11-4.06-3.164-9.14-4.746-15.21-4.746q-8.745 0-14.85 4.596c-4.06 3.064-7.15 7.358-9.26 12.883q-3.09 8.287-3.09 19.513m184.41-27.273-24.86 2.712q-1.05-3.767-3.69-7.082-2.565-3.315-6.93-5.349c-2.91-1.356-6.48-2.034-10.7-2.034-5.67 0-10.45 1.23-14.31 3.691-3.82 2.462-5.7 5.651-5.65 9.569q-.075 5.047 3.69 8.212c2.56 2.109 6.78 3.842 12.65 5.198l19.74 4.219c10.95 2.361 19.09 6.103 24.41 11.226 5.38 5.123 8.09 11.828 8.14 20.116-.05 7.282-2.18 13.711-6.4 19.287-4.17 5.525-9.97 9.844-17.41 12.958-7.43 3.114-15.97 4.671-25.61 4.671-14.17 0-25.57-2.963-34.21-8.89-8.64-5.977-13.78-14.289-15.44-24.937l26.59-2.562c1.21 5.224 3.77 9.166 7.69 11.828s9.01 3.993 15.29 3.993q9.72 0 15.6-3.993c3.97-2.662 5.95-5.952 5.95-9.869q0-4.972-3.84-8.212-3.765-3.24-11.76-4.973l-19.74-4.143q-16.65-3.466-24.63-11.678c-5.33-5.525-7.96-12.507-7.91-20.945-.05-7.132 1.88-13.31 5.8-18.533q5.955-7.91 16.5-12.205 10.62-4.37 24.48-4.37c13.57 0 24.24 2.888 32.02 8.664 7.84 5.776 12.69 13.586 14.54 23.431"
            ></path>
            <mask
              id="mask0_4454_292"
              width="869"
              height="162"
              x="12"
              y="49"
              maskUnits="userSpaceOnUse"
              style={{ maskType: 'luminance' }}
            >
              <path fill="#fff" d="M12 49h869v162H12z"></path>
              <path
                fill="#000"
                d="M15.219 205.999V51.703h57.86q17.782 0 29.835 6.178 12.13 6.177 18.308 17.328 6.253 11.075 6.253 25.841 0 14.842-6.328 25.767-6.253 10.85-18.459 16.8-12.204 5.877-29.985 5.877h-41.21v-23.205h37.443q10.397 0 17.027-2.863 6.63-2.937 9.794-8.513 3.24-5.65 3.24-13.863 0-8.211-3.24-14.013-3.24-5.874-9.87-8.89-6.63-3.09-17.102-3.089H43.17V206zm79.71-69.916 38.196 69.916h-31.191l-37.52-69.916zm93.914 72.176q-17.404 0-30.061-7.232-12.582-7.308-19.362-20.644-6.781-13.41-6.781-31.567 0-17.856 6.781-31.342 6.855-13.56 19.136-21.095 12.28-7.61 28.855-7.609 10.699 0 20.191 3.466 9.569 3.39 16.877 10.547 7.383 7.158 11.602 18.232 4.22 11 4.219 26.219v8.363h-94.853v-18.383h68.71q-.075-7.836-3.39-13.938-3.315-6.179-9.267-9.719-5.876-3.541-13.712-3.541-8.362 0-14.691 4.068-6.328 3.993-9.87 10.548-3.466 6.479-3.541 14.239v16.047q0 10.096 3.692 17.329 3.69 7.157 10.321 10.999 6.63 3.767 15.52 3.767 5.952 0 10.774-1.657 4.821-1.733 8.363-5.048 3.54-3.315 5.349-8.212l25.465 2.863q-2.41 10.095-9.192 17.629-6.705 7.459-17.177 11.603-10.473 4.068-23.958 4.068m154.324-87.394-24.862 2.712q-1.055-3.767-3.692-7.082-2.563-3.315-6.931-5.349-4.37-2.034-10.699-2.034-8.514 0-14.314 3.691-5.726 3.692-5.651 9.569-.075 5.047 3.692 8.212 3.843 3.164 12.657 5.198l19.739 4.219q16.424 3.542 24.41 11.226 8.061 7.684 8.137 20.116-.075 10.923-6.404 19.287-6.255 8.287-17.403 12.958-11.15 4.671-25.616 4.671-21.246 0-34.204-8.89-12.958-8.965-15.445-24.937l26.595-2.562q1.808 7.835 7.685 11.828 5.874 3.993 15.294 3.993 9.717 0 15.595-3.993 5.952-3.993 5.952-9.869 0-4.972-3.842-8.212-3.767-3.24-11.753-4.973l-19.739-4.143q-16.651-3.466-24.637-11.678-7.986-8.288-7.91-20.945-.076-10.698 5.801-18.533 5.952-7.91 16.499-12.205 10.623-4.37 24.486-4.37 20.34 0 32.019 8.664 11.754 8.664 14.541 23.431m64.538 87.394q-17.404 0-30.061-7.232-12.582-7.308-19.362-20.644-6.781-13.41-6.781-31.567 0-17.856 6.781-31.342 6.854-13.56 19.136-21.095 12.28-7.61 28.855-7.609 10.699 0 20.191 3.466 9.569 3.39 16.877 10.547 7.383 7.158 11.602 18.232 4.22 11 4.219 26.219v8.363h-94.853v-18.383h68.71q-.075-7.836-3.39-13.938-3.315-6.179-9.267-9.719-5.877-3.541-13.712-3.541-8.362 0-14.691 4.068-6.33 3.993-9.87 10.548-3.465 6.479-3.541 14.239v16.047q0 10.096 3.692 17.329 3.69 7.157 10.321 10.999 6.63 3.767 15.52 3.767 5.952 0 10.774-1.657 4.821-1.733 8.363-5.048 3.54-3.315 5.349-8.212l25.465 2.863q-2.41 10.095-9.192 17.629-6.705 7.459-17.177 11.603-10.473 4.068-23.958 4.068m108.987-.226q-13.637 0-24.41-7.006-10.773-7.008-17.027-20.342-6.253-13.335-6.253-32.396 0-19.287 6.329-32.547 6.404-13.336 17.252-20.116 10.848-6.855 24.185-6.856 10.17 0 16.725 3.466 6.555 3.39 10.397 8.212 3.843 4.746 5.952 8.965h1.13V90.277h27.348V206h-26.821v-18.232h-1.657q-2.11 4.218-6.103 8.965-3.993 4.671-10.547 7.986t-16.5 3.315m7.61-22.376q8.664 0 14.766-4.671 6.102-4.746 9.267-13.184 3.164-8.44 3.164-19.664t-3.164-19.513q-3.09-8.287-9.191-12.883-6.028-4.596-14.842-4.596-9.117 0-15.219 4.746t-9.192 13.11q-3.088 8.362-3.088 19.136 0 10.85 3.088 19.362 3.165 8.439 9.267 13.335 6.179 4.822 15.144 4.822m68.23 20.342V90.277h26.444v19.287h1.206q3.162-10.02 10.849-15.445 7.684-5.5 17.704-5.5 4.671 0 8.589 1.13 3.918 1.131 6.931 3.09l-8.438 22.601q-2.184-1.054-4.821-1.733-2.637-.678-5.952-.678-7.083 0-12.808 3.165-5.726 3.163-9.116 8.815-3.315 5.574-3.315 12.958v68.032zm121.915 2.26q-17.328 0-29.759-7.609-12.356-7.61-19.061-21.02-6.63-13.486-6.63-31.04 0-17.63 6.78-31.116 6.78-13.56 19.137-21.095 12.429-7.61 29.382-7.609 14.088 0 24.938 5.198 10.923 5.124 17.403 14.541 6.48 9.342 7.384 21.849h-26.068q-1.582-8.363-7.534-13.938-5.876-5.65-15.746-5.651-8.362 0-14.691 4.521-6.33 4.444-9.87 12.807-3.465 8.364-3.465 20.041 0 11.828 3.465 20.342 3.465 8.438 9.719 13.033 6.327 4.521 14.842 4.521 6.027 0 10.774-2.26 4.821-2.335 8.061-6.706 3.24-4.37 4.445-10.623h26.068q-.981 12.28-7.233 21.774-6.254 9.417-17.027 14.766-10.773 5.274-25.314 5.274m88.634-70.066v67.806h-27.273V51.703h26.67v58.237h1.356q4.068-9.793 12.582-15.444 8.59-5.726 21.848-5.726 12.054 0 21.02 5.048 8.964 5.047 13.863 14.766 4.971 9.72 4.972 23.732v73.683h-27.273v-69.463q0-11.679-6.027-18.157-5.952-6.555-16.725-6.555-7.233 0-12.959 3.164-5.65 3.09-8.89 8.966-3.165 5.876-3.164 14.239"
              ></path>
            </mask>
            <g mask="url(#mask0_4454_292)">
              <path
                fill="#000"
                d="M15.22 206.001h-2.486v2.486h2.486zM15 51.705l.22-2.486h-2.486v2.486zm87.915 6.178-1.134 2.212.006.003zm18.308 17.328-2.175 1.205.005.008.005.01zm-.075 51.608-2.152-1.247-.002.005zm-18.459 16.8 1.079 2.241.011-.006zm-71.196 5.877h-2.486v2.486h2.486zm0-23.205v-2.486h-2.486v2.486zm54.47-2.863.987 2.283.01-.005.011-.005zm9.795-8.513-2.157-1.237-.005.01zm0-27.876-2.177 1.2.007.012zm-9.87-8.89-1.05 2.254.011.005.01.004zm-42.717-3.09v-2.485h-2.486v2.486zm0 130.942v2.486h2.486v-2.486zm51.758-69.916 2.182-1.192-.707-1.294H94.93zm38.198 69.916v2.486h4.191l-2.009-3.678zm-31.191 0-2.19 1.176.703 1.31h1.487zm-37.52-69.916v-2.486h-4.155l1.965 3.662zm-49.195 69.916H15V51.705h-2.265V206zM15 51.705l58.081 2.486v-4.972h-57.86zm58.081 0v2.486c11.58 0 21.108 2.013 28.702 5.904l1.132-2.212 1.135-2.213c-8.48-4.346-18.84-6.451-30.969-6.451zm29.834 6.178-1.128 2.215c7.676 3.91 13.4 9.348 17.261 16.318l2.175-1.205 2.176-1.205c-4.376-7.897-10.857-14.011-19.354-18.34zm18.308 17.328-2.164 1.222c3.927 6.954 5.932 15.134 5.932 24.619h4.973c0-10.203-2.164-19.251-6.575-27.064zm6.254 25.841h-2.486c0 9.535-2.031 17.678-5.995 24.52l2.152 1.247 2.152 1.246c4.474-7.723 6.664-16.758 6.664-27.013zm-6.329 25.767-2.153-1.242c-3.9 6.766-9.664 12.038-17.394 15.808l1.088 2.234 1.09 2.235c8.543-4.166 15.086-10.095 19.524-17.794zm-18.459 16.8-1.077-2.24c-7.712 3.714-17.315 5.631-28.907 5.631v4.972c12.115 0 22.502-2 31.063-6.122zm-29.984 5.877v-2.486h-41.21v4.972h41.21zm-41.21 0h2.485v-23.205h-4.973v23.205zm0-23.205v2.486h37.443v-4.972H31.493zm37.443 0v2.486c7.133 0 13.175-.978 18.012-3.066l-.985-2.283-.986-2.282c-4.003 1.729-9.31 2.659-16.04 2.659zm17.027-2.863 1.006 2.273c4.84-2.145 8.544-5.319 10.951-9.559l-2.164-1.227-2.162-1.227c-1.813 3.193-4.639 5.695-8.639 7.467zm9.793-8.513 2.158 1.237c2.425-4.23 3.569-9.302 3.569-15.1h-4.974c0 5.153-1.015 9.322-2.91 12.626zM99 101.052h2.486c0-5.8-1.145-10.91-3.555-15.225l-2.17 1.212-2.172 1.212c1.91 3.42 2.923 7.652 2.923 12.801zM95.76 87.039l2.176-1.2c-2.44-4.427-6.154-7.743-11.018-9.953l-1.028 2.263-1.03 2.263c3.976 1.808 6.842 4.42 8.721 7.827zm-9.87-8.89 1.05-2.254c-4.859-2.264-10.954-3.321-18.153-3.321v4.972c6.764 0 12.072 1.002 16.053 2.857zm-17.103-3.09v-2.485H43.171v4.972h25.616zm-25.615 0h-2.486v130.942h4.972V75.061zm0 130.942v-2.486H15.22v4.972h27.951zm51.757-69.916-2.18 1.192 38.197 69.916 2.181-1.192 2.183-1.192-38.199-69.916zm38.198 69.916v-2.486h-31.191v4.972h31.191zm-31.191 0 2.191-1.176-37.52-69.915-2.19 1.175-2.19 1.176 37.52 69.916zm-37.52-69.916v2.487H94.93v-4.973H64.416zm94.367 64.944-1.249 2.149.008.005.008.004zm-19.362-20.644-2.219 1.122.003.005zm0-62.909-2.219-1.121-.003.005zm19.136-21.095 1.3 2.12.01-.006zm49.046-4.143-.852 2.335.011.004.011.004zm16.877 10.547-1.74 1.776.009.009zm11.602 18.232-2.323.886.002.005zm4.219 34.582v2.486h2.486v-2.486zm-94.853 0h-2.486v2.486h2.486zm0-18.383v-2.487h-2.486v2.487zm68.71 0v2.486h2.51l-.024-2.51zm-3.39-13.938-2.191 1.175.006.011zm-9.267-9.719-1.283 2.129.012.007zm-28.403.527 1.326 2.103.009-.006.009-.005zm-9.87 10.548-2.187-1.182-.005.009zm-3.541 14.239-2.486-.024v.024zm3.692 33.376-2.215 1.13.005.009zm10.321 10.999-1.246 2.151.009.006.009.005zm26.294 2.11.808 2.351.017-.006.016-.005zm13.712-13.26.278-2.471-1.936-.217-.674 1.827zm25.465 2.863 2.418.577.653-2.734-2.793-.314zm-9.192 17.629-1.848-1.663-.001.001zm-17.177 11.603.9 2.317.007-.002.008-.003zm-23.958 4.068v-2.486c-11.254 0-20.832-2.336-28.827-6.905l-1.234 2.159-1.233 2.158c8.88 5.075 19.343 7.56 31.294 7.56zm-30.061-7.232 1.249-2.15c-7.962-4.625-14.085-11.145-18.395-19.62l-2.216 1.126-2.216 1.127c4.731 9.305 11.515 16.547 20.329 21.666zm-19.362-20.644 2.218-1.121c-4.311-8.528-6.513-18.651-6.513-30.446h-4.972c0 12.414 2.319 23.336 7.048 32.689zm-6.781-31.567h2.486c0-11.586 2.199-21.639 6.516-30.225l-2.221-1.117-2.222-1.116c-4.723 9.395-7.045 20.237-7.045 32.458zm6.781-31.342 2.218 1.122c4.375-8.653 10.446-15.329 18.218-20.097l-1.3-2.12-1.3-2.12c-8.602 5.278-15.288 12.665-20.055 22.094zm19.136-21.095 1.31 2.114c7.738-4.795 16.888-7.237 27.545-7.237v-4.972c-11.443 0-21.529 2.63-30.164 7.982zm28.855-7.61v2.487c6.859 0 13.299 1.11 19.339 3.315l.852-2.335.853-2.336c-6.617-2.416-13.638-3.616-21.044-3.616zm20.191 3.467-.83 2.343c6.035 2.139 11.351 5.46 15.967 9.98l1.74-1.776 1.739-1.776c-5.128-5.022-11.063-8.733-17.785-11.115zm16.877 10.547-1.731 1.785c4.624 4.483 8.307 10.237 11.01 17.333l2.323-.886 2.323-.885c-2.922-7.671-6.975-14.071-12.195-19.132zm11.602 18.232-2.321.891c2.677 6.979 4.054 15.402 4.054 25.328h4.972c0-10.366-1.435-19.422-4.384-27.109zm4.219 26.219h-2.486v8.363h4.972v-8.363zm0 8.363v-2.487h-94.853v4.973h94.853zm-94.853 0h2.486v-18.383h-4.972v18.383zm0-18.383v2.486h68.71v-4.973h-68.71zm68.71 0 2.486-.024c-.054-5.578-1.264-10.632-3.692-15.101l-2.184 1.187-2.185 1.186c1.992 3.668 3.042 7.906 3.089 12.775zm-3.39-13.938 2.19-1.176c-2.42-4.511-5.825-8.085-10.186-10.68l-1.271 2.137-1.271 2.136c3.574 2.127 6.348 5.032 8.347 8.758zm-9.267-9.719 1.283-2.13c-4.358-2.625-9.385-3.897-14.995-3.897v4.972c4.837 0 8.951 1.089 12.429 3.184zm-13.712-3.541v-2.486c-5.997 0-11.372 1.465-16.036 4.463l1.345 2.091 1.344 2.092c3.774-2.427 8.194-3.674 13.347-3.674zm-14.691 4.068-1.327-2.102c-4.579 2.888-8.166 6.721-10.73 11.468l2.187 1.182 2.188 1.182c2.156-3.993 5.149-7.192 9.008-9.627zm-9.87 10.548-2.192-1.173c-2.51 4.693-3.781 9.837-3.835 15.388l2.486.024 2.486.024c.047-4.795 1.137-9.145 3.247-13.091zm-3.541 14.239h-2.486v16.047h4.972v-16.047zm0 16.047h-2.486c0 7.03 1.285 13.212 3.963 18.459l2.215-1.13 2.214-1.131c-2.244-4.397-3.42-9.766-3.42-16.198zm3.692 17.329-2.21 1.139c2.667 5.172 6.432 9.199 11.285 12.011l1.246-2.151 1.247-2.151c-3.987-2.311-7.104-5.616-9.359-9.988zm10.321 10.999-1.228 2.162c4.853 2.757 10.463 4.092 16.748 4.092v-4.973c-5.568 0-10.304-1.177-14.291-3.442zm15.52 3.767v2.487c4.198 0 8.068-.585 11.582-1.793l-.808-2.351-.808-2.351c-2.915 1.002-6.228 1.522-9.966 1.522zm10.774-1.657.841 2.34c3.515-1.264 6.599-3.118 9.221-5.573l-1.699-1.815-1.699-1.815c-2.1 1.966-4.591 3.476-7.505 4.523zm8.363-5.048 1.699 1.815c2.664-2.494 4.653-5.567 5.982-9.166l-2.332-.861-2.332-.861c-1.082 2.93-2.659 5.332-4.716 7.258zm5.349-8.212-.278 2.471 25.465 2.863.278-2.471.278-2.471-25.465-2.863zm25.465 2.863-2.418-.578c-1.514 6.337-4.386 11.838-8.622 16.544l1.848 1.663 1.848 1.664c4.805-5.339 8.061-11.591 9.762-18.716zm-9.192 17.629-1.849-1.662c-4.183 4.653-9.574 8.314-16.243 10.953l.915 2.312.915 2.312c7.294-2.887 13.354-6.961 18.111-12.252zm-17.177 11.603-.9-2.318c-6.644 2.581-14.315 3.9-23.058 3.9v4.972c9.238 0 17.538-1.393 24.858-4.237zm130.366-83.326.27 2.471 2.672-.291-.499-2.641zm-24.862 2.712-2.394.67.568 2.03 2.095-.228zm-3.692-7.082-1.967 1.52.01.014.011.014zm-31.944-3.692-1.335-2.097-.006.004-.006.004zm-5.651 9.569 2.486.037.001-.035-.001-.034zm3.692 8.212-1.599 1.903.009.008.01.008zm12.657 5.198-.559 2.423.02.004.02.004zm19.739 4.219.524-2.43-.004-.001zm24.41 11.226-1.723 1.791.008.008zm8.137 20.116 2.486.017v-.032zm-6.404 19.287-1.982-1.501-.002.003zm-77.223 8.739-1.415 2.045.008.005zm-15.445-24.937-.238-2.475-2.624.252.405 2.605zm26.595-2.562 2.423-.559-.491-2.125-2.17.209zm38.574 11.828-1.385-2.064-.006.004-.006.004zm2.11-18.081-1.621 1.885.009.008.009.008zm-11.753-4.973.527-2.429-.008-.002-.009-.002zm-19.739-4.143.51-2.434h-.004zm-24.637-11.678-1.79 1.725.008.008zm-7.91-20.945 2.486.015v-.032zm5.801-18.533-1.987-1.495-.002.003zm16.499-12.205.938 2.302.008-.003zm56.505 4.294-1.481 1.997.006.004zm14.541 23.431-.27-2.472-24.862 2.712.27 2.472.269 2.472 24.863-2.713zm-24.862 2.712 2.394-.67c-.8-2.857-2.193-5.512-4.14-7.96l-1.946 1.548-1.946 1.548c1.569 1.972 2.637 4.038 3.244 6.204zm-3.692-7.082 1.967-1.52c-1.985-2.569-4.63-4.585-7.849-6.083l-1.049 2.254-1.049 2.254c2.607 1.214 4.582 2.764 6.013 4.615zm-6.931-5.349 1.049-2.254c-3.328-1.549-7.274-2.266-11.748-2.266v4.972c3.966 0 7.151.639 9.65 1.802zm-10.699-2.034v-2.486c-6.035 0-11.297 1.311-15.649 4.08l1.335 2.097 1.335 2.098c3.383-2.153 7.664-3.303 12.979-3.303zm-14.314 3.691-1.347-2.089c-4.402 2.838-6.853 6.767-6.79 11.689l2.486-.031 2.486-.032c-.037-2.913 1.28-5.363 4.512-7.447zm-5.651 9.569-2.486-.038c-.061 4.09 1.478 7.549 4.579 10.153l1.599-1.903 1.599-1.904c-1.922-1.614-2.844-3.631-2.805-6.271zm3.692 8.212-1.58 1.919c3.011 2.48 7.685 4.319 13.678 5.702l.559-2.423.559-2.422c-5.76-1.33-9.524-2.957-11.635-4.696zm12.657 5.198-.519 2.431 19.739 4.219.519-2.431.52-2.431-19.739-4.219zm19.739 4.219-.524 2.431c10.714 2.309 18.349 5.908 23.211 10.586l1.723-1.791 1.724-1.792c-5.786-5.568-14.425-9.453-25.61-11.864zm24.41 11.226-1.715 1.799c4.827 4.602 7.319 10.633 7.366 18.332l2.486-.015 2.486-.015c-.053-8.876-2.985-16.256-8.907-21.901zm8.137 20.116-2.486-.018c-.047 6.771-2.019 12.675-5.9 17.804l1.982 1.501 1.983 1.5c4.556-6.021 6.854-12.976 6.907-20.77zm-6.404 19.287-1.984-1.498c-3.863 5.12-9.285 9.191-16.38 12.163l.961 2.293.96 2.293c7.772-3.255 13.953-7.824 18.428-13.754zm-17.403 12.958-.961-2.293c-7.076 2.964-15.278 4.478-24.655 4.478v4.972c9.91 0 18.785-1.6 26.576-4.864zm-25.616 4.671v-2.486c-13.835 0-24.696-2.896-32.798-8.454l-1.406 2.05-1.407 2.05c9.176 6.295 21.118 9.326 35.611 9.326zm-34.204-8.89 1.414-2.044c-8.062-5.579-12.847-13.282-14.402-23.276l-2.457.383-2.457.382c1.76 11.302 7.272 20.224 16.487 26.6zm-15.445-24.937.238 2.474 26.595-2.561-.238-2.475-.238-2.475-26.595 2.562zm26.595-2.562-2.422.559c1.326 5.747 4.204 10.265 8.709 13.326l1.398-2.057 1.397-2.056c-3.33-2.263-5.575-5.631-6.659-10.331zm7.685 11.828-1.398 2.057c4.445 3.02 10.075 4.423 16.692 4.423v-4.973c-5.94 0-10.506-1.259-13.897-3.563zm15.294 3.993v2.487c6.799 0 12.536-1.395 16.992-4.423l-1.397-2.057-1.397-2.056c-3.379 2.296-8.039 3.563-14.198 3.563zm15.595-3.993 1.385 2.065c4.484-3.008 7.053-7 7.053-11.934h-4.972c0 2.901-1.399 5.489-4.851 7.805zm5.952-9.869h2.486c0-4.057-1.611-7.487-4.726-10.113l-1.602 1.901-1.603 1.901c2.008 1.693 2.959 3.738 2.959 6.311zm-3.842-8.212 1.621-1.885c-2.966-2.551-7.35-4.325-12.847-5.517l-.527 2.429-.528 2.43c5.151 1.118 8.602 2.659 10.66 4.428zm-11.753-4.973.51-2.433-19.739-4.144-.51 2.434-.511 2.433 19.739 4.144zm-19.739-4.143.506-2.434c-10.836-2.256-18.512-5.992-23.36-10.977l-1.783 1.733-1.782 1.733c5.8 5.964 14.548 10.013 25.912 12.379zm-24.637-11.678 1.791-1.725c-4.827-5.01-7.262-11.344-7.215-19.205l-2.486-.015-2.487-.014c-.053 9.015 2.786 16.644 8.607 22.684zm-7.91-20.945 2.486-.017c-.047-6.642 1.743-12.277 5.304-17.025l-1.989-1.491-1.989-1.492c-4.275 5.699-6.352 12.42-6.298 20.043zm5.801-18.533 1.987 1.495c3.659-4.864 8.771-8.678 15.45-11.398l-.938-2.302-.937-2.303c-7.385 3.007-13.272 7.329-17.549 13.013zm16.499-12.205.946 2.299c6.727-2.767 14.557-4.183 23.54-4.183v-4.972c-9.501 0-17.994 1.497-25.432 4.556zm24.486-4.37v2.486c13.235 0 23.322 2.82 30.538 8.175l1.481-1.997 1.482-1.997c-8.355-6.198-19.614-9.153-33.501-9.153zm32.019 8.664-1.475 2c7.314 5.393 11.827 12.645 13.573 21.892l2.443-.461 2.443-.461c-1.971-10.442-7.151-18.811-15.508-24.971zm49.018 103.593-1.249 2.149.008.005.008.004zm-19.362-20.644-2.219 1.122.002.005zm0-62.909-2.219-1.121-.003.005zm19.136-21.095 1.3 2.12.01-.006zm49.046-4.143-.852 2.335.011.004.011.004zm16.877 10.547-1.74 1.776.009.009zm11.602 18.232-2.323.886.002.005zm4.219 34.582v2.486h2.486v-2.486zm-94.853 0h-2.486v2.486h2.486zm0-18.383v-2.487h-2.486v2.487zm68.71 0v2.486h2.51l-.024-2.51zm-3.39-13.938-2.191 1.175.006.011zm-9.267-9.719-1.283 2.129.012.007zm-28.403.527 1.326 2.103.009-.006.009-.005zm-9.87 10.548-2.187-1.182-.005.009zm-3.541 14.239-2.486-.024v.024zm3.692 33.376-2.215 1.13.005.009zm10.321 10.999-1.246 2.151.009.006.009.005zm26.294 2.11.808 2.351.017-.006.016-.005zm13.712-13.26.278-2.471-1.936-.217-.674 1.827zm25.465 2.863 2.418.577.653-2.734-2.793-.314zm-9.192 17.629-1.848-1.663-.001.001zm-17.177 11.603.9 2.317.007-.002.008-.003zm-23.958 4.068v-2.486c-11.254 0-20.832-2.336-28.827-6.905l-1.234 2.159-1.233 2.158c8.88 5.075 19.343 7.56 31.294 7.56zm-30.061-7.232 1.249-2.15c-7.962-4.625-14.085-11.145-18.395-19.62l-2.216 1.126-2.217 1.127c4.732 9.305 11.516 16.547 20.33 21.666zm-19.362-20.644 2.218-1.121c-4.311-8.528-6.513-18.651-6.513-30.446h-4.972c0 12.414 2.319 23.336 7.048 32.689zm-6.781-31.567h2.486c0-11.586 2.199-21.639 6.516-30.225l-2.221-1.117-2.222-1.116c-4.723 9.395-7.045 20.237-7.045 32.458zm6.781-31.342 2.218 1.122c4.375-8.653 10.446-15.329 18.218-20.097l-1.3-2.12-1.3-2.12c-8.602 5.278-15.289 12.665-20.055 22.094zm19.136-21.095 1.31 2.114c7.738-4.795 16.888-7.237 27.545-7.237v-4.972c-11.443 0-21.529 2.63-30.165 7.982zm28.855-7.61v2.487c6.859 0 13.299 1.11 19.339 3.315l.852-2.335.853-2.336c-6.618-2.416-13.638-3.616-21.044-3.616zm20.191 3.467-.83 2.343c6.035 2.139 11.351 5.46 15.967 9.98l1.74-1.776 1.739-1.776c-5.128-5.022-11.063-8.733-17.785-11.115zm16.877 10.547-1.731 1.785c4.624 4.483 8.307 10.237 11.01 17.333l2.323-.886 2.323-.885c-2.922-7.671-6.975-14.071-12.195-19.132zm11.602 18.232-2.321.891c2.677 6.979 4.054 15.402 4.054 25.328h4.972c0-10.366-1.435-19.422-4.384-27.109zm4.219 26.219h-2.486v8.363h4.972v-8.363zm0 8.363v-2.487H364.31v4.973h94.853zm-94.853 0h2.486v-18.383h-4.972v18.383zm0-18.383v2.486h68.71v-4.973h-68.71zm68.71 0 2.486-.024c-.054-5.578-1.264-10.632-3.692-15.101l-2.184 1.187-2.185 1.186c1.992 3.668 3.042 7.906 3.089 12.775zm-3.39-13.938 2.19-1.176c-2.42-4.511-5.825-8.085-10.186-10.68l-1.271 2.137-1.271 2.136c3.574 2.127 6.348 5.032 8.347 8.758zm-9.267-9.719 1.283-2.13c-4.358-2.625-9.385-3.897-14.995-3.897v4.972c4.837 0 8.951 1.089 12.429 3.184zm-13.712-3.541v-2.486c-5.997 0-11.372 1.465-16.036 4.463l1.345 2.091 1.344 2.092c3.774-2.427 8.193-3.674 13.347-3.674zm-14.691 4.068-1.327-2.102c-4.579 2.888-8.166 6.721-10.73 11.468l2.187 1.182 2.188 1.182c2.156-3.993 5.149-7.192 9.008-9.627zm-9.87 10.548-2.192-1.173c-2.51 4.693-3.781 9.837-3.835 15.388l2.486.024 2.486.024c.047-4.795 1.137-9.145 3.247-13.091zm-3.541 14.239h-2.486v16.047h4.972v-16.047zm0 16.047h-2.486c0 7.03 1.285 13.212 3.963 18.459l2.215-1.13 2.214-1.131c-2.244-4.397-3.42-9.766-3.42-16.198zm3.692 17.329-2.21 1.139c2.667 5.172 6.432 9.199 11.285 12.011l1.246-2.151 1.247-2.151c-3.987-2.311-7.104-5.616-9.359-9.988zm10.321 10.999-1.228 2.162c4.852 2.757 10.463 4.092 16.748 4.092v-4.973c-5.568 0-10.304-1.177-14.291-3.442zm15.52 3.767v2.487c4.198 0 8.068-.585 11.582-1.793l-.808-2.351-.808-2.351c-2.915 1.002-6.228 1.522-9.966 1.522zm10.774-1.657.841 2.34c3.515-1.264 6.599-3.118 9.221-5.573l-1.699-1.815-1.699-1.815c-2.1 1.966-4.591 3.476-7.505 4.523zm8.363-5.048 1.699 1.815c2.664-2.494 4.653-5.567 5.982-9.166l-2.332-.861-2.332-.861c-1.082 2.93-2.659 5.332-4.716 7.258zm5.349-8.212-.278 2.471 25.465 2.863.278-2.471.278-2.471-25.465-2.863zm25.465 2.863-2.418-.578c-1.514 6.337-4.386 11.838-8.622 16.544l1.848 1.663 1.848 1.664c4.805-5.339 8.061-11.591 9.762-18.716zm-9.192 17.629-1.849-1.662c-4.183 4.653-9.575 8.314-16.243 10.953l.915 2.312.915 2.312c7.294-2.887 13.354-6.961 18.111-12.252zm-17.177 11.603-.901-2.318c-6.643 2.581-14.315 3.9-23.057 3.9v4.972c9.238 0 17.538-1.393 24.858-4.237zm43.668-88.449-2.242-1.077-.002.006zm17.252-20.116 1.318 2.108.011-.006zm40.91-3.39-1.162 2.198.01.005.01.005zm10.397 8.212-1.944 1.549.006.008.006.007zm5.952 8.965-2.224 1.112.687 1.374h1.537zm1.13 0v2.486h2.486v-2.486zm0-19.136V87.79h-2.486v2.487zm27.348 0h2.487V87.79h-2.487zm0 115.722v2.486h2.487v-2.486zm-26.821 0h-2.486v2.486h2.486zm0-18.232h2.487v-2.486H551.5zm-1.657 0v-2.486h-1.537l-.687 1.374zm-6.103 8.965 1.89 1.616.007-.008.006-.007zm-4.671-15.746 1.511 1.974.008-.005.008-.006zm9.267-52.361-2.33.868.004.009.003.01zm-9.191-12.883-1.508 1.977.006.004.006.005zm-39.253 51.758-2.337.848.005.013.005.012zm9.267 13.335-1.556 1.94.013.01.014.01zm7.534 27.198v-2.486c-8.64 0-16.3-2.212-23.054-6.605l-1.356 2.085-1.355 2.084c7.611 4.95 16.224 7.408 25.765 7.408zm-24.41-7.006 1.356-2.085c-6.74-4.383-12.13-10.78-16.132-19.313l-2.251 1.056-2.251 1.055c4.336 9.247 10.297 16.412 17.923 21.371zm-17.027-20.342 2.251-1.056c-3.975-8.477-6.018-18.895-6.018-31.34h-4.972c0 12.969 2.126 24.149 6.488 33.451zm-6.253-32.396h2.486c0-12.599 2.069-23.058 6.086-31.476l-2.243-1.071-2.244-1.071c-4.421 9.262-6.571 20.5-6.571 33.618zm6.329-32.547 2.241 1.076c4.098-8.533 9.555-14.85 16.329-19.084l-1.318-2.108-1.317-2.108c-7.692 4.807-13.736 11.901-18.177 21.147zm17.252-20.116 1.329 2.102c6.819-4.31 14.416-6.472 22.856-6.472v-4.972c-9.341 0-17.867 2.408-25.513 7.24zm24.185-6.856v2.486c6.518 0 11.66 1.115 15.563 3.178l1.162-2.198 1.162-2.198c-4.836-2.557-10.845-3.754-17.887-3.754zm16.725 3.466-1.142 2.208c4.119 2.13 7.29 4.66 9.595 7.553l1.944-1.549 1.944-1.55c-2.818-3.536-6.578-6.48-11.199-8.87zm10.397 8.212-1.932 1.564c2.479 3.063 4.354 5.9 5.66 8.513l2.224-1.112 2.224-1.112c-1.507-3.012-3.6-6.152-6.244-9.418zm5.952 8.965v2.486h1.13v-4.972h-1.13zm1.13 0h2.486V90.279l-4.972-.001v19.137zm0-19.136v2.486h27.348V87.79h-27.348zm27.348 0h-2.486V206h4.973V90.279zm0 115.722v-2.486H551.5v4.972h26.821zm-26.821 0h2.487v-18.232h-4.973v18.232zm0-18.232v-2.486h-1.657v4.972h1.657zm-1.657 0-2.224-1.112c-1.296 2.593-3.208 5.418-5.781 8.477l1.902 1.6 1.903 1.601c2.751-3.27 4.907-6.422 6.424-9.454zm-6.103 8.965-1.889-1.615c-2.412 2.82-5.648 5.293-9.78 7.383l1.122 2.218 1.122 2.219c4.607-2.33 8.402-5.182 11.315-8.589zm-10.547 7.986-1.122-2.218c-3.921 1.983-9.006 3.047-15.378 3.047v4.972c6.889 0 12.803-1.145 17.622-3.582zm-8.89-19.061v2.486c6.249 0 11.721-1.695 16.277-5.183l-1.511-1.974-1.511-1.974c-3.58 2.74-7.952 4.159-13.255 4.159zm14.766-4.671 1.527 1.963c4.487-3.491 7.824-8.291 10.068-14.274l-2.328-.873-2.328-.873c-1.975 5.267-4.816 9.256-8.465 12.095zm9.267-13.184 2.328.873c2.236-5.964 3.323-12.826 3.323-20.537h-4.973c0 7.256-1.023 13.504-3.006 18.791zm3.164-19.664h2.487c0-7.71-1.086-14.528-3.328-20.4l-2.323.887-2.323.887c1.977 5.177 3.001 11.368 3.001 18.626zm-3.164-19.513 2.33-.869c-2.199-5.897-5.522-10.608-10.026-14l-1.495 1.986-1.496 1.986c3.633 2.735 6.437 6.613 8.357 11.765zm-9.191-12.883 1.507-1.977c-4.519-3.446-10.021-5.105-16.349-5.105v4.972c5.424 0 9.817 1.405 13.334 4.087zm-14.842-4.596v-2.486c-6.528 0-12.166 1.708-16.745 5.27l1.526 1.962 1.526 1.963c3.557-2.767 8.065-4.223 13.693-4.223zm-15.219 4.746-1.526-1.962c-4.488 3.49-7.803 8.268-9.998 14.21l2.332.862 2.333.861c1.923-5.208 4.736-9.17 8.385-12.008zm-9.192 13.11-2.332-.862c-2.18 5.902-3.243 12.581-3.243 19.998h4.973c0-6.948.996-13.026 2.935-18.275zm-3.088 19.136h-2.487c0 7.466 1.063 14.215 3.238 20.21l2.337-.848 2.338-.848c-1.944-5.356-2.94-11.515-2.94-18.514zm3.088 19.362-2.327.873c2.242 5.979 5.571 10.817 10.038 14.402l1.556-1.94 1.556-1.939c-3.67-2.945-6.518-6.997-8.495-12.269zm9.267 13.335-1.529 1.96c4.617 3.604 10.225 5.348 16.673 5.348v-4.972c-5.507 0-9.994-1.47-13.614-4.295zm83.374 25.164h-2.486v2.486h2.486zm0-115.722V87.79h-2.486v2.487zm26.444 0h2.486V87.79h-2.486zm0 19.287h-2.486v2.486h2.486zm1.206 0v2.486h1.822l.548-1.738zm10.849-15.445 1.433 2.03.007-.003.006-.005zm33.224-1.28 2.33.869.697-1.868-1.672-1.086zm-8.438 22.601-1.08 2.239 2.456 1.186.954-2.555zm-32.697 9.569-2.132-1.28-.005.009zm-3.315 80.99v2.486h2.486v-2.486zm-27.273 0h2.486V90.279l-4.972-.001V206zm0-115.722v2.486h26.444V87.79h-26.444zm26.444 0h-2.486v19.287h4.972V90.279zm0 19.287v2.486h1.206v-4.972h-1.206zm1.206 0 2.37.748c1.966-6.225 5.285-10.895 9.912-14.162l-1.433-2.031-1.434-2.031c-5.619 3.966-9.533 9.592-11.786 16.727zm10.849-15.445 1.446 2.022c4.675-3.346 10.064-5.035 16.258-5.035v-4.973c-7.165 0-13.58 1.977-19.151 5.964zm17.704-5.5v2.487c2.915 0 5.542.352 7.9 1.032l.689-2.39.689-2.387c-2.865-.827-5.964-1.228-9.278-1.228zm8.589 1.13-.689 2.389c2.407.694 4.488 1.629 6.266 2.785l1.354-2.084 1.355-2.085c-2.24-1.456-4.78-2.581-7.597-3.393zm6.931 3.09-2.329-.87-8.438 22.602 2.329.869 2.33.87 8.438-22.602zm-8.438 22.601 1.081-2.239c-1.621-.782-3.385-1.413-5.283-1.901l-.619 2.407-.62 2.408c1.618.416 3.069.941 4.361 1.564zm-4.821-1.733.619-2.407c-1.999-.514-4.196-.757-6.571-.757v4.973c2.044 0 3.815.209 5.332.599zm-5.952-.678v-2.486c-5.106 0-9.795 1.145-14.011 3.475l1.203 2.176 1.203 2.176c3.419-1.89 7.268-2.854 11.605-2.854zm-12.808 3.165-1.203-2.176c-4.203 2.323-7.561 5.572-10.045 9.711l2.132 1.28 2.132 1.279c2.036-3.395 4.756-6.022 8.187-7.918zm-9.116 8.815-2.137-1.271c-2.469 4.152-3.664 8.923-3.664 14.229h4.972c0-4.538 1.015-8.406 2.966-11.688zm-3.315 12.958h-2.486v68.032h4.972v-68.032zm0 68.032v-2.486h-27.273v4.972h27.273zm64.883-5.349-1.304 2.117.006.003zm-19.061-21.02-2.232 1.097.004.007.004.008zm.15-62.156 2.222 1.117.002-.005zm19.137-21.095 1.294 2.123.004-.002zm54.32-2.41-1.075 2.242.01.004.009.004zm17.403 14.54-2.048 1.409.005.008zm7.384 21.849v2.486h2.672l-.193-2.666zm-26.068 0-2.443.462.383 2.024h2.06zm-7.534-13.938-1.723 1.792.012.011.011.011zm-30.437-1.13 1.429 2.034.008-.006.008-.005zm-9.87 12.807-2.289-.969-.004.009-.004.009zm0 40.383-2.303.937.003.007zm9.719 13.033-1.472 2.004.013.01.014.01zm25.616 2.261 1.069 2.244.007-.003.007-.004zm12.506-17.329v-2.486h-2.053l-.388 2.016zm26.068 0 2.478.198.214-2.684h-2.692zm-7.233 21.774 2.071 1.375.005-.008zm-17.027 14.766 1.093 2.233.013-.006zm-25.314 5.274v-2.486c-11.181 0-20.633-2.452-28.461-7.244l-1.298 2.121-1.298 2.12c8.746 5.354 19.134 7.975 31.057 7.975zm-29.759-7.609 1.303-2.117c-7.829-4.822-13.87-11.474-18.141-20.015l-2.223 1.112-2.224 1.112c4.67 9.34 11.336 16.701 19.981 22.025zm-19.061-21.02 2.231-1.097c-4.226-8.596-6.375-18.557-6.375-29.943h-4.972c0 12.019 2.271 22.752 6.884 32.137zm-6.63-31.04h2.486c0-11.43 2.196-21.408 6.516-29.999l-2.222-1.117-2.221-1.116c-4.722 9.391-7.045 20.156-7.045 32.232zm6.78-31.116 2.224 1.112c4.322-8.644 10.388-15.316 18.207-20.084l-1.294-2.123-1.295-2.122c-8.655 5.277-15.347 12.668-20.065 22.106zm19.137-21.095 1.298 2.12c7.836-4.795 17.166-7.243 28.084-7.243v-4.972c-11.683 0-21.942 2.626-30.68 7.975zm29.382-7.61v2.487c9.084 0 17.019 1.676 23.863 4.955l1.075-2.242 1.074-2.243c-7.621-3.651-16.311-5.442-26.012-5.442zm24.938 5.2-1.056 2.25c6.906 3.24 12.356 7.805 16.411 13.699l2.048-1.409 2.049-1.409c-4.584-6.663-10.737-11.79-18.397-15.383zm17.403 14.54-2.043 1.417c4.04 5.825 6.373 12.67 6.947 20.611l2.48-.179 2.479-.18c-.631-8.734-3.221-16.455-7.82-23.086zm7.384 21.849v-2.487h-26.068v4.973h26.068zm-26.068 0 2.443-.463c-1.148-6.069-3.907-11.196-8.277-15.29l-1.7 1.815-1.7 1.814c3.566 3.34 5.83 7.505 6.791 12.586zm-7.534-13.938 1.723-1.792c-4.475-4.303-10.39-6.345-17.469-6.345v4.972c6.081 0 10.662 1.726 14.023 4.957zm-15.746-5.651v-2.486c-6.052 0-11.463 1.646-16.136 4.984l1.445 2.023 1.445 2.023c3.765-2.69 8.148-4.058 13.246-4.058zm-14.691 4.521-1.429-2.035c-4.662 3.275-8.22 7.945-10.73 13.873l2.289.969 2.29.97c2.211-5.223 5.233-9.091 9.009-11.743zm-9.87 12.807-2.297-.951c-2.466 5.95-3.655 12.971-3.655 20.992h4.973c0-7.549 1.121-13.889 3.276-19.089zm-3.465 20.041h-2.487c0 8.119 1.189 15.234 3.649 21.279l2.303-.937 2.303-.938c-2.16-5.306-3.282-11.752-3.282-19.404zm3.465 20.342-2.3.944c2.453 5.973 5.95 10.714 10.547 14.093l1.472-2.004 1.472-2.003c-3.74-2.749-6.723-6.697-8.891-11.975zm9.719 13.033-1.445 2.024c4.681 3.343 10.145 4.983 16.287 4.983v-4.972c-5.209 0-9.64-1.374-13.397-4.058zm14.842 4.521v2.486c4.334 0 8.299-.814 11.843-2.502l-1.069-2.244-1.069-2.245c-2.785 1.326-6.003 2.019-9.705 2.019zm10.774-2.26 1.083 2.237c3.582-1.734 6.58-4.232 8.975-7.462l-1.997-1.481-1.997-1.48c-1.925 2.596-4.3 4.569-7.148 5.948zm8.061-6.706 1.997 1.481c2.417-3.259 4.027-7.16 4.889-11.633l-2.441-.471-2.441-.47c-.745 3.865-2.098 7.046-4.001 9.613zm4.445-10.623v2.487h26.068v-4.973h-26.068zm26.068 0-2.479-.197c-.622 7.805-2.911 14.653-6.83 20.603l2.076 1.368 2.076 1.367c4.419-6.707 6.952-14.374 7.635-22.943zm-7.233 21.774-2.071-1.376c-3.912 5.892-9.244 10.531-16.061 13.916l1.105 2.226 1.106 2.227c7.547-3.747 13.566-8.953 17.992-15.618zm-17.027 14.766-1.093-2.233c-6.777 3.318-14.827 5.021-24.221 5.021v4.972c9.993 0 18.82-1.812 26.407-5.527zm63.32 3.014v2.486h2.486v-2.486zm-27.273 0h-2.487v2.486h2.487zm0-154.296v-2.486h-2.487v2.486zm26.67 0h2.486v-2.486h-2.486zm0 58.237h-2.486v2.487h2.486zm1.356 0v2.487h1.66l.636-1.533zm12.582-15.444 1.375 2.07.004-.001zm56.731 14.088-2.22 1.119.003.007.004.007zm4.972 97.415v2.486h2.487v-2.486zm-27.273 0h-2.486v2.486h2.486zm-6.027-87.62-1.841 1.671.01.011.011.011zm-29.684-3.391 1.193 2.182.01-.006zm-8.89 8.966-2.177-1.201-.006.011-.006.011zm-3.164 14.239h-2.487v67.806h4.973v-67.806zm0 67.806v-2.486h-27.273v4.972h27.273zm-27.273 0h2.486V51.705h-4.973V206zm0-154.296v2.486h26.67v-4.972h-26.67zm26.67 0h-2.486v58.237h4.972V51.705zm0 58.237v2.487h1.356v-4.973h-1.356zm1.356 0 2.296.954c2.531-6.092 6.413-10.843 11.661-14.327l-1.375-2.071-1.375-2.072c-6.103 4.05-10.609 9.596-13.503 16.563zm12.582-15.444 1.379 2.069c5.216-3.478 11.982-5.31 20.469-5.31v-4.971c-9.192 0-16.991 1.986-23.227 6.143zm21.848-5.726v2.486c7.683 0 14.255 1.606 19.801 4.728l1.219-2.166 1.22-2.167c-6.409-3.608-13.85-5.367-22.24-5.367zm21.02 5.048-1.219 2.166c5.521 3.109 9.805 7.654 12.862 13.719l2.22-1.119 2.22-1.118c-3.473-6.894-8.43-12.193-14.863-15.815zm13.863 14.766-2.213 1.133c3.092 6.043 4.699 13.543 4.699 22.599h4.973c0-9.627-1.708-17.949-5.246-24.864zm4.972 23.732h-2.486v73.683h4.973v-73.683zm0 73.683v-2.486h-27.273v4.972h27.273zm-27.273 0h2.486v-69.463h-4.972v69.463zm0-69.463h2.486c0-8.208-2.124-14.94-6.693-19.851l-1.82 1.694-1.82 1.693c3.468 3.728 5.361 9.101 5.361 16.464zm-6.027-18.157 1.841-1.672c-4.54-4.999-10.848-7.369-18.566-7.369v4.972c6.646 0 11.488 2 14.884 5.74zm-16.725-6.555v-2.486c-5.197 0-9.938 1.14-14.161 3.474l1.202 2.176 1.203 2.176c3.411-1.885 7.309-2.854 11.756-2.854zm-12.959 3.164-1.192-2.181c-4.2 2.296-7.497 5.633-9.875 9.946l2.177 1.201 2.177 1.2c1.942-3.522 4.571-6.162 7.906-7.984zm-8.89 8.966-2.189-1.179c-2.348 4.36-3.462 9.534-3.462 15.418h4.973c0-5.266.996-9.586 2.867-13.061z"
              ></path>
            </g>
          </svg>
        </div>
        <div className="absolute top-0 left-0 w-36 h-full bg-gradient-to-r from-white via-10% via-white to-transparent z-[1] hidden 2xl:block"></div>
        <div className="absolute top-0 right-0 w-36 h-full bg-gradient-to-l from-white via-10% via-white to-transparent z-[1] hidden 2xl:block"></div>

        <div className="relative border-y">
          <div className="mx-auto max-w-7xl z-[0]">
            <section
              aria-labelledby="hero-heading"
              className="text-center relative grid grid-cols-1 md:grid-cols-2 border-x"
            >
              <div className="md:border-r aspect-[16/12] overflow-hidden relative p-8 flex items-center justify-between border-b sm:border-b-0">
                <span className="transition-all inline-flex items-center w-full h-full absolute top-12 left-[850px] text-black">
                  {Array(180)
                    .fill(0)
                    .map((_, i) => (
                      <div
                        key={`bottom-${i}`}
                        className="h-[200%] w-px bg-neutral-200 dark:bg-neutral-800 -ml-1 -mr-1 rotate-45"
                      ></div>
                    ))}
                </span>

                <a
                  target="_blank"
                  href="https://docs.google.com/presentation/d/1vC-smwntEnyBO1tNOdMEPg4y0lKs61Wp2Vyhswu2kwU/edit?usp=sharing"
                >
                  <div className="relative p-2 rounded-[32px] bg-white border  shadow-sm">
                    <Image
                      alt="Screenshot showing the massive library of content available to practice with"
                      src="/images/interspeech.png"
                      className="h-full aspect-video object-cover object-top rounded-3xl border bg-white border-black/10"
                      width={556}
                      height={313}
                    />
                  </div>
                </a>
              </div>
              <div className="">
                <div className="relative flex flex-col justify-between h-full overflow-hidden">
                  <div className="p-6 text-left">
                    <h2 className="text-xl sm:text-xl lg:text-2xl max-w-full text-balance font-medium tracking-tight text-neutral-950">
                      Speak Like The Stars: Pronunciation Mastery Through Movies.
                    </h2>

                    <div className="flex flex-col gap-1 justify-start mt-4 items-start text-left">
                      <p className="text-neutral-600">Interspeech Conference Science Fair</p>
                      <time dateTime="2025-08-20" className="text-neutral-600">
                        August 20, 2025
                      </time>
                    </div>
                  </div>
                  <div className="p-6 w-full text-left flex justify-start">
                    <p className="mt-2 max-w-lg text-sm/6 text-neutral-600 w-full text-balance">
                      We presented our work on making speech pathology more accessible, insights and
                      statistics into our latest phonetic model, and a demo of our work-in-progress
                      pronunciation platform.
                    </p>
                  </div>
                </div>
              </div>
            </section>
          </div>
        </div>
        <div className="max-w-7xl border-x h-12 w-full mx-auto"></div>
        <div className="relative border-y">
          <div className="mx-auto max-w-7xl z-[0]">
            <section
              aria-labelledby="hero-heading"
              className="text-center relative grid grid-cols-1 md:grid-cols-2 border-x"
            >
              <div className="md:border-r">
                <div className="relative flex flex-col justify-between h-full overflow-hidden">
                  <div className="p-6 text-left">
                    <h2 className="text-xl sm:text-xl lg:text-2xl max-w-[400px] mr-auto font-medium tracking-tight text-neutral-950">
                      Speech Technology Built for Everyone, Everywhere.
                    </h2>

                    <div className="flex flex-col gap-1 justify-start mt-4 items-start text-left">
                      <div className="flex flex-col justify-center align-baseline sm:items-center gap-1 grayscale text-left">
                        <p className="text-neutral-600">
                          University of Washington Research Symposium
                        </p>

                        <time dateTime="2025-05-16" className="text-neutral-600 mr-auto">
                          May 16, 2025
                        </time>
                      </div>
                    </div>
                  </div>
                  <div className="p-6 w-full text-left flex justify-start">
                    <p className="mt-2 max-w-lg text-sm/6 text-neutral-600 text-balance">
                      We presented our work on making speech pathology more accessible, insights and
                      statistics into our latest phonetic model, and a demo of our work-in-progress
                      pronunciation platform.
                    </p>
                  </div>
                </div>
              </div>
              <div className="aspect-[16/12] overflow-hidden relative p-8 flex items-center justify-between border-t sm:border-t-0">
                <span className="transition-all inline-flex items-center w-full h-full absolute top-12 left-[850px] text-black">
                  {Array(180)
                    .fill(0)
                    .map((_, i) => (
                      <div
                        key={`bottom-${i}`}
                        className="h-[200%] w-px bg-neutral-200 dark:bg-neutral-800 -ml-1 -mr-1 rotate-45"
                      ></div>
                    ))}
                </span>
                <a
                  target="_blank"
                  href="https://docs.google.com/presentation/d/19v1o8X_8QxV-W1kG4dt7m1ltAXbYasK_f4srhnypF8E/edit?usp=sharing"
                >
                  <div className="relative p-2 rounded-[32px] bg-white border  shadow-sm">
                    <Image
                      alt="Screenshot showing the massive library of content available to practice with"
                      src="/images/UofW.png"
                      className="h-full aspect-video object-cover object-top rounded-3xl border bg-white border-black/10"
                      width={556}
                      height={313}
                    />
                  </div>
                </a>
              </div>
            </section>
          </div>
        </div>

        <div className="overflow-hidden border mt-12 mb-24 py-24 sm:py-32">
          <div className="mx-auto max-w-7xl p-6 md:p-0">
            <div className="mx-auto grid max-w-2xl grid-cols-1 gap-y-16 sm:gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-2">
              <div className="lg:ml-auto lg:pl-4 lg:pt-4">
                <div className="lg:max-w-2xl lg:mt-12">
                  <p className="text-lg font-semibold text-sky-600 mb-2">
                    Research and Collaboration
                  </p>
                  <h2 className="text-pretty text-4xl font-semibold tracking-tight text-neutral-900 sm:text-5xl">
                    Our Way Forward
                  </h2>
                  <p className="mt-6 text-lg/8 text-neutral-600">
                    Driven by a commitment to collaborative science, we advance open-source research
                    in language technologies while building practical, engaging solutions. This
                    dedication stems from a core belief: transformative innovation builds upon
                    collective knowledge.
                  </p>

                  <p className="mt-6 text-lg/8 text-neutral-600">
                    Through open-source contributions, our organization accelerates progress in
                    linguistic technology, shaping a future where language learning knows no bounds.
                  </p>

                  <p className="mt-6 text-lg/8 text-neutral-600">
                    We work with linguists, natural-language processing researchers, and research
                    labs worldwide. If you're interested in our work, please contact us to explore
                    collaboration opportunities!
                  </p>
                </div>
              </div>
              <div className="flex items-start justify-end lg:order-first sm:mr-8 mr-0">
                <div className="w-full relative h-full bg-white/50 border border-neutral-200/50 rounded-[32px] p-2">
                  <Image
                    alt="A photo of the Koel Labs founders, Alexander Metzger, Aruna Srivastava, and Ruslan Mukhamedvaleev standing in front of the bay bridge in San Francisco."
                    src="/images/research.png"
                    width={590}
                    height={590}
                    className="w-full h-full rounded-[26px] object-cover object-right lg:max-w-none xl:row-span-2 opacity-100 bg-white xl:row-end-2 aspect-square border"
                  />
                </div>
              </div>
            </div>
          </div>
        </div>

        <div className="z-[3] bg-white">
          <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
            <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
              {Array(500)
                .fill(0)
                .map((_, i) => (
                  <div
                    key={`bottom-${i}`}
                    className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                  ></div>
                ))}
            </div>
          </div>
          <CTA />
          <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
            <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
              {Array(500)
                .fill(0)
                .map((_, i) => (
                  <div
                    key={`bottom-${i}`}
                    className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                  ></div>
                ))}
            </div>
          </div>
        </div>
        <Footer />
      </div>
    </div>
  );
}



================================================
FILE: app/research/[slug]/page.tsx
================================================
'use server';
import React from 'react';
import CTA from '@/components/sections/cta';
import Footer from '@/components/sections/footer';
import Header from '@/components/ui/header';
import { notFound } from 'next/navigation';

export default async function ResearchPage() {
  return notFound();

  const page = (
    <div className="flex-col flex w-screen relative scroll-smooth">
      <div className="z-2 sticky top-0 mx-auto w-full">
        <Header />
      </div>
      <div className="flex-col flex w-screen relative scroll-smooth z-0">
        <div className="absolute top-0 left-0 w-full h-36 bg-gradient-to-b from-white via-10% via-white to-transparent z-[0]"></div>
        <div className="mx-auto max-w-7xl border-x w-full h-64 flex flex-col justify-end items-start">
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="2037"
            height="257"
            fill="none"
            viewBox="0 0 2037 257"
            className="h-24 w-[1024px] -ml-27 mb-3"
          >
            <path
              fill="#000"
              d="M975.811 208.033q-13.637 0-24.41-7.006-10.774-7.008-17.027-20.342-6.253-13.335-6.253-32.396 0-19.287 6.328-32.547 6.404-13.336 17.253-20.116 10.85-6.855 24.184-6.856 10.171 0 16.726 3.466 6.557 3.39 10.398 8.212c2.56 3.164 4.55 6.152 5.95 8.965h1.13V90.277h27.35V206h-26.82v-18.232h-1.66c-1.4 2.812-3.44 5.801-6.1 8.965q-3.992 4.671-10.55 7.986-6.554 3.315-16.499 3.315m7.609-22.376q8.664 0 14.767-4.671 6.109-4.746 9.273-13.184c2.11-5.626 3.16-12.18 3.16-19.664s-1.05-13.988-3.16-19.513c-2.06-5.525-5.13-9.819-9.198-12.883q-6.027-4.596-14.842-4.596-9.116 0-15.218 4.746t-9.192 13.11q-3.088 8.363-3.089 19.136 0 10.85 3.089 19.362 3.165 8.439 9.267 13.335 6.178 4.822 15.143 4.822m128.14-95.38v21.095h-66.53V90.277zm-50.1-27.725h27.27v108.64c0 3.666.55 6.479 1.66 8.438 1.15 1.909 2.66 3.215 4.52 3.918q2.79 1.054 6.18 1.054c1.71 0 3.26-.125 4.67-.376 1.46-.251 2.56-.477 3.31-.678l4.6 21.321c-1.46.502-3.54 1.055-6.25 1.657-2.67.603-5.93.955-9.8 1.055-6.83.201-12.98-.829-18.46-3.089-5.47-2.31-9.82-5.876-13.03-10.698-3.16-4.822-4.72-10.849-4.67-18.082zM1162.74 206V51.703h27.95v70.895h1.89l60.19-70.895h34.13l-59.67 69.237 60.2 85.059h-33.6l-46.04-66.149-17.1 20.192v45.957zm171.63 2.26c-11.3 0-21.1-2.486-29.38-7.458q-12.435-7.459-19.29-20.87-6.78-13.41-6.78-31.341 0-17.93 6.78-31.417 6.855-13.486 19.29-20.944c8.28-4.973 18.08-7.459 29.38-7.459s21.09 2.486 29.38 7.46c8.29 4.972 14.69 11.953 19.21 20.943 4.57 8.991 6.86 19.463 6.86 31.417s-2.29 22.401-6.86 31.341c-4.52 8.941-10.92 15.897-19.21 20.87-8.29 4.972-18.08 7.458-29.38 7.458m.15-21.848c6.13 0 11.25-1.683 15.37-5.048 4.12-3.416 7.18-7.986 9.19-13.712q3.09-8.59 3.09-19.136 0-10.623-3.09-19.212c-2.01-5.776-5.07-10.372-9.19-13.787s-9.24-5.123-15.37-5.123c-6.28 0-11.5 1.707-15.67 5.123q-6.18 5.123-9.27 13.787c-2.01 5.726-3.01 12.13-3.01 19.212 0 7.031 1 13.41 3.01 19.136q3.09 8.59 9.27 13.712c4.17 3.365 9.39 5.048 15.67 5.048m116.95 21.848q-17.4 0-30.06-7.232c-8.39-4.872-14.84-11.753-19.36-20.644-4.53-8.94-6.79-19.462-6.79-31.567 0-11.904 2.26-22.351 6.79-31.342 4.57-9.04 10.94-16.072 19.13-21.095q12.285-7.61 28.86-7.609 10.695 0 20.19 3.466c6.38 2.26 12 5.776 16.87 10.547 4.93 4.772 8.79 10.849 11.61 18.232 2.81 7.334 4.22 16.073 4.22 26.219v8.363h-94.86v-18.383h68.71q-.075-7.836-3.39-13.938c-2.21-4.119-5.3-7.359-9.26-9.719-3.92-2.361-8.49-3.541-13.72-3.541-5.57 0-10.47 1.356-14.69 4.068q-6.33 3.993-9.87 10.548-3.465 6.479-3.54 14.239v16.047q0 10.096 3.69 17.329 3.69 7.157 10.32 10.999c4.42 2.512 9.6 3.767 15.52 3.767 3.97 0 7.56-.552 10.78-1.657 3.21-1.155 6-2.838 8.36-5.048s4.14-4.947 5.35-8.212l25.47 2.863c-1.61 6.73-4.68 12.607-9.2 17.629-4.47 4.973-10.19 8.84-17.17 11.603-6.99 2.712-14.97 4.068-23.96 4.068m89.07-156.556V206h-27.27V51.703zM1596.96 206V51.703h27.95v130.865h67.96v23.431zm139.53 2.336c-7.33 0-13.94-1.306-19.81-3.918-5.83-2.662-10.45-6.58-13.87-11.753q-5.04-7.76-5.04-19.137c0-6.529 1.2-11.928 3.61-16.198q3.615-6.403 9.87-10.246c4.17-2.561 8.87-4.495 14.09-5.801a114 114 0 0 1 16.35-2.938q10.17-1.055 16.5-1.884c4.22-.603 7.28-1.507 9.19-2.712q2.94-1.883 2.94-5.801v-.452c0-5.676-1.68-10.071-5.05-13.185-3.36-3.114-8.21-4.671-14.54-4.671q-10.02 0-15.9 4.37c-3.86 2.913-6.48 6.354-7.83 10.321l-25.47-3.616c2.01-7.032 5.33-12.908 9.95-17.629q6.93-7.158 16.95-10.699c6.68-2.41 14.06-3.616 22.15-3.616q8.37 0 16.65 1.96c5.53 1.305 10.57 3.464 15.14 6.478 4.57 2.963 8.24 7.007 11 12.13 2.82 5.123 4.22 11.527 4.22 19.211v77.45h-26.22v-15.897h-.9c-1.66 3.215-3.99 6.228-7.01 9.041q-4.44 4.145-11.22 6.705-6.705 2.487-15.75 2.487m7.08-20.041c5.48 0 10.22-1.08 14.24-3.24q6.03-3.314 9.27-8.739c2.21-3.616 3.31-7.559 3.31-11.828V150.85c-.85.703-2.31 1.356-4.37 1.959q-3 .904-6.78 1.582c-2.51.452-4.99.854-7.45 1.206-2.47.351-4.6.652-6.41.904q-6.105.828-10.92 2.712c-3.22 1.256-5.75 3.013-7.61 5.274q-2.79 3.315-2.79 8.588c0 5.023 1.83 8.815 5.5 11.377q5.505 3.842 14.01 3.842m69.92 17.705V51.703h27.28v57.71h1.13c1.4-2.813 3.39-5.801 5.95-8.965 2.56-3.215 6.02-5.952 10.39-8.212 4.37-2.31 9.95-3.466 16.73-3.466q13.41 0 24.18 6.856c7.24 4.52 12.96 11.226 17.18 20.116 4.27 8.84 6.41 19.689 6.41 32.547 0 12.707-2.09 23.506-6.26 32.396s-9.84 15.67-17.03 20.342c-7.18 4.671-15.31 7.006-24.41 7.006-6.63 0-12.12-1.105-16.49-3.315s-7.89-4.872-10.55-7.986c-2.61-3.164-4.65-6.153-6.1-8.965h-1.59v18.232zm26.75-57.861c0 7.484 1.05 14.038 3.16 19.664q3.24 8.438 9.27 13.184c4.07 3.114 8.99 4.671 14.77 4.671 6.02 0 11.07-1.607 15.14-4.822 4.07-3.264 7.13-7.709 9.19-13.335 2.11-5.675 3.16-12.129 3.16-19.362 0-7.183-1.03-13.561-3.08-19.136-2.06-5.576-5.13-9.945-9.2-13.11-4.06-3.164-9.14-4.746-15.21-4.746q-8.745 0-14.85 4.596c-4.06 3.064-7.15 7.358-9.26 12.883q-3.09 8.287-3.09 19.513m184.41-27.273-24.86 2.712q-1.05-3.767-3.69-7.082-2.565-3.315-6.93-5.349c-2.91-1.356-6.48-2.034-10.7-2.034-5.67 0-10.45 1.23-14.31 3.691-3.82 2.462-5.7 5.651-5.65 9.569q-.075 5.047 3.69 8.212c2.56 2.109 6.78 3.842 12.65 5.198l19.74 4.219c10.95 2.361 19.09 6.103 24.41 11.226 5.38 5.123 8.09 11.828 8.14 20.116-.05 7.282-2.18 13.711-6.4 19.287-4.17 5.525-9.97 9.844-17.41 12.958-7.43 3.114-15.97 4.671-25.61 4.671-14.17 0-25.57-2.963-34.21-8.89-8.64-5.977-13.78-14.289-15.44-24.937l26.59-2.562c1.21 5.224 3.77 9.166 7.69 11.828s9.01 3.993 15.29 3.993q9.72 0 15.6-3.993c3.97-2.662 5.95-5.952 5.95-9.869q0-4.972-3.84-8.212-3.765-3.24-11.76-4.973l-19.74-4.143q-16.65-3.466-24.63-11.678c-5.33-5.525-7.96-12.507-7.91-20.945-.05-7.132 1.88-13.31 5.8-18.533q5.955-7.91 16.5-12.205 10.62-4.37 24.48-4.37c13.57 0 24.24 2.888 32.02 8.664 7.84 5.776 12.69 13.586 14.54 23.431"
            ></path>
            <mask
              id="mask0_4454_292"
              width="869"
              height="162"
              x="12"
              y="49"
              maskUnits="userSpaceOnUse"
              style={{ maskType: 'luminance' }}
            >
              <path fill="#fff" d="M12 49h869v162H12z"></path>
              <path
                fill="#000"
                d="M15.219 205.999V51.703h57.86q17.782 0 29.835 6.178 12.13 6.177 18.308 17.328 6.253 11.075 6.253 25.841 0 14.842-6.328 25.767-6.253 10.85-18.459 16.8-12.204 5.877-29.985 5.877h-41.21v-23.205h37.443q10.397 0 17.027-2.863 6.63-2.937 9.794-8.513 3.24-5.65 3.24-13.863 0-8.211-3.24-14.013-3.24-5.874-9.87-8.89-6.63-3.09-17.102-3.089H43.17V206zm79.71-69.916 38.196 69.916h-31.191l-37.52-69.916zm93.914 72.176q-17.404 0-30.061-7.232-12.582-7.308-19.362-20.644-6.781-13.41-6.781-31.567 0-17.856 6.781-31.342 6.855-13.56 19.136-21.095 12.28-7.61 28.855-7.609 10.699 0 20.191 3.466 9.569 3.39 16.877 10.547 7.383 7.158 11.602 18.232 4.22 11 4.219 26.219v8.363h-94.853v-18.383h68.71q-.075-7.836-3.39-13.938-3.315-6.179-9.267-9.719-5.876-3.541-13.712-3.541-8.362 0-14.691 4.068-6.328 3.993-9.87 10.548-3.466 6.479-3.541 14.239v16.047q0 10.096 3.692 17.329 3.69 7.157 10.321 10.999 6.63 3.767 15.52 3.767 5.952 0 10.774-1.657 4.821-1.733 8.363-5.048 3.54-3.315 5.349-8.212l25.465 2.863q-2.41 10.095-9.192 17.629-6.705 7.459-17.177 11.603-10.473 4.068-23.958 4.068m154.324-87.394-24.862 2.712q-1.055-3.767-3.692-7.082-2.563-3.315-6.931-5.349-4.37-2.034-10.699-2.034-8.514 0-14.314 3.691-5.726 3.692-5.651 9.569-.075 5.047 3.692 8.212 3.843 3.164 12.657 5.198l19.739 4.219q16.424 3.542 24.41 11.226 8.061 7.684 8.137 20.116-.075 10.923-6.404 19.287-6.255 8.287-17.403 12.958-11.15 4.671-25.616 4.671-21.246 0-34.204-8.89-12.958-8.965-15.445-24.937l26.595-2.562q1.808 7.835 7.685 11.828 5.874 3.993 15.294 3.993 9.717 0 15.595-3.993 5.952-3.993 5.952-9.869 0-4.972-3.842-8.212-3.767-3.24-11.753-4.973l-19.739-4.143q-16.651-3.466-24.637-11.678-7.986-8.288-7.91-20.945-.076-10.698 5.801-18.533 5.952-7.91 16.499-12.205 10.623-4.37 24.486-4.37 20.34 0 32.019 8.664 11.754 8.664 14.541 23.431m64.538 87.394q-17.404 0-30.061-7.232-12.582-7.308-19.362-20.644-6.781-13.41-6.781-31.567 0-17.856 6.781-31.342 6.854-13.56 19.136-21.095 12.28-7.61 28.855-7.609 10.699 0 20.191 3.466 9.569 3.39 16.877 10.547 7.383 7.158 11.602 18.232 4.22 11 4.219 26.219v8.363h-94.853v-18.383h68.71q-.075-7.836-3.39-13.938-3.315-6.179-9.267-9.719-5.877-3.541-13.712-3.541-8.362 0-14.691 4.068-6.33 3.993-9.87 10.548-3.465 6.479-3.541 14.239v16.047q0 10.096 3.692 17.329 3.69 7.157 10.321 10.999 6.63 3.767 15.52 3.767 5.952 0 10.774-1.657 4.821-1.733 8.363-5.048 3.54-3.315 5.349-8.212l25.465 2.863q-2.41 10.095-9.192 17.629-6.705 7.459-17.177 11.603-10.473 4.068-23.958 4.068m108.987-.226q-13.637 0-24.41-7.006-10.773-7.008-17.027-20.342-6.253-13.335-6.253-32.396 0-19.287 6.329-32.547 6.404-13.336 17.252-20.116 10.848-6.855 24.185-6.856 10.17 0 16.725 3.466 6.555 3.39 10.397 8.212 3.843 4.746 5.952 8.965h1.13V90.277h27.348V206h-26.821v-18.232h-1.657q-2.11 4.218-6.103 8.965-3.993 4.671-10.547 7.986t-16.5 3.315m7.61-22.376q8.664 0 14.766-4.671 6.102-4.746 9.267-13.184 3.164-8.44 3.164-19.664t-3.164-19.513q-3.09-8.287-9.191-12.883-6.028-4.596-14.842-4.596-9.117 0-15.219 4.746t-9.192 13.11q-3.088 8.362-3.088 19.136 0 10.85 3.088 19.362 3.165 8.439 9.267 13.335 6.179 4.822 15.144 4.822m68.23 20.342V90.277h26.444v19.287h1.206q3.162-10.02 10.849-15.445 7.684-5.5 17.704-5.5 4.671 0 8.589 1.13 3.918 1.131 6.931 3.09l-8.438 22.601q-2.184-1.054-4.821-1.733-2.637-.678-5.952-.678-7.083 0-12.808 3.165-5.726 3.163-9.116 8.815-3.315 5.574-3.315 12.958v68.032zm121.915 2.26q-17.328 0-29.759-7.609-12.356-7.61-19.061-21.02-6.63-13.486-6.63-31.04 0-17.63 6.78-31.116 6.78-13.56 19.137-21.095 12.429-7.61 29.382-7.609 14.088 0 24.938 5.198 10.923 5.124 17.403 14.541 6.48 9.342 7.384 21.849h-26.068q-1.582-8.363-7.534-13.938-5.876-5.65-15.746-5.651-8.362 0-14.691 4.521-6.33 4.444-9.87 12.807-3.465 8.364-3.465 20.041 0 11.828 3.465 20.342 3.465 8.438 9.719 13.033 6.327 4.521 14.842 4.521 6.027 0 10.774-2.26 4.821-2.335 8.061-6.706 3.24-4.37 4.445-10.623h26.068q-.981 12.28-7.233 21.774-6.254 9.417-17.027 14.766-10.773 5.274-25.314 5.274m88.634-70.066v67.806h-27.273V51.703h26.67v58.237h1.356q4.068-9.793 12.582-15.444 8.59-5.726 21.848-5.726 12.054 0 21.02 5.048 8.964 5.047 13.863 14.766 4.971 9.72 4.972 23.732v73.683h-27.273v-69.463q0-11.679-6.027-18.157-5.952-6.555-16.725-6.555-7.233 0-12.959 3.164-5.65 3.09-8.89 8.966-3.165 5.876-3.164 14.239"
              ></path>
            </mask>
            <g mask="url(#mask0_4454_292)">
              <path
                fill="#000"
                d="M15.22 206.001h-2.486v2.486h2.486zM15 51.705l.22-2.486h-2.486v2.486zm87.915 6.178-1.134 2.212.006.003zm18.308 17.328-2.175 1.205.005.008.005.01zm-.075 51.608-2.152-1.247-.002.005zm-18.459 16.8 1.079 2.241.011-.006zm-71.196 5.877h-2.486v2.486h2.486zm0-23.205v-2.486h-2.486v2.486zm54.47-2.863.987 2.283.01-.005.011-.005zm9.795-8.513-2.157-1.237-.005.01zm0-27.876-2.177 1.2.007.012zm-9.87-8.89-1.05 2.254.011.005.01.004zm-42.717-3.09v-2.485h-2.486v2.486zm0 130.942v2.486h2.486v-2.486zm51.758-69.916 2.182-1.192-.707-1.294H94.93zm38.198 69.916v2.486h4.191l-2.009-3.678zm-31.191 0-2.19 1.176.703 1.31h1.487zm-37.52-69.916v-2.486h-4.155l1.965 3.662zm-49.195 69.916H15V51.705h-2.265V206zM15 51.705l58.081 2.486v-4.972h-57.86zm58.081 0v2.486c11.58 0 21.108 2.013 28.702 5.904l1.132-2.212 1.135-2.213c-8.48-4.346-18.84-6.451-30.969-6.451zm29.834 6.178-1.128 2.215c7.676 3.91 13.4 9.348 17.261 16.318l2.175-1.205 2.176-1.205c-4.376-7.897-10.857-14.011-19.354-18.34zm18.308 17.328-2.164 1.222c3.927 6.954 5.932 15.134 5.932 24.619h4.973c0-10.203-2.164-19.251-6.575-27.064zm6.254 25.841h-2.486c0 9.535-2.031 17.678-5.995 24.52l2.152 1.247 2.152 1.246c4.474-7.723 6.664-16.758 6.664-27.013zm-6.329 25.767-2.153-1.242c-3.9 6.766-9.664 12.038-17.394 15.808l1.088 2.234 1.09 2.235c8.543-4.166 15.086-10.095 19.524-17.794zm-18.459 16.8-1.077-2.24c-7.712 3.714-17.315 5.631-28.907 5.631v4.972c12.115 0 22.502-2 31.063-6.122zm-29.984 5.877v-2.486h-41.21v4.972h41.21zm-41.21 0h2.485v-23.205h-4.973v23.205zm0-23.205v2.486h37.443v-4.972H31.493zm37.443 0v2.486c7.133 0 13.175-.978 18.012-3.066l-.985-2.283-.986-2.282c-4.003 1.729-9.31 2.659-16.04 2.659zm17.027-2.863 1.006 2.273c4.84-2.145 8.544-5.319 10.951-9.559l-2.164-1.227-2.162-1.227c-1.813 3.193-4.639 5.695-8.639 7.467zm9.793-8.513 2.158 1.237c2.425-4.23 3.569-9.302 3.569-15.1h-4.974c0 5.153-1.015 9.322-2.91 12.626zM99 101.052h2.486c0-5.8-1.145-10.91-3.555-15.225l-2.17 1.212-2.172 1.212c1.91 3.42 2.923 7.652 2.923 12.801zM95.76 87.039l2.176-1.2c-2.44-4.427-6.154-7.743-11.018-9.953l-1.028 2.263-1.03 2.263c3.976 1.808 6.842 4.42 8.721 7.827zm-9.87-8.89 1.05-2.254c-4.859-2.264-10.954-3.321-18.153-3.321v4.972c6.764 0 12.072 1.002 16.053 2.857zm-17.103-3.09v-2.485H43.171v4.972h25.616zm-25.615 0h-2.486v130.942h4.972V75.061zm0 130.942v-2.486H15.22v4.972h27.951zm51.757-69.916-2.18 1.192 38.197 69.916 2.181-1.192 2.183-1.192-38.199-69.916zm38.198 69.916v-2.486h-31.191v4.972h31.191zm-31.191 0 2.191-1.176-37.52-69.915-2.19 1.175-2.19 1.176 37.52 69.916zm-37.52-69.916v2.487H94.93v-4.973H64.416zm94.367 64.944-1.249 2.149.008.005.008.004zm-19.362-20.644-2.219 1.122.003.005zm0-62.909-2.219-1.121-.003.005zm19.136-21.095 1.3 2.12.01-.006zm49.046-4.143-.852 2.335.011.004.011.004zm16.877 10.547-1.74 1.776.009.009zm11.602 18.232-2.323.886.002.005zm4.219 34.582v2.486h2.486v-2.486zm-94.853 0h-2.486v2.486h2.486zm0-18.383v-2.487h-2.486v2.487zm68.71 0v2.486h2.51l-.024-2.51zm-3.39-13.938-2.191 1.175.006.011zm-9.267-9.719-1.283 2.129.012.007zm-28.403.527 1.326 2.103.009-.006.009-.005zm-9.87 10.548-2.187-1.182-.005.009zm-3.541 14.239-2.486-.024v.024zm3.692 33.376-2.215 1.13.005.009zm10.321 10.999-1.246 2.151.009.006.009.005zm26.294 2.11.808 2.351.017-.006.016-.005zm13.712-13.26.278-2.471-1.936-.217-.674 1.827zm25.465 2.863 2.418.577.653-2.734-2.793-.314zm-9.192 17.629-1.848-1.663-.001.001zm-17.177 11.603.9 2.317.007-.002.008-.003zm-23.958 4.068v-2.486c-11.254 0-20.832-2.336-28.827-6.905l-1.234 2.159-1.233 2.158c8.88 5.075 19.343 7.56 31.294 7.56zm-30.061-7.232 1.249-2.15c-7.962-4.625-14.085-11.145-18.395-19.62l-2.216 1.126-2.216 1.127c4.731 9.305 11.515 16.547 20.329 21.666zm-19.362-20.644 2.218-1.121c-4.311-8.528-6.513-18.651-6.513-30.446h-4.972c0 12.414 2.319 23.336 7.048 32.689zm-6.781-31.567h2.486c0-11.586 2.199-21.639 6.516-30.225l-2.221-1.117-2.222-1.116c-4.723 9.395-7.045 20.237-7.045 32.458zm6.781-31.342 2.218 1.122c4.375-8.653 10.446-15.329 18.218-20.097l-1.3-2.12-1.3-2.12c-8.602 5.278-15.288 12.665-20.055 22.094zm19.136-21.095 1.31 2.114c7.738-4.795 16.888-7.237 27.545-7.237v-4.972c-11.443 0-21.529 2.63-30.164 7.982zm28.855-7.61v2.487c6.859 0 13.299 1.11 19.339 3.315l.852-2.335.853-2.336c-6.617-2.416-13.638-3.616-21.044-3.616zm20.191 3.467-.83 2.343c6.035 2.139 11.351 5.46 15.967 9.98l1.74-1.776 1.739-1.776c-5.128-5.022-11.063-8.733-17.785-11.115zm16.877 10.547-1.731 1.785c4.624 4.483 8.307 10.237 11.01 17.333l2.323-.886 2.323-.885c-2.922-7.671-6.975-14.071-12.195-19.132zm11.602 18.232-2.321.891c2.677 6.979 4.054 15.402 4.054 25.328h4.972c0-10.366-1.435-19.422-4.384-27.109zm4.219 26.219h-2.486v8.363h4.972v-8.363zm0 8.363v-2.487h-94.853v4.973h94.853zm-94.853 0h2.486v-18.383h-4.972v18.383zm0-18.383v2.486h68.71v-4.973h-68.71zm68.71 0 2.486-.024c-.054-5.578-1.264-10.632-3.692-15.101l-2.184 1.187-2.185 1.186c1.992 3.668 3.042 7.906 3.089 12.775zm-3.39-13.938 2.19-1.176c-2.42-4.511-5.825-8.085-10.186-10.68l-1.271 2.137-1.271 2.136c3.574 2.127 6.348 5.032 8.347 8.758zm-9.267-9.719 1.283-2.13c-4.358-2.625-9.385-3.897-14.995-3.897v4.972c4.837 0 8.951 1.089 12.429 3.184zm-13.712-3.541v-2.486c-5.997 0-11.372 1.465-16.036 4.463l1.345 2.091 1.344 2.092c3.774-2.427 8.194-3.674 13.347-3.674zm-14.691 4.068-1.327-2.102c-4.579 2.888-8.166 6.721-10.73 11.468l2.187 1.182 2.188 1.182c2.156-3.993 5.149-7.192 9.008-9.627zm-9.87 10.548-2.192-1.173c-2.51 4.693-3.781 9.837-3.835 15.388l2.486.024 2.486.024c.047-4.795 1.137-9.145 3.247-13.091zm-3.541 14.239h-2.486v16.047h4.972v-16.047zm0 16.047h-2.486c0 7.03 1.285 13.212 3.963 18.459l2.215-1.13 2.214-1.131c-2.244-4.397-3.42-9.766-3.42-16.198zm3.692 17.329-2.21 1.139c2.667 5.172 6.432 9.199 11.285 12.011l1.246-2.151 1.247-2.151c-3.987-2.311-7.104-5.616-9.359-9.988zm10.321 10.999-1.228 2.162c4.853 2.757 10.463 4.092 16.748 4.092v-4.973c-5.568 0-10.304-1.177-14.291-3.442zm15.52 3.767v2.487c4.198 0 8.068-.585 11.582-1.793l-.808-2.351-.808-2.351c-2.915 1.002-6.228 1.522-9.966 1.522zm10.774-1.657.841 2.34c3.515-1.264 6.599-3.118 9.221-5.573l-1.699-1.815-1.699-1.815c-2.1 1.966-4.591 3.476-7.505 4.523zm8.363-5.048 1.699 1.815c2.664-2.494 4.653-5.567 5.982-9.166l-2.332-.861-2.332-.861c-1.082 2.93-2.659 5.332-4.716 7.258zm5.349-8.212-.278 2.471 25.465 2.863.278-2.471.278-2.471-25.465-2.863zm25.465 2.863-2.418-.578c-1.514 6.337-4.386 11.838-8.622 16.544l1.848 1.663 1.848 1.664c4.805-5.339 8.061-11.591 9.762-18.716zm-9.192 17.629-1.849-1.662c-4.183 4.653-9.574 8.314-16.243 10.953l.915 2.312.915 2.312c7.294-2.887 13.354-6.961 18.111-12.252zm-17.177 11.603-.9-2.318c-6.644 2.581-14.315 3.9-23.058 3.9v4.972c9.238 0 17.538-1.393 24.858-4.237zm130.366-83.326.27 2.471 2.672-.291-.499-2.641zm-24.862 2.712-2.394.67.568 2.03 2.095-.228zm-3.692-7.082-1.967 1.52.01.014.011.014zm-31.944-3.692-1.335-2.097-.006.004-.006.004zm-5.651 9.569 2.486.037.001-.035-.001-.034zm3.692 8.212-1.599 1.903.009.008.01.008zm12.657 5.198-.559 2.423.02.004.02.004zm19.739 4.219.524-2.43-.004-.001zm24.41 11.226-1.723 1.791.008.008zm8.137 20.116 2.486.017v-.032zm-6.404 19.287-1.982-1.501-.002.003zm-77.223 8.739-1.415 2.045.008.005zm-15.445-24.937-.238-2.475-2.624.252.405 2.605zm26.595-2.562 2.423-.559-.491-2.125-2.17.209zm38.574 11.828-1.385-2.064-.006.004-.006.004zm2.11-18.081-1.621 1.885.009.008.009.008zm-11.753-4.973.527-2.429-.008-.002-.009-.002zm-19.739-4.143.51-2.434h-.004zm-24.637-11.678-1.79 1.725.008.008zm-7.91-20.945 2.486.015v-.032zm5.801-18.533-1.987-1.495-.002.003zm16.499-12.205.938 2.302.008-.003zm56.505 4.294-1.481 1.997.006.004zm14.541 23.431-.27-2.472-24.862 2.712.27 2.472.269 2.472 24.863-2.713zm-24.862 2.712 2.394-.67c-.8-2.857-2.193-5.512-4.14-7.96l-1.946 1.548-1.946 1.548c1.569 1.972 2.637 4.038 3.244 6.204zm-3.692-7.082 1.967-1.52c-1.985-2.569-4.63-4.585-7.849-6.083l-1.049 2.254-1.049 2.254c2.607 1.214 4.582 2.764 6.013 4.615zm-6.931-5.349 1.049-2.254c-3.328-1.549-7.274-2.266-11.748-2.266v4.972c3.966 0 7.151.639 9.65 1.802zm-10.699-2.034v-2.486c-6.035 0-11.297 1.311-15.649 4.08l1.335 2.097 1.335 2.098c3.383-2.153 7.664-3.303 12.979-3.303zm-14.314 3.691-1.347-2.089c-4.402 2.838-6.853 6.767-6.79 11.689l2.486-.031 2.486-.032c-.037-2.913 1.28-5.363 4.512-7.447zm-5.651 9.569-2.486-.038c-.061 4.09 1.478 7.549 4.579 10.153l1.599-1.903 1.599-1.904c-1.922-1.614-2.844-3.631-2.805-6.271zm3.692 8.212-1.58 1.919c3.011 2.48 7.685 4.319 13.678 5.702l.559-2.423.559-2.422c-5.76-1.33-9.524-2.957-11.635-4.696zm12.657 5.198-.519 2.431 19.739 4.219.519-2.431.52-2.431-19.739-4.219zm19.739 4.219-.524 2.431c10.714 2.309 18.349 5.908 23.211 10.586l1.723-1.791 1.724-1.792c-5.786-5.568-14.425-9.453-25.61-11.864zm24.41 11.226-1.715 1.799c4.827 4.602 7.319 10.633 7.366 18.332l2.486-.015 2.486-.015c-.053-8.876-2.985-16.256-8.907-21.901zm8.137 20.116-2.486-.018c-.047 6.771-2.019 12.675-5.9 17.804l1.982 1.501 1.983 1.5c4.556-6.021 6.854-12.976 6.907-20.77zm-6.404 19.287-1.984-1.498c-3.863 5.12-9.285 9.191-16.38 12.163l.961 2.293.96 2.293c7.772-3.255 13.953-7.824 18.428-13.754zm-17.403 12.958-.961-2.293c-7.076 2.964-15.278 4.478-24.655 4.478v4.972c9.91 0 18.785-1.6 26.576-4.864zm-25.616 4.671v-2.486c-13.835 0-24.696-2.896-32.798-8.454l-1.406 2.05-1.407 2.05c9.176 6.295 21.118 9.326 35.611 9.326zm-34.204-8.89 1.414-2.044c-8.062-5.579-12.847-13.282-14.402-23.276l-2.457.383-2.457.382c1.76 11.302 7.272 20.224 16.487 26.6zm-15.445-24.937.238 2.474 26.595-2.561-.238-2.475-.238-2.475-26.595 2.562zm26.595-2.562-2.422.559c1.326 5.747 4.204 10.265 8.709 13.326l1.398-2.057 1.397-2.056c-3.33-2.263-5.575-5.631-6.659-10.331zm7.685 11.828-1.398 2.057c4.445 3.02 10.075 4.423 16.692 4.423v-4.973c-5.94 0-10.506-1.259-13.897-3.563zm15.294 3.993v2.487c6.799 0 12.536-1.395 16.992-4.423l-1.397-2.057-1.397-2.056c-3.379 2.296-8.039 3.563-14.198 3.563zm15.595-3.993 1.385 2.065c4.484-3.008 7.053-7 7.053-11.934h-4.972c0 2.901-1.399 5.489-4.851 7.805zm5.952-9.869h2.486c0-4.057-1.611-7.487-4.726-10.113l-1.602 1.901-1.603 1.901c2.008 1.693 2.959 3.738 2.959 6.311zm-3.842-8.212 1.621-1.885c-2.966-2.551-7.35-4.325-12.847-5.517l-.527 2.429-.528 2.43c5.151 1.118 8.602 2.659 10.66 4.428zm-11.753-4.973.51-2.433-19.739-4.144-.51 2.434-.511 2.433 19.739 4.144zm-19.739-4.143.506-2.434c-10.836-2.256-18.512-5.992-23.36-10.977l-1.783 1.733-1.782 1.733c5.8 5.964 14.548 10.013 25.912 12.379zm-24.637-11.678 1.791-1.725c-4.827-5.01-7.262-11.344-7.215-19.205l-2.486-.015-2.487-.014c-.053 9.015 2.786 16.644 8.607 22.684zm-7.91-20.945 2.486-.017c-.047-6.642 1.743-12.277 5.304-17.025l-1.989-1.491-1.989-1.492c-4.275 5.699-6.352 12.42-6.298 20.043zm5.801-18.533 1.987 1.495c3.659-4.864 8.771-8.678 15.45-11.398l-.938-2.302-.937-2.303c-7.385 3.007-13.272 7.329-17.549 13.013zm16.499-12.205.946 2.299c6.727-2.767 14.557-4.183 23.54-4.183v-4.972c-9.501 0-17.994 1.497-25.432 4.556zm24.486-4.37v2.486c13.235 0 23.322 2.82 30.538 8.175l1.481-1.997 1.482-1.997c-8.355-6.198-19.614-9.153-33.501-9.153zm32.019 8.664-1.475 2c7.314 5.393 11.827 12.645 13.573 21.892l2.443-.461 2.443-.461c-1.971-10.442-7.151-18.811-15.508-24.971zm49.018 103.593-1.249 2.149.008.005.008.004zm-19.362-20.644-2.219 1.122.002.005zm0-62.909-2.219-1.121-.003.005zm19.136-21.095 1.3 2.12.01-.006zm49.046-4.143-.852 2.335.011.004.011.004zm16.877 10.547-1.74 1.776.009.009zm11.602 18.232-2.323.886.002.005zm4.219 34.582v2.486h2.486v-2.486zm-94.853 0h-2.486v2.486h2.486zm0-18.383v-2.487h-2.486v2.487zm68.71 0v2.486h2.51l-.024-2.51zm-3.39-13.938-2.191 1.175.006.011zm-9.267-9.719-1.283 2.129.012.007zm-28.403.527 1.326 2.103.009-.006.009-.005zm-9.87 10.548-2.187-1.182-.005.009zm-3.541 14.239-2.486-.024v.024zm3.692 33.376-2.215 1.13.005.009zm10.321 10.999-1.246 2.151.009.006.009.005zm26.294 2.11.808 2.351.017-.006.016-.005zm13.712-13.26.278-2.471-1.936-.217-.674 1.827zm25.465 2.863 2.418.577.653-2.734-2.793-.314zm-9.192 17.629-1.848-1.663-.001.001zm-17.177 11.603.9 2.317.007-.002.008-.003zm-23.958 4.068v-2.486c-11.254 0-20.832-2.336-28.827-6.905l-1.234 2.159-1.233 2.158c8.88 5.075 19.343 7.56 31.294 7.56zm-30.061-7.232 1.249-2.15c-7.962-4.625-14.085-11.145-18.395-19.62l-2.216 1.126-2.217 1.127c4.732 9.305 11.516 16.547 20.33 21.666zm-19.362-20.644 2.218-1.121c-4.311-8.528-6.513-18.651-6.513-30.446h-4.972c0 12.414 2.319 23.336 7.048 32.689zm-6.781-31.567h2.486c0-11.586 2.199-21.639 6.516-30.225l-2.221-1.117-2.222-1.116c-4.723 9.395-7.045 20.237-7.045 32.458zm6.781-31.342 2.218 1.122c4.375-8.653 10.446-15.329 18.218-20.097l-1.3-2.12-1.3-2.12c-8.602 5.278-15.289 12.665-20.055 22.094zm19.136-21.095 1.31 2.114c7.738-4.795 16.888-7.237 27.545-7.237v-4.972c-11.443 0-21.529 2.63-30.165 7.982zm28.855-7.61v2.487c6.859 0 13.299 1.11 19.339 3.315l.852-2.335.853-2.336c-6.618-2.416-13.638-3.616-21.044-3.616zm20.191 3.467-.83 2.343c6.035 2.139 11.351 5.46 15.967 9.98l1.74-1.776 1.739-1.776c-5.128-5.022-11.063-8.733-17.785-11.115zm16.877 10.547-1.731 1.785c4.624 4.483 8.307 10.237 11.01 17.333l2.323-.886 2.323-.885c-2.922-7.671-6.975-14.071-12.195-19.132zm11.602 18.232-2.321.891c2.677 6.979 4.054 15.402 4.054 25.328h4.972c0-10.366-1.435-19.422-4.384-27.109zm4.219 26.219h-2.486v8.363h4.972v-8.363zm0 8.363v-2.487H364.31v4.973h94.853zm-94.853 0h2.486v-18.383h-4.972v18.383zm0-18.383v2.486h68.71v-4.973h-68.71zm68.71 0 2.486-.024c-.054-5.578-1.264-10.632-3.692-15.101l-2.184 1.187-2.185 1.186c1.992 3.668 3.042 7.906 3.089 12.775zm-3.39-13.938 2.19-1.176c-2.42-4.511-5.825-8.085-10.186-10.68l-1.271 2.137-1.271 2.136c3.574 2.127 6.348 5.032 8.347 8.758zm-9.267-9.719 1.283-2.13c-4.358-2.625-9.385-3.897-14.995-3.897v4.972c4.837 0 8.951 1.089 12.429 3.184zm-13.712-3.541v-2.486c-5.997 0-11.372 1.465-16.036 4.463l1.345 2.091 1.344 2.092c3.774-2.427 8.193-3.674 13.347-3.674zm-14.691 4.068-1.327-2.102c-4.579 2.888-8.166 6.721-10.73 11.468l2.187 1.182 2.188 1.182c2.156-3.993 5.149-7.192 9.008-9.627zm-9.87 10.548-2.192-1.173c-2.51 4.693-3.781 9.837-3.835 15.388l2.486.024 2.486.024c.047-4.795 1.137-9.145 3.247-13.091zm-3.541 14.239h-2.486v16.047h4.972v-16.047zm0 16.047h-2.486c0 7.03 1.285 13.212 3.963 18.459l2.215-1.13 2.214-1.131c-2.244-4.397-3.42-9.766-3.42-16.198zm3.692 17.329-2.21 1.139c2.667 5.172 6.432 9.199 11.285 12.011l1.246-2.151 1.247-2.151c-3.987-2.311-7.104-5.616-9.359-9.988zm10.321 10.999-1.228 2.162c4.852 2.757 10.463 4.092 16.748 4.092v-4.973c-5.568 0-10.304-1.177-14.291-3.442zm15.52 3.767v2.487c4.198 0 8.068-.585 11.582-1.793l-.808-2.351-.808-2.351c-2.915 1.002-6.228 1.522-9.966 1.522zm10.774-1.657.841 2.34c3.515-1.264 6.599-3.118 9.221-5.573l-1.699-1.815-1.699-1.815c-2.1 1.966-4.591 3.476-7.505 4.523zm8.363-5.048 1.699 1.815c2.664-2.494 4.653-5.567 5.982-9.166l-2.332-.861-2.332-.861c-1.082 2.93-2.659 5.332-4.716 7.258zm5.349-8.212-.278 2.471 25.465 2.863.278-2.471.278-2.471-25.465-2.863zm25.465 2.863-2.418-.578c-1.514 6.337-4.386 11.838-8.622 16.544l1.848 1.663 1.848 1.664c4.805-5.339 8.061-11.591 9.762-18.716zm-9.192 17.629-1.849-1.662c-4.183 4.653-9.575 8.314-16.243 10.953l.915 2.312.915 2.312c7.294-2.887 13.354-6.961 18.111-12.252zm-17.177 11.603-.901-2.318c-6.643 2.581-14.315 3.9-23.057 3.9v4.972c9.238 0 17.538-1.393 24.858-4.237zm43.668-88.449-2.242-1.077-.002.006zm17.252-20.116 1.318 2.108.011-.006zm40.91-3.39-1.162 2.198.01.005.01.005zm10.397 8.212-1.944 1.549.006.008.006.007zm5.952 8.965-2.224 1.112.687 1.374h1.537zm1.13 0v2.486h2.486v-2.486zm0-19.136V87.79h-2.486v2.487zm27.348 0h2.487V87.79h-2.487zm0 115.722v2.486h2.487v-2.486zm-26.821 0h-2.486v2.486h2.486zm0-18.232h2.487v-2.486H551.5zm-1.657 0v-2.486h-1.537l-.687 1.374zm-6.103 8.965 1.89 1.616.007-.008.006-.007zm-4.671-15.746 1.511 1.974.008-.005.008-.006zm9.267-52.361-2.33.868.004.009.003.01zm-9.191-12.883-1.508 1.977.006.004.006.005zm-39.253 51.758-2.337.848.005.013.005.012zm9.267 13.335-1.556 1.94.013.01.014.01zm7.534 27.198v-2.486c-8.64 0-16.3-2.212-23.054-6.605l-1.356 2.085-1.355 2.084c7.611 4.95 16.224 7.408 25.765 7.408zm-24.41-7.006 1.356-2.085c-6.74-4.383-12.13-10.78-16.132-19.313l-2.251 1.056-2.251 1.055c4.336 9.247 10.297 16.412 17.923 21.371zm-17.027-20.342 2.251-1.056c-3.975-8.477-6.018-18.895-6.018-31.34h-4.972c0 12.969 2.126 24.149 6.488 33.451zm-6.253-32.396h2.486c0-12.599 2.069-23.058 6.086-31.476l-2.243-1.071-2.244-1.071c-4.421 9.262-6.571 20.5-6.571 33.618zm6.329-32.547 2.241 1.076c4.098-8.533 9.555-14.85 16.329-19.084l-1.318-2.108-1.317-2.108c-7.692 4.807-13.736 11.901-18.177 21.147zm17.252-20.116 1.329 2.102c6.819-4.31 14.416-6.472 22.856-6.472v-4.972c-9.341 0-17.867 2.408-25.513 7.24zm24.185-6.856v2.486c6.518 0 11.66 1.115 15.563 3.178l1.162-2.198 1.162-2.198c-4.836-2.557-10.845-3.754-17.887-3.754zm16.725 3.466-1.142 2.208c4.119 2.13 7.29 4.66 9.595 7.553l1.944-1.549 1.944-1.55c-2.818-3.536-6.578-6.48-11.199-8.87zm10.397 8.212-1.932 1.564c2.479 3.063 4.354 5.9 5.66 8.513l2.224-1.112 2.224-1.112c-1.507-3.012-3.6-6.152-6.244-9.418zm5.952 8.965v2.486h1.13v-4.972h-1.13zm1.13 0h2.486V90.279l-4.972-.001v19.137zm0-19.136v2.486h27.348V87.79h-27.348zm27.348 0h-2.486V206h4.973V90.279zm0 115.722v-2.486H551.5v4.972h26.821zm-26.821 0h2.487v-18.232h-4.973v18.232zm0-18.232v-2.486h-1.657v4.972h1.657zm-1.657 0-2.224-1.112c-1.296 2.593-3.208 5.418-5.781 8.477l1.902 1.6 1.903 1.601c2.751-3.27 4.907-6.422 6.424-9.454zm-6.103 8.965-1.889-1.615c-2.412 2.82-5.648 5.293-9.78 7.383l1.122 2.218 1.122 2.219c4.607-2.33 8.402-5.182 11.315-8.589zm-10.547 7.986-1.122-2.218c-3.921 1.983-9.006 3.047-15.378 3.047v4.972c6.889 0 12.803-1.145 17.622-3.582zm-8.89-19.061v2.486c6.249 0 11.721-1.695 16.277-5.183l-1.511-1.974-1.511-1.974c-3.58 2.74-7.952 4.159-13.255 4.159zm14.766-4.671 1.527 1.963c4.487-3.491 7.824-8.291 10.068-14.274l-2.328-.873-2.328-.873c-1.975 5.267-4.816 9.256-8.465 12.095zm9.267-13.184 2.328.873c2.236-5.964 3.323-12.826 3.323-20.537h-4.973c0 7.256-1.023 13.504-3.006 18.791zm3.164-19.664h2.487c0-7.71-1.086-14.528-3.328-20.4l-2.323.887-2.323.887c1.977 5.177 3.001 11.368 3.001 18.626zm-3.164-19.513 2.33-.869c-2.199-5.897-5.522-10.608-10.026-14l-1.495 1.986-1.496 1.986c3.633 2.735 6.437 6.613 8.357 11.765zm-9.191-12.883 1.507-1.977c-4.519-3.446-10.021-5.105-16.349-5.105v4.972c5.424 0 9.817 1.405 13.334 4.087zm-14.842-4.596v-2.486c-6.528 0-12.166 1.708-16.745 5.27l1.526 1.962 1.526 1.963c3.557-2.767 8.065-4.223 13.693-4.223zm-15.219 4.746-1.526-1.962c-4.488 3.49-7.803 8.268-9.998 14.21l2.332.862 2.333.861c1.923-5.208 4.736-9.17 8.385-12.008zm-9.192 13.11-2.332-.862c-2.18 5.902-3.243 12.581-3.243 19.998h4.973c0-6.948.996-13.026 2.935-18.275zm-3.088 19.136h-2.487c0 7.466 1.063 14.215 3.238 20.21l2.337-.848 2.338-.848c-1.944-5.356-2.94-11.515-2.94-18.514zm3.088 19.362-2.327.873c2.242 5.979 5.571 10.817 10.038 14.402l1.556-1.94 1.556-1.939c-3.67-2.945-6.518-6.997-8.495-12.269zm9.267 13.335-1.529 1.96c4.617 3.604 10.225 5.348 16.673 5.348v-4.972c-5.507 0-9.994-1.47-13.614-4.295zm83.374 25.164h-2.486v2.486h2.486zm0-115.722V87.79h-2.486v2.487zm26.444 0h2.486V87.79h-2.486zm0 19.287h-2.486v2.486h2.486zm1.206 0v2.486h1.822l.548-1.738zm10.849-15.445 1.433 2.03.007-.003.006-.005zm33.224-1.28 2.33.869.697-1.868-1.672-1.086zm-8.438 22.601-1.08 2.239 2.456 1.186.954-2.555zm-32.697 9.569-2.132-1.28-.005.009zm-3.315 80.99v2.486h2.486v-2.486zm-27.273 0h2.486V90.279l-4.972-.001V206zm0-115.722v2.486h26.444V87.79h-26.444zm26.444 0h-2.486v19.287h4.972V90.279zm0 19.287v2.486h1.206v-4.972h-1.206zm1.206 0 2.37.748c1.966-6.225 5.285-10.895 9.912-14.162l-1.433-2.031-1.434-2.031c-5.619 3.966-9.533 9.592-11.786 16.727zm10.849-15.445 1.446 2.022c4.675-3.346 10.064-5.035 16.258-5.035v-4.973c-7.165 0-13.58 1.977-19.151 5.964zm17.704-5.5v2.487c2.915 0 5.542.352 7.9 1.032l.689-2.39.689-2.387c-2.865-.827-5.964-1.228-9.278-1.228zm8.589 1.13-.689 2.389c2.407.694 4.488 1.629 6.266 2.785l1.354-2.084 1.355-2.085c-2.24-1.456-4.78-2.581-7.597-3.393zm6.931 3.09-2.329-.87-8.438 22.602 2.329.869 2.33.87 8.438-22.602zm-8.438 22.601 1.081-2.239c-1.621-.782-3.385-1.413-5.283-1.901l-.619 2.407-.62 2.408c1.618.416 3.069.941 4.361 1.564zm-4.821-1.733.619-2.407c-1.999-.514-4.196-.757-6.571-.757v4.973c2.044 0 3.815.209 5.332.599zm-5.952-.678v-2.486c-5.106 0-9.795 1.145-14.011 3.475l1.203 2.176 1.203 2.176c3.419-1.89 7.268-2.854 11.605-2.854zm-12.808 3.165-1.203-2.176c-4.203 2.323-7.561 5.572-10.045 9.711l2.132 1.28 2.132 1.279c2.036-3.395 4.756-6.022 8.187-7.918zm-9.116 8.815-2.137-1.271c-2.469 4.152-3.664 8.923-3.664 14.229h4.972c0-4.538 1.015-8.406 2.966-11.688zm-3.315 12.958h-2.486v68.032h4.972v-68.032zm0 68.032v-2.486h-27.273v4.972h27.273zm64.883-5.349-1.304 2.117.006.003zm-19.061-21.02-2.232 1.097.004.007.004.008zm.15-62.156 2.222 1.117.002-.005zm19.137-21.095 1.294 2.123.004-.002zm54.32-2.41-1.075 2.242.01.004.009.004zm17.403 14.54-2.048 1.409.005.008zm7.384 21.849v2.486h2.672l-.193-2.666zm-26.068 0-2.443.462.383 2.024h2.06zm-7.534-13.938-1.723 1.792.012.011.011.011zm-30.437-1.13 1.429 2.034.008-.006.008-.005zm-9.87 12.807-2.289-.969-.004.009-.004.009zm0 40.383-2.303.937.003.007zm9.719 13.033-1.472 2.004.013.01.014.01zm25.616 2.261 1.069 2.244.007-.003.007-.004zm12.506-17.329v-2.486h-2.053l-.388 2.016zm26.068 0 2.478.198.214-2.684h-2.692zm-7.233 21.774 2.071 1.375.005-.008zm-17.027 14.766 1.093 2.233.013-.006zm-25.314 5.274v-2.486c-11.181 0-20.633-2.452-28.461-7.244l-1.298 2.121-1.298 2.12c8.746 5.354 19.134 7.975 31.057 7.975zm-29.759-7.609 1.303-2.117c-7.829-4.822-13.87-11.474-18.141-20.015l-2.223 1.112-2.224 1.112c4.67 9.34 11.336 16.701 19.981 22.025zm-19.061-21.02 2.231-1.097c-4.226-8.596-6.375-18.557-6.375-29.943h-4.972c0 12.019 2.271 22.752 6.884 32.137zm-6.63-31.04h2.486c0-11.43 2.196-21.408 6.516-29.999l-2.222-1.117-2.221-1.116c-4.722 9.391-7.045 20.156-7.045 32.232zm6.78-31.116 2.224 1.112c4.322-8.644 10.388-15.316 18.207-20.084l-1.294-2.123-1.295-2.122c-8.655 5.277-15.347 12.668-20.065 22.106zm19.137-21.095 1.298 2.12c7.836-4.795 17.166-7.243 28.084-7.243v-4.972c-11.683 0-21.942 2.626-30.68 7.975zm29.382-7.61v2.487c9.084 0 17.019 1.676 23.863 4.955l1.075-2.242 1.074-2.243c-7.621-3.651-16.311-5.442-26.012-5.442zm24.938 5.2-1.056 2.25c6.906 3.24 12.356 7.805 16.411 13.699l2.048-1.409 2.049-1.409c-4.584-6.663-10.737-11.79-18.397-15.383zm17.403 14.54-2.043 1.417c4.04 5.825 6.373 12.67 6.947 20.611l2.48-.179 2.479-.18c-.631-8.734-3.221-16.455-7.82-23.086zm7.384 21.849v-2.487h-26.068v4.973h26.068zm-26.068 0 2.443-.463c-1.148-6.069-3.907-11.196-8.277-15.29l-1.7 1.815-1.7 1.814c3.566 3.34 5.83 7.505 6.791 12.586zm-7.534-13.938 1.723-1.792c-4.475-4.303-10.39-6.345-17.469-6.345v4.972c6.081 0 10.662 1.726 14.023 4.957zm-15.746-5.651v-2.486c-6.052 0-11.463 1.646-16.136 4.984l1.445 2.023 1.445 2.023c3.765-2.69 8.148-4.058 13.246-4.058zm-14.691 4.521-1.429-2.035c-4.662 3.275-8.22 7.945-10.73 13.873l2.289.969 2.29.97c2.211-5.223 5.233-9.091 9.009-11.743zm-9.87 12.807-2.297-.951c-2.466 5.95-3.655 12.971-3.655 20.992h4.973c0-7.549 1.121-13.889 3.276-19.089zm-3.465 20.041h-2.487c0 8.119 1.189 15.234 3.649 21.279l2.303-.937 2.303-.938c-2.16-5.306-3.282-11.752-3.282-19.404zm3.465 20.342-2.3.944c2.453 5.973 5.95 10.714 10.547 14.093l1.472-2.004 1.472-2.003c-3.74-2.749-6.723-6.697-8.891-11.975zm9.719 13.033-1.445 2.024c4.681 3.343 10.145 4.983 16.287 4.983v-4.972c-5.209 0-9.64-1.374-13.397-4.058zm14.842 4.521v2.486c4.334 0 8.299-.814 11.843-2.502l-1.069-2.244-1.069-2.245c-2.785 1.326-6.003 2.019-9.705 2.019zm10.774-2.26 1.083 2.237c3.582-1.734 6.58-4.232 8.975-7.462l-1.997-1.481-1.997-1.48c-1.925 2.596-4.3 4.569-7.148 5.948zm8.061-6.706 1.997 1.481c2.417-3.259 4.027-7.16 4.889-11.633l-2.441-.471-2.441-.47c-.745 3.865-2.098 7.046-4.001 9.613zm4.445-10.623v2.487h26.068v-4.973h-26.068zm26.068 0-2.479-.197c-.622 7.805-2.911 14.653-6.83 20.603l2.076 1.368 2.076 1.367c4.419-6.707 6.952-14.374 7.635-22.943zm-7.233 21.774-2.071-1.376c-3.912 5.892-9.244 10.531-16.061 13.916l1.105 2.226 1.106 2.227c7.547-3.747 13.566-8.953 17.992-15.618zm-17.027 14.766-1.093-2.233c-6.777 3.318-14.827 5.021-24.221 5.021v4.972c9.993 0 18.82-1.812 26.407-5.527zm63.32 3.014v2.486h2.486v-2.486zm-27.273 0h-2.487v2.486h2.487zm0-154.296v-2.486h-2.487v2.486zm26.67 0h2.486v-2.486h-2.486zm0 58.237h-2.486v2.487h2.486zm1.356 0v2.487h1.66l.636-1.533zm12.582-15.444 1.375 2.07.004-.001zm56.731 14.088-2.22 1.119.003.007.004.007zm4.972 97.415v2.486h2.487v-2.486zm-27.273 0h-2.486v2.486h2.486zm-6.027-87.62-1.841 1.671.01.011.011.011zm-29.684-3.391 1.193 2.182.01-.006zm-8.89 8.966-2.177-1.201-.006.011-.006.011zm-3.164 14.239h-2.487v67.806h4.973v-67.806zm0 67.806v-2.486h-27.273v4.972h27.273zm-27.273 0h2.486V51.705h-4.973V206zm0-154.296v2.486h26.67v-4.972h-26.67zm26.67 0h-2.486v58.237h4.972V51.705zm0 58.237v2.487h1.356v-4.973h-1.356zm1.356 0 2.296.954c2.531-6.092 6.413-10.843 11.661-14.327l-1.375-2.071-1.375-2.072c-6.103 4.05-10.609 9.596-13.503 16.563zm12.582-15.444 1.379 2.069c5.216-3.478 11.982-5.31 20.469-5.31v-4.971c-9.192 0-16.991 1.986-23.227 6.143zm21.848-5.726v2.486c7.683 0 14.255 1.606 19.801 4.728l1.219-2.166 1.22-2.167c-6.409-3.608-13.85-5.367-22.24-5.367zm21.02 5.048-1.219 2.166c5.521 3.109 9.805 7.654 12.862 13.719l2.22-1.119 2.22-1.118c-3.473-6.894-8.43-12.193-14.863-15.815zm13.863 14.766-2.213 1.133c3.092 6.043 4.699 13.543 4.699 22.599h4.973c0-9.627-1.708-17.949-5.246-24.864zm4.972 23.732h-2.486v73.683h4.973v-73.683zm0 73.683v-2.486h-27.273v4.972h27.273zm-27.273 0h2.486v-69.463h-4.972v69.463zm0-69.463h2.486c0-8.208-2.124-14.94-6.693-19.851l-1.82 1.694-1.82 1.693c3.468 3.728 5.361 9.101 5.361 16.464zm-6.027-18.157 1.841-1.672c-4.54-4.999-10.848-7.369-18.566-7.369v4.972c6.646 0 11.488 2 14.884 5.74zm-16.725-6.555v-2.486c-5.197 0-9.938 1.14-14.161 3.474l1.202 2.176 1.203 2.176c3.411-1.885 7.309-2.854 11.756-2.854zm-12.959 3.164-1.192-2.181c-4.2 2.296-7.497 5.633-9.875 9.946l2.177 1.201 2.177 1.2c1.942-3.522 4.571-6.162 7.906-7.984zm-8.89 8.966-2.189-1.179c-2.348 4.36-3.462 9.534-3.462 15.418h4.973c0-5.266.996-9.586 2.867-13.061z"
              ></path>
            </g>
          </svg>
        </div>
        <div className="absolute top-0 left-0 w-36 h-full bg-gradient-to-r from-white via-10% via-white to-transparent z-[1] hidden 2xl:block"></div>
        <div className="absolute top-0 right-0 w-36 h-full bg-gradient-to-l from-white via-10% via-white to-transparent z-[1] hidden 2xl:block"></div>

        <div className="relative border-y">
          <div className="mx-auto max-w-7xl z-[0]">
            <section
              aria-labelledby="hero-heading"
              className="text-center relative grid grid-cols-1 md:grid-cols-2 border-x"
            >
              <div className="md:border-r aspect-[16/12] overflow-hidden relative p-8 flex items-center justify-between">
                <span className="transition-all inline-flex items-center w-full h-full absolute top-24 left-[850px] text-black">
                  {Array(180)
                    .fill(0)
                    .map((_, i) => (
                      <div
                        key={`bottom-${i}`}
                        className="h-[200%] w-px bg-neutral-200 dark:bg-neutral-800 -ml-1 -mr-1 rotate-45"
                      ></div>
                    ))}
                </span>
                <div className="relative p-2 rounded-[32px] bg-white border  shadow-sm">
                  <img
                    alt="Screenshot showing the massive library of content available to practice with"
                    src="/images/interspeech.png"
                    className="h-full aspect-video object-cover object-top rounded-3xl border bg-white border-black/10"
                  />
                </div>
              </div>
              <div className="">
                <div className="relative flex flex-col justify-between h-full overflow-hidden">
                  <div className="p-6 text-left">
                    <h2 className="text-xl sm:text-xl lg:text-2xl max-w-full text-balance font-medium tracking-tight text-neutral-950">
                      Speak Like The Stars: Pronunciation Mastery Through Movies.
                    </h2>

                    <div className="flex flex-col gap-1 justify-start mt-4 items-start text-left">
                      <p className="text-neutral-600">Interspeech Conference Science Slam</p>
                      <time dateTime="2025-08-20" className="text-neutral-600">
                        August 20, 2025
                      </time>
                    </div>
                  </div>
                  <div className="p-6 w-full text-left flex justify-start">
                    <p className="mt-2 max-w-lg text-sm/6 text-neutral-600 w-full text-balance">
                      We presented our work on making speech pathology more accessible, insights and
                      statistics into our latest phonetic model, and a demo of our work-in-progress
                      pronunciation platform.
                    </p>
                  </div>
                </div>
              </div>
            </section>
          </div>
        </div>
        <div className="max-w-7xl border-x h-12 w-full mx-auto"></div>
        <div className="relative border-y">
          <div className="mx-auto max-w-7xl z-[0]">
            <section
              aria-labelledby="hero-heading"
              className="text-center relative grid grid-cols-1 md:grid-cols-2 border-x"
            >
              <div className="md:border-r">
                <div className="relative flex flex-col justify-between h-full overflow-hidden">
                  <div className="p-6 text-left">
                    <h2 className="text-xl sm:text-xl lg:text-2xl max-w-[400px] mr-auto font-medium tracking-tight text-neutral-950">
                      Speech Technology Built for Everyone, Everywhere.
                    </h2>

                    <div className="flex flex-col gap-1 justify-start mt-4 items-start text-left">
                      <div className="flex flex-col justify-center align-baseline sm:items-center gap-1 grayscale text-left">
                        <p className="text-neutral-600">
                          University of Washington Research Symposium
                        </p>

                        <time dateTime="2025-05-16" className="text-neutral-600 mr-auto">
                          May 16, 2025
                        </time>
                      </div>
                    </div>
                  </div>
                  <div className="p-6 w-full text-left flex justify-start">
                    <p className="mt-2 max-w-lg text-sm/6 text-neutral-600 text-balance">
                      We presented our work on making speech pathology more accessible, insights and
                      statistics into our latest phonetic model, and a demo of our work-in-progress
                      pronunciation platform.
                    </p>
                  </div>
                </div>
              </div>
              <div className="aspect-[16/12] overflow-hidden relative p-8 flex items-center justify-between">
                <span className="transition-all inline-flex items-center w-full h-full absolute top-24 left-[850px] text-black">
                  {Array(180)
                    .fill(0)
                    .map((_, i) => (
                      <div
                        key={`bottom-${i}`}
                        className="h-[200%] w-px bg-neutral-200 dark:bg-neutral-800 -ml-1 -mr-1 rotate-45"
                      ></div>
                    ))}
                </span>
                <div className="relative p-2 rounded-[32px] bg-white border  shadow-sm">
                  <img
                    alt="Screenshot showing the massive library of content available to practice with"
                    src="/images/UofW.png"
                    className="h-full aspect-video object-cover object-top rounded-3xl border bg-white border-black/10"
                  />
                </div>
              </div>
            </section>
          </div>
        </div>

        <div className="overflow-hidden border mt-12 mb-24 py-24 sm:py-32">
          <div className="mx-auto max-w-7xl">
            <div className="mx-auto grid max-w-2xl grid-cols-1 gap-y-16 sm:gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-2">
              <div className="lg:ml-auto lg:pl-4 lg:pt-4">
                <div className="lg:max-w-2xl lg:mt-12">
                  <p className="text-lg font-semibold text-sky-600 mb-2">
                    Research and Collaboration
                  </p>
                  <h2 className="text-pretty text-4xl font-semibold tracking-tight text-neutral-900 sm:text-5xl">
                    Our Way Forward
                  </h2>
                  <p className="mt-6 text-lg/8 text-neutral-600">
                    Driven by a commitment to collaborative science, we advance open-source research
                    in language technologies while building practical, engaging solutions. This
                    dedication stems from a core belief: transformative innovation builds upon
                    collective knowledge.
                  </p>

                  <p className="mt-6 text-lg/8 text-neutral-600">
                    Through open-source contributions, our organization accelerates progress in
                    linguistic technology, shaping a future where language learning knows no bounds.
                  </p>

                  <p className="mt-6 text-lg/8 text-neutral-600">
                    We work with linguists, natural-language processing researchers, and research
                    labs worldwide. If you're interested in our work, please contact us to explore
                    collaboration opportunities!
                  </p>
                </div>
              </div>
              <div className="flex items-start justify-end lg:order-first sm:mr-8 mr-0">
                <div className="w-full relative h-full bg-white/50 border border-neutral-200/50 rounded-[32px] p-2">
                  <img
                    alt="A photo of the Koel Labs founders, Alexander Metzger, Aruna Srivastava, and Ruslan Mukhamedvaleev standing in front of the bay bridge in San Francisco."
                    src="/images/research.png"
                    className="w-full h-full rounded-[26px] object-cover object-right lg:max-w-none xl:row-span-2 opacity-100 bg-white xl:row-end-2 aspect-square border"
                  />
                </div>
              </div>
            </div>
          </div>
        </div>

        <div className="z-[3] bg-white">
          <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
            <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
              {Array(500)
                .fill(0)
                .map((_, i) => (
                  <div
                    key={`bottom-${i}`}
                    className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                  ></div>
                ))}
            </div>
          </div>
          <CTA />
          <div className="w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-y">
            <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
              {Array(500)
                .fill(0)
                .map((_, i) => (
                  <div
                    key={`bottom-${i}`}
                    className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                  ></div>
                ))}
            </div>
          </div>
        </div>
        <Footer />
      </div>
    </div>
  );
}



================================================
FILE: app/reset-password/page.js
================================================
// // TODO: create page

// const token = new URLSearchParams(window.location.search).get('token');
// if (!token) {
//   // Handle the error
// }
// const { data, error } = await authClient.resetPassword({
//   newPassword: 'password1234',
//   token,
// });

export default function ResetPasswordPage() {
  return <div>ResetPasswordPage</div>;
}



================================================
FILE: app/sign-in/page.tsx
================================================
'use client';

import { Button } from '@/components/ui/base/button';
import { Input } from '@/components/ui/base/input';
import { Label } from '@/components/ui/base/label';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { authClient } from '@/lib/auth-client';
import React from 'react';
import Link from 'next/link';
import { useToast } from '@/hooks/use-toast';
import { Toaster } from '@/components/ui/toaster';
import { Search, Mail, Lock } from 'lucide-react';
import KoelBirdRounded from '@/components/ui/base/koel-bird-rounded';

const ONBOARDING_URL = '/onboarding/welcome'; // Changed from dashboard to onboarding
const RETURNING_USER_URL = '/dashboard';

export default function AuthScreen() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const router = useRouter();
  const { toast } = useToast();

  const handleSignIn = async e => {
    e.preventDefault();
    setIsLoading(true);

    try {
      const { error } = await authClient.signIn.email({
        email,
        password,
        rememberMe: true,
      });

      if (error) {
        toast({
          title: 'Authentication failed',
          description: error.message,
          variant: 'destructive',
        });
      } else {
        toast({
          title: 'Success!',
          description: "You've been signed in successfully",
        });
        router.push(RETURNING_USER_URL);
      }
    } catch (err) {
      toast({
        title: 'Something went wrong',
        description: 'Please try again later',
        variant: 'destructive',
      });
    } finally {
      setIsLoading(false);
    }
  };

  const handlePasswordReset = async () => {
    if (!email) {
      toast({
        title: 'Email required',
        description: 'Please enter your email address first',
        variant: 'destructive',
      });
      return;
    }

    setIsLoading(true);
    try {
      const { error } = await authClient.requestPasswordReset({
        email: email,
        redirectTo: '/reset-password',
      });

      if (error) {
        toast({
          title: 'Reset failed',
          description: error.message,
          variant: 'destructive',
        });
      } else {
        toast({
          title: 'Email sent',
          description: 'Check your inbox for password reset instructions',
        });
      }
    } catch (err) {
      toast({
        title: 'Something went wrong',
        description: 'Please try again later',
        variant: 'destructive',
      });
    } finally {
      setIsLoading(false);
    }
  };

  const handleSocialSignIn = async provider => {
    setIsLoading(true);
    try {
      const { error } = await authClient.signIn.social({
        provider,
        callbackURL: RETURNING_USER_URL,
        newUserCallbackURL: ONBOARDING_URL,
      });

      if (error) {
        toast({
          title: 'Authentication failed',
          description: error.message,
          variant: 'destructive',
        });
      }
    } catch (err) {
      toast({
        title: 'Something went wrong',
        description: 'Please try again later',
        variant: 'destructive',
      });
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div className="w-full min-h-screen bg-white dark:bg-neutral-950/[0.99] tracking-[-0.015em] relative overflow-hidden flex items-center justify-center">
      {/* Repeating line pattern - top */}
      <div className="absolute top-0 left-0 w-full h-[6vh] overflow-hidden flex items-end justify-center bg-neutral-50">
        <div className="flex h-full items-end gap-2">
          {Array(500)
            .fill(0)
            .map((_, i) => (
              <div
                key={`top-${i}`}
                className="h-full w-px bg-neutral-200 dark:bg-neutral-800"
              ></div>
            ))}
        </div>
      </div>

      <div className="flex items-center justify-center my-12 relative w-full h-[90vh] bg-neutral-50/20 backdrop-blur-md border-y border-neutral-200 transform-gpu dark:border-neutral-800 z-10">
        <div className="mx-auto grid w-full px-6 sm:w-[420px] gap-8 relative z-10">
          <div className="grid gap-2 text-center">
            <KoelBirdRounded className="w-16 h-16 mx-auto" />
            <h1 className="text-2xl font-semibold tracking-tighter text-black dark:text-white">
              <span className="relative">Welcome Back!</span>
            </h1>
            <p className="text-balance text-md text-muted-foreground">
              Sign in to your account to continue
            </p>
          </div>

          <form onSubmit={handleSignIn} className="grid gap-5">
            <div className="grid gap-4">
              <div className="space-y-2">
                <Label htmlFor="email" className="text-sm font-medium ml-1">
                  Email
                </Label>
                <div className="relative mt-1.5">
                  <div className="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3 text-muted-foreground z-20">
                    <Mail size={16} strokeWidth={2} aria-hidden="true" />
                  </div>
                  <Input
                    id="email"
                    type="email"
                    value={email}
                    className="pl-10 h-10 rounded-xl border-neutral-200 bg-white/80 backdrop-blur-sm"
                    placeholder="name@example.com"
                    required
                    onChange={e => setEmail(e.target.value)}
                  />
                </div>
              </div>

              <div className="space-y-2">
                <div className="flex items-center justify-between">
                  <Label htmlFor="password" className="text-sm font-medium ml-1">
                    Password
                  </Label>
                  <Button
                    type="button"
                    variant="link"
                    className="text-xs font-medium text-sky-600 hover:text-sky-700 p-0 h-auto"
                    onClick={handlePasswordReset}
                    disabled={isLoading}
                  >
                    Forgot password?
                  </Button>
                </div>
                <div className="relative">
                  <div className="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3 text-muted-foreground z-20">
                    <Lock size={16} strokeWidth={2} aria-hidden="true" />
                  </div>
                  <Input
                    id="password"
                    type="password"
                    className="pl-10 h-10 rounded-xl border-neutral-200 bg-white/80 backdrop-blur-sm"
                    required
                    placeholder="••••••••••••••"
                    onChange={e => setPassword(e.target.value)}
                  />
                </div>
              </div>
            </div>

            <Button
              className="w-full h-10 rounded-xl font-medium bg-black hover:bg-neutral-800 text-white dark:bg-sky-600 dark:hover:bg-sky-700 mt-1"
              type="submit"
              disabled={isLoading}
            >
              {isLoading ? 'Signing in...' : 'Sign in'}
            </Button>

            <div className="flex items-center gap-4 my-2">
              <div className="h-px bg-neutral-200 dark:bg-neutral-800 flex-1"></div>
              <span className="text-xs text-neutral-500 dark:text-neutral-400">
                or continue with
              </span>
              <div className="h-px bg-neutral-200 dark:bg-neutral-800 flex-1"></div>
            </div>

            <div className="grid grid-cols-2 gap-3">
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-9 rounded-xl border-neutral-200 hover:bg-neutral-50 text-sm bg-white/80 backdrop-blur-sm"
                onClick={() => handleSocialSignIn('google')}
                disabled={isLoading}
              >
                <svg
                  className="h-4 w-4 mr-2"
                  width="754"
                  height="768"
                  viewBox="0 0 754 768"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M753.32 392.727C753.32 365.498 750.876 339.316 746.338 314.182H384.68V462.895H591.342C582.266 510.72 555.036 551.215 514.193 578.444V675.142H638.818C711.429 608.116 753.32 509.673 753.32 392.727Z"
                    fill="#4285F4"
                  />
                  <path
                    d="M384.68 768C488.36 768 575.284 733.789 638.818 675.142L514.193 578.444C479.982 601.484 436.346 615.447 384.68 615.447C284.84 615.447 200.011 548.073 169.64 457.309H41.8728V556.451C105.058 681.775 234.571 768 384.68 768Z"
                    fill="#34A853"
                  />
                  <path
                    d="M169.64 456.96C161.96 433.92 157.422 409.484 157.422 384C157.422 358.516 161.96 334.08 169.64 311.04V211.898H41.8728C15.691 263.564 0.680054 321.862 0.680054 384C0.680054 446.138 15.691 504.436 41.8728 556.102L141.364 478.604L169.64 456.96Z"
                    fill="#FBBC05"
                  />
                  <path
                    d="M384.68 152.902C441.233 152.902 491.502 172.451 531.647 210.153L641.611 100.189C574.935 38.0509 488.36 0 384.68 0C234.571 0 105.058 86.2255 41.8728 211.898L169.64 311.04C200.011 220.276 284.84 152.902 384.68 152.902Z"
                    fill="#EA4335"
                  />
                </svg>
                Google
              </Button>
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-9 rounded-xl border-neutral-200 hover:bg-neutral-50 text-sm bg-white/80 backdrop-blur-sm"
                onClick={() => handleSocialSignIn('wechat')}
                disabled={isLoading}
              >
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  className="h-4 w-4 mr-2"
                  viewBox="0 0 800 800"
                  fill="none"
                >
                  <g clipPath="url(#clip0_3668_300)">
                    <path
                      fill="#2DC100"
                      d="M800 680c0 66.277-53.725 120-120 120H120C53.723 800 0 746.277 0 680V120C0 53.725 53.725 0 120 0h560c66.275 0 120 53.725 120 120z"
                    ></path>
                    <path
                      fill="#fff"
                      d="M535.476 298.345c-64.568 3.373-120.715 22.946-166.299 67.167-46.056 44.678-67.08 99.425-61.333 167.291-25.238-3.125-48.224-6.565-71.342-8.512-7.984-.672-17.458.283-24.221 4.099-22.448 12.667-43.968 26.968-69.475 42.912 4.68-21.168 7.71-39.704 13.072-57.533 3.944-13.104 2.118-20.398-9.954-28.931-77.51-54.723-110.182-136.619-85.731-220.933 22.621-78 78.173-125.304 153.656-149.963 103.027-33.653 218.811.675 281.459 82.472 22.626 29.547 36.501 62.709 40.168 101.931M238.31 272.073c.595-15.422-12.768-29.315-28.64-29.779-16.25-.477-29.616 11.941-30.09 27.955-.48 16.229 11.933 29.234 28.301 29.65 16.227.411 29.829-12.024 30.429-27.826m155.043-29.79c-15.931.294-29.392 13.862-29.109 29.344.29 16.048 13.496 28.603 29.877 28.406 16.424-.198 28.88-12.886 28.725-29.272-.136-16.086-13.282-28.774-29.493-28.478"
                    ></path>
                    <path
                      fill="#fff"
                      d="M680.538 700.878c-20.446-9.104-39.2-22.762-59.168-24.848-19.891-2.077-40.8 9.398-61.611 11.526-63.389 6.485-120.179-11.182-167.005-54.486-89.059-82.373-76.334-208.677 26.704-276.181 91.576-59.995 225.877-39.995 290.442 43.251 56.344 72.64 49.723 169.066-19.061 230.09-19.904 17.662-27.067 32.195-14.296 55.478 2.357 4.298 2.627 9.741 3.995 15.17m-232.731-225.33c13.016.013 23.733-10.174 24.227-23.03.52-13.61-10.427-25.026-24.056-25.082-13.494-.062-24.798 11.514-24.328 24.922.442 12.811 11.234 23.174 24.157 23.19m150.029-48.059c-12.629-.088-23.36 10.251-23.874 23.011-.547 13.645 10.058 24.85 23.562 24.885 13.062.043 23.382-9.835 23.856-22.832.507-13.677-10.104-24.971-23.544-25.064"
                    ></path>
                  </g>
                  <defs>
                    <clipPath id="clip0_3668_300">
                      <path fill="#fff" d="M0 0h800v800H0z"></path>
                    </clipPath>
                  </defs>
                </svg>
                WeChat
              </Button>
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-9 rounded-xl border-neutral-200 hover:bg-neutral-50 text-sm bg-white/80 backdrop-blur-sm"
                onClick={() => handleSocialSignIn('facebook')}
                disabled={isLoading}
              >
                <svg
                  className="h-6 w-6 mr-1.5"
                  width="934"
                  height="934"
                  viewBox="0 0 934 934"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <mask
                    id="mask0_1728_218"
                    maskUnits="userSpaceOnUse"
                    x="0"
                    y="0"
                    width="934"
                    height="934"
                  >
                    <path d="M0 0.000706673H933.333V933.334H0V0.000706673Z" fill="white" />
                  </mask>
                  <g mask="url(#mask0_1728_218)">
                    <path
                      d="M800 466.669C800 282.574 650.761 133.335 466.666 133.335C282.572 133.335 133.333 282.574 133.333 466.669C133.333 622.995 240.953 754.165 386.141 790.186V568.53H317.405V466.669H386.141V422.777C386.141 309.321 437.485 256.734 548.872 256.734C569.989 256.734 606.428 260.874 621.334 265.015V357.354C613.466 356.526 599.802 356.111 582.825 356.111C528.168 356.111 507.049 376.815 507.049 430.645V466.669H615.928L597.224 568.53H507.049V797.561C672.097 777.626 800 637.093 800 466.669Z"
                      fill="#0866FF"
                    />
                    <path
                      d="M597.223 568.53L615.928 466.669H507.05V430.643C507.05 376.814 528.167 356.111 582.824 356.111C599.802 356.111 613.466 356.525 621.334 357.353V265.015C606.427 260.874 569.988 256.733 548.871 256.733C437.486 256.733 386.14 309.321 386.14 422.777V466.669H317.404V568.53H386.14V790.186C411.931 796.583 438.898 800.002 466.666 800.002C480.338 800.002 493.81 799.159 507.05 797.561V568.53H597.223Z"
                      fill="white"
                    />
                  </g>
                </svg>
                Facebook
              </Button>
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-9 rounded-xl border-neutral-200 hover:bg-neutral-50 text-sm bg-white/80 backdrop-blur-sm"
                onClick={() => handleSocialSignIn('microsoft')}
                disabled={isLoading}
              >
                <svg
                  className="h-4 w-4 mr-2"
                  width="171"
                  height="172"
                  viewBox="0 0 171 172"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path d="M81.1557 81.7631H0V0.607422H81.1557V81.7631Z" fill="#F1511B" />
                  <path d="M170.761 81.7631H89.6064V0.607422H170.761V81.7631Z" fill="#80CC28" />
                  <path d="M81.1534 171.399H0V90.2441H81.1534V171.399Z" fill="#00ADEF" />
                  <path d="M170.761 171.399H89.6064V90.2441H170.761V171.399Z" fill="#FBBC09" />
                </svg>
                Microsoft
              </Button>
            </div>
          </form>

          <div className="text-center">
            <p className="text-xs text-neutral-600 dark:text-neutral-400">
              Don't have an account?{' '}
              <Link
                href="/sign-up"
                className="font-medium text-sky-600 hover:text-sky-700 hover:underline"
              >
                Sign up
              </Link>
            </p>
          </div>
        </div>
      </div>

      {/* Repeating line pattern - bottom */}
      <div className="absolute bottom-0 left-0 w-full h-[6vh] overflow-hidden flex items-start justify-center bg-neutral-50 z-[1]">
        <div className="flex h-full items-start gap-2">
          {Array(500)
            .fill(0)
            .map((_, i) => (
              <div
                key={`bottom-${i}`}
                className="h-full w-px bg-neutral-200 dark:bg-neutral-800"
              ></div>
            ))}
        </div>
      </div>

      <Toaster />
    </div>
  );
}



================================================
FILE: app/sign-up/page.tsx
================================================
'use client';

import { Button } from '@/components/ui/base/button';
import { Input } from '@/components/ui/base/input';
import { Label } from '@/components/ui/base/label';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { authClient } from '@/lib/auth-client';
import React from 'react';
import Link from 'next/link';
import { useToast } from '@/hooks/use-toast';
import { Toaster } from '@/components/ui/toaster';
import { Mail, Lock, User } from 'lucide-react';
import KoelBirdRounded from '@/components/ui/base/koel-bird-rounded';

const ONBOARDING_URL = '/onboarding/welcome'; // Changed from dashboard to onboarding

export default function SignUpScreen() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const router = useRouter();
  const { toast } = useToast();

  const handleSignUp = async e => {
    e.preventDefault();
    setIsLoading(true);

    try {
      const { error } = await authClient.signUp.email(
        {
          email,
          password,
          name,
        },
        {
          onRequest: () => {
            // Loading handled by isLoading state
          },
        },
      );

      if (error) {
        toast({
          title: 'Sign up failed',
          description: error.message,
          variant: 'destructive',
        });
      } else {
        toast({
          title: 'Account created',
          description: 'Welcome to Koel! Please check your email to verify your account.',
        });
        router.push(ONBOARDING_URL);
      }
    } catch (err) {
      toast({
        title: 'Something went wrong',
        description: 'Please try again later',
        variant: 'destructive',
      });
    } finally {
      setIsLoading(false);
    }
  };

  const handleSocialSignUp = async provider => {
    setIsLoading(true);
    try {
      const { error } = await authClient.signIn.social({
        provider,
        callbackURL: ONBOARDING_URL,
      });

      if (error) {
        toast({
          title: 'Sign up failed',
          description: error.message,
          variant: 'destructive',
        });
      }
    } catch (err) {
      toast({
        title: 'Something went wrong',
        description: 'Please try again later',
        variant: 'destructive',
      });
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div className="w-full min-h-screen bg-white dark:bg-neutral-950/[0.99] tracking-[-0.015em] relative overflow-hidden flex items-center justify-center">
      <div className="absolute top-0 opacity-0 left-0 w-full h-full overflow-hidden pointer-events-none">
        <div className="absolute top-[60%] -left-[10%] w-[40%] h-[40%] bg-sky-500/20 dark:bg-sky-600/20 rounded-full blur-[100px] animate-blob opacity-75"></div>
        <div className="absolute top-[25%] -left-[15%] w-[40%] h-[30%] bg-sky-300/20 dark:bg-sky-400/20 rounded-full blur-[100px] animate-blob animation-delay-4000 opacity-75"></div>

        <div className="absolute top-[60%] -right-[10%] w-[40%] h-[40%] bg-blue-500/20 dark:bg-blue-600/20 rounded-full blur-[100px] animate-blob animation-delay-2000 opacity-75"></div>
        <div className="absolute top-[25%] -right-[15%] w-[40%] h-[30%] bg-sky-300/20 dark:bg-sky-400/20 rounded-full blur-[100px] animate-blob animation-delay-4000 opacity-75"></div>
      </div>

      {/* Repeating line pattern - top */}
      <div className="absolute top-0 left-0 w-full h-[6vh] overflow-hidden flex items-end justify-center bg-neutral-50">
        <div className="flex h-full items-end gap-2">
          {Array(500)
            .fill(0)
            .map((_, i) => (
              <div
                key={`top-${i}`}
                className="h-full w-px bg-neutral-200 dark:bg-neutral-800"
              ></div>
            ))}
        </div>
      </div>

      <div className="flex items-center justify-center my-12 relative w-full h-[90vh] bg-neutral-50/20 backdrop-blur-md border-y border-neutral-200 transform-gpu dark:border-neutral-800 z-10">
        <div className="mx-auto grid w-full px-6 sm:w-[420px] gap-8 relative z-10">
          <div className="grid gap-2 text-center">
            <KoelBirdRounded className="w-16 h-16 mx-auto" />
            <h1 className="text-2xl font-semibold tracking-tighter text-black dark:text-white">
              <span className="relative">Get Started Today</span>
            </h1>
            <p className="text-balance text-md text-muted-foreground">
              Sign up to get started with Koel Labs.
            </p>
          </div>

          <form onSubmit={handleSignUp} className="grid gap-5">
            <div className="grid gap-4">
              <div className="space-y-2">
                <Label htmlFor="name" className="text-sm font-medium ml-1">
                  Name
                </Label>
                <div className="relative mt-1">
                  <div className="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3 text-muted-foreground z-20">
                    <User size={16} strokeWidth={2} aria-hidden="true" />
                  </div>
                  <Input
                    id="name"
                    type="text"
                    value={name}
                    className="pl-10 h-10 rounded-xl border-neutral-200 bg-white/80 backdrop-blur-sm"
                    placeholder="Your name"
                    required
                    onChange={e => setName(e.target.value)}
                  />
                </div>
              </div>

              <div className="space-y-2">
                <Label htmlFor="email" className="text-sm font-medium ml-1">
                  Email
                </Label>
                <div className="relative mt-1">
                  <div className="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3 text-muted-foreground z-20">
                    <Mail size={16} strokeWidth={2} aria-hidden="true" />
                  </div>
                  <Input
                    id="email"
                    type="email"
                    value={email}
                    className="pl-10 h-10 rounded-xl border-neutral-200 bg-white/80 backdrop-blur-sm"
                    placeholder="name@example.com"
                    required
                    onChange={e => setEmail(e.target.value)}
                  />
                </div>
              </div>

              <div className="space-y-2">
                <Label htmlFor="password" className="text-sm font-medium ml-1">
                  Password
                </Label>
                <div className="relative mt-1">
                  <div className="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3 text-muted-foreground z-20">
                    <Lock size={16} strokeWidth={2} aria-hidden="true" />
                  </div>
                  <Input
                    id="password"
                    type="password"
                    className="pl-10 h-10 rounded-xl border-neutral-200 bg-white/80 backdrop-blur-sm"
                    required
                    placeholder="•••••••••••••"
                    onChange={e => setPassword(e.target.value)}
                  />
                </div>
                <p className="text-xs text-muted-foreground ml-1 mt-1">
                  Password must be at least 8 characters
                </p>
              </div>
            </div>

            <Button
              className="w-full h-10 rounded-xl font-medium bg-black hover:bg-neutral-800 text-white dark:bg-sky-600 dark:hover:bg-sky-700 mt-1"
              type="submit"
              disabled={isLoading}
            >
              {isLoading ? 'Creating account...' : 'Sign up'}
            </Button>

            <div className="flex items-center gap-4 my-2">
              <div className="h-px bg-neutral-200 dark:bg-neutral-800 flex-1"></div>
              <span className="text-xs text-neutral-500 dark:text-neutral-400">
                or continue with
              </span>
              <div className="h-px bg-neutral-200 dark:bg-neutral-800 flex-1"></div>
            </div>

            <div className="grid grid-cols-2 gap-3">
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-9 rounded-xl border-neutral-200 hover:bg-neutral-50 text-sm bg-white/80 backdrop-blur-sm"
                onClick={() => handleSocialSignUp('google')}
                disabled={isLoading}
              >
                <svg
                  className="h-4 w-4 mr-2"
                  width="754"
                  height="768"
                  viewBox="0 0 754 768"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M753.32 392.727C753.32 365.498 750.876 339.316 746.338 314.182H384.68V462.895H591.342C582.266 510.72 555.036 551.215 514.193 578.444V675.142H638.818C711.429 608.116 753.32 509.673 753.32 392.727Z"
                    fill="#4285F4"
                  />
                  <path
                    d="M384.68 768C488.36 768 575.284 733.789 638.818 675.142L514.193 578.444C479.982 601.484 436.346 615.447 384.68 615.447C284.84 615.447 200.011 548.073 169.64 457.309H41.8728V556.451C105.058 681.775 234.571 768 384.68 768Z"
                    fill="#34A853"
                  />
                  <path
                    d="M169.64 456.96C161.96 433.92 157.422 409.484 157.422 384C157.422 358.516 161.96 334.08 169.64 311.04V211.898H41.8728C15.691 263.564 0.680054 321.862 0.680054 384C0.680054 446.138 15.691 504.436 41.8728 556.102L141.364 478.604L169.64 456.96Z"
                    fill="#FBBC05"
                  />
                  <path
                    d="M384.68 152.902C441.233 152.902 491.502 172.451 531.647 210.153L641.611 100.189C574.935 38.0509 488.36 0 384.68 0C234.571 0 105.058 86.2255 41.8728 211.898L169.64 311.04C200.011 220.276 284.84 152.902 384.68 152.902Z"
                    fill="#EA4335"
                  />
                </svg>
                Google
              </Button>
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-9 rounded-xl border-neutral-200 hover:bg-neutral-50 text-sm bg-white/80 backdrop-blur-sm"
                onClick={() => handleSocialSignUp('wechat')}
                disabled={isLoading}
              >
                <svg
                  className="h-4 w-4 mr-2"
                  viewBox="0 0 800 800"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <g clipPath="url(#clip0_3668_300)">
                    <path
                      fill="#2DC100"
                      d="M800 680c0 66.277-53.725 120-120 120H120C53.723 800 0 746.277 0 680V120C0 53.725 53.725 0 120 0h560c66.275 0 120 53.725 120 120z"
                    ></path>
                    <path
                      fill="#fff"
                      d="M535.476 298.345c-64.568 3.373-120.715 22.946-166.299 67.167-46.056 44.678-67.08 99.425-61.333 167.291-25.238-3.125-48.224-6.565-71.342-8.512-7.984-.672-17.458.283-24.221 4.099-22.448 12.667-43.968 26.968-69.475 42.912 4.68-21.168 7.71-39.704 13.072-57.533 3.944-13.104 2.118-20.398-9.954-28.931-77.51-54.723-110.182-136.619-85.731-220.933 22.621-78 78.173-125.304 153.656-149.963 103.027-33.653 218.811.675 281.459 82.472 22.626 29.547 36.501 62.709 40.168 101.931M238.31 272.073c.595-15.422-12.768-29.315-28.64-29.779-16.25-.477-29.616 11.941-30.09 27.955-.48 16.229 11.933 29.234 28.301 29.65 16.227.411 29.829-12.024 30.429-27.826m155.043-29.79c-15.931.294-29.392 13.862-29.109 29.344.29 16.048 13.496 28.603 29.877 28.406 16.424-.198 28.88-12.886 28.725-29.272-.136-16.086-13.282-28.774-29.493-28.478"
                    ></path>
                    <path
                      fill="#fff"
                      d="M680.538 700.878c-20.446-9.104-39.2-22.762-59.168-24.848-19.891-2.077-40.8 9.398-61.611 11.526-63.389 6.485-120.179-11.182-167.005-54.486-89.059-82.373-76.334-208.677 26.704-276.181 91.576-59.995 225.877-39.995 290.442 43.251 56.344 72.64 49.723 169.066-19.061 230.09-19.904 17.662-27.067 32.195-14.296 55.478 2.357 4.298 2.627 9.741 3.995 15.17m-232.731-225.33c13.016.013 23.733-10.174 24.227-23.03.52-13.61-10.427-25.026-24.056-25.082-13.494-.062-24.798 11.514-24.328 24.922.442 12.811 11.234 23.174 24.157 23.19m150.029-48.059c-12.629-.088-23.36 10.251-23.874 23.011-.547 13.645 10.058 24.85 23.562 24.885 13.062.043 23.382-9.835 23.856-22.832.507-13.677-10.104-24.971-23.544-25.064"
                    ></path>
                  </g>
                  <defs>
                    <clipPath id="clip0_3668_300">
                      <path fill="#fff" d="M0 0h800v800H0z"></path>
                    </clipPath>
                  </defs>
                </svg>
                WeChat
              </Button>
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-9 rounded-xl border-neutral-200 hover:bg-neutral-50 text-sm bg-white/80 backdrop-blur-sm"
                onClick={() => handleSocialSignUp('facebook')}
                disabled={isLoading}
              >
                <svg
                  className="h-6 w-6 mr-2"
                  width="934"
                  height="934"
                  viewBox="0 0 934 934"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <mask
                    id="mask0_1728_218"
                    maskUnits="userSpaceOnUse"
                    x="0"
                    y="0"
                    width="934"
                    height="934"
                  >
                    <path d="M0 0.000706673H933.333V933.334H0V0.000706673Z" fill="white" />
                  </mask>
                  <g mask="url(#mask0_1728_218)">
                    <path
                      d="M800 466.669C800 282.574 650.761 133.335 466.666 133.335C282.572 133.335 133.333 282.574 133.333 466.669C133.333 622.995 240.953 754.165 386.141 790.186V568.53H317.405V466.669H386.141V422.777C386.141 309.321 437.485 256.734 548.872 256.734C569.989 256.734 606.428 260.874 621.334 265.015V357.354C613.466 356.526 599.802 356.111 582.825 356.111C528.168 356.111 507.049 376.815 507.049 430.645V466.669H615.928L597.224 568.53H507.049V797.561C672.097 777.626 800 637.093 800 466.669Z"
                      fill="#0866FF"
                    />
                    <path
                      d="M597.223 568.53L615.928 466.669H507.05V430.643C507.05 376.814 528.167 356.111 582.824 356.111C599.802 356.111 613.466 356.525 621.334 357.353V265.015C606.427 260.874 569.988 256.733 548.871 256.733C437.486 256.733 386.14 309.321 386.14 422.777V466.669H317.404V568.53H386.14V790.186C411.931 796.583 438.898 800.002 466.666 800.002C480.338 800.002 493.81 799.159 507.05 797.561V568.53H597.223Z"
                      fill="white"
                    />
                  </g>
                </svg>
                Facebook
              </Button>
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-9 rounded-xl border-neutral-200 hover:bg-neutral-50 text-sm bg-white/80 backdrop-blur-sm"
                onClick={() => handleSocialSignUp('microsoft')}
                disabled={isLoading}
              >
                <svg
                  className="h-4 w-4 mr-2"
                  width="171"
                  height="172"
                  viewBox="0 0 171 172"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path d="M81.1557 81.7631H0V0.607422H81.1557V81.7631Z" fill="#F1511B" />
                  <path d="M170.761 81.7631H89.6064V0.607422H170.761V81.7631Z" fill="#80CC28" />
                  <path d="M81.1534 171.399H0V90.2441H81.1534V171.399Z" fill="#00ADEF" />
                  <path d="M170.761 171.399H89.6064V90.2441H170.761V171.399Z" fill="#FBBC09" />
                </svg>
                Microsoft
              </Button>
            </div>
          </form>

          <div className="text-center">
            <p className="text-xs text-neutral-600 dark:text-neutral-400">
              Already have an account?{' '}
              <Link
                href="/sign-in"
                className="font-medium text-sky-600 hover:text-sky-700 hover:underline"
              >
                Sign in
              </Link>
            </p>
          </div>
        </div>
      </div>

      {/* Repeating line pattern - bottom */}
      <div className="absolute bottom-0 left-0 w-full h-[6vh] overflow-hidden flex items-start justify-center bg-neutral-50 z-[1]">
        <div className="flex h-full items-start gap-2">
          {Array(400)
            .fill(0)
            .map((_, i) => (
              <div
                key={`bottom-${i}`}
                className="h-full w-px bg-neutral-200 dark:bg-neutral-800"
              ></div>
            ))}
        </div>
      </div>

      <Toaster />
    </div>
  );
}



================================================
FILE: components/comp-331.jsx
================================================
'use client';

import { useCharacterLimit } from '@/hooks/use-character-limit';
import { useImageUpload } from '@/hooks/use-image-upload';
import { Button } from '@/components/ui/base/button';
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '@/components/ui/base/dialog';
import { Input } from '@/components/ui/base/input';
import { Label } from '@/components/ui/base/label';
import { Textarea } from '@/components/ui/base/textarea';
import { Check, ImagePlus, X } from 'lucide-react';
import { useId, useState } from 'react';

export default function Component() {
  const id = useId();

  const maxLength = 180;
  const {
    value,
    characterCount,
    handleChange,
    maxLength: limit,
  } = useCharacterLimit({
    maxLength,
    initialValue:
      'Hey, I am Margaret, a web developer who loves turning ideas into amazing websites!',
  });

  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="outline">Edit profile</Button>
      </DialogTrigger>
      <DialogContent className="flex flex-col gap-0 overflow-y-visible p-0 sm:max-w-lg [&>button:last-child]:top-3.5">
        <DialogHeader className="contents space-y-0 text-left">
          <DialogTitle className="border-b border-border px-6 py-4 text-base">
            Edit profile
          </DialogTitle>
        </DialogHeader>
        <DialogDescription className="sr-only">
          Make changes to your profile here. You can change your photo and set a username.
        </DialogDescription>
        <div className="overflow-y-auto">
          <ProfileBg defaultImage="/profile-bg.jpg" />
          <Avatar defaultImage="/avatar-72-01.jpg" />
          <div className="px-6 pb-6 pt-4">
            <form className="space-y-4">
              <div className="flex flex-col gap-4 sm:flex-row">
                <div className="flex-1 space-y-2">
                  <Label htmlFor={`${id}-first-name`}>First name</Label>
                  <Input
                    id={`${id}-first-name`}
                    placeholder="Matt"
                    defaultValue="Margaret"
                    type="text"
                    required
                  />
                </div>
                <div className="flex-1 space-y-2">
                  <Label htmlFor={`${id}-last-name`}>Last name</Label>
                  <Input
                    id={`${id}-last-name`}
                    placeholder="Welsh"
                    defaultValue="Villard"
                    type="text"
                    required
                  />
                </div>
              </div>
              <div className="space-y-2">
                <Label htmlFor={`${id}-username`}>Username</Label>
                <div className="relative">
                  <Input
                    id={`${id}-username`}
                    className="peer pe-9"
                    placeholder="Username"
                    defaultValue="margaret-villard-69"
                    type="text"
                    required
                  />
                  <div className="pointer-events-none absolute inset-y-0 end-0 flex items-center justify-center pe-3 text-muted-foreground/80 peer-disabled:opacity-50">
                    <Check
                      size={16}
                      strokeWidth={2}
                      className="text-emerald-500"
                      aria-hidden="true"
                    />
                  </div>
                </div>
              </div>
              <div className="space-y-2">
                <Label htmlFor={`${id}-website`}>Website</Label>
                <div className="flex rounded-lg shadow-xs shadow-black/5">
                  <span className="-z-10 inline-flex items-center rounded-s-lg border border-input bg-background px-3 text-sm text-muted-foreground">
                    https://
                  </span>
                  <Input
                    id={`${id}-website`}
                    className="-ms-px rounded-s-none shadow-none"
                    placeholder="yourwebsite.com"
                    defaultValue="www.margaret.com"
                    type="text"
                  />
                </div>
              </div>
              <div className="space-y-2">
                <Label htmlFor={`${id}-bio`}>Biography</Label>
                <Textarea
                  id={`${id}-bio`}
                  placeholder="Write a few sentences about yourself"
                  defaultValue={value}
                  maxLength={maxLength}
                  onChange={handleChange}
                  aria-describedby={`${id}-description`}
                />
                <p
                  id={`${id}-description`}
                  className="mt-2 text-right text-xs text-muted-foreground"
                  role="status"
                  aria-live="polite"
                >
                  <span className="tabular-nums">{limit - characterCount}</span> characters left
                </p>
              </div>
            </form>
          </div>
        </div>
        <DialogFooter className="border-t border-border px-6 py-4">
          <DialogClose asChild>
            <Button type="button" variant="outline">
              Cancel
            </Button>
          </DialogClose>
          <DialogClose asChild>
            <Button type="button">Save changes</Button>
          </DialogClose>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

function ProfileBg({ defaultImage }) {
  const [hideDefault, setHideDefault] = useState(false);
  const { previewUrl, fileInputRef, handleThumbnailClick, handleFileChange, handleRemove } =
    useImageUpload();

  const currentImage = previewUrl || (!hideDefault ? defaultImage : null);

  const handleImageRemove = () => {
    handleRemove();
    setHideDefault(true);
  };

  return (
    <div className="h-32">
      <div className="relative flex h-full w-full items-center justify-center overflow-hidden bg-muted">
        {currentImage && (
          <img
            className="h-full w-full object-cover"
            src={currentImage}
            alt={previewUrl ? 'Preview of uploaded image' : 'Default profile background'}
            width={512}
            height={96}
          />
        )}
        <div className="absolute inset-0 flex items-center justify-center gap-2">
          <button
            type="button"
            className="z-50 flex size-10 cursor-pointer items-center justify-center rounded-full bg-black/60 text-white outline-offset-2 transition-colors hover:bg-black/80 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring/70"
            onClick={handleThumbnailClick}
            aria-label={currentImage ? 'Change image' : 'Upload image'}
          >
            <ImagePlus size={16} strokeWidth={2} aria-hidden="true" />
          </button>
          {currentImage && (
            <button
              type="button"
              className="z-50 flex size-10 cursor-pointer items-center justify-center rounded-full bg-black/60 text-white outline-offset-2 transition-colors hover:bg-black/80 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring/70"
              onClick={handleImageRemove}
              aria-label="Remove image"
            >
              <X size={16} strokeWidth={2} aria-hidden="true" />
            </button>
          )}
        </div>
      </div>
      <input
        type="file"
        ref={fileInputRef}
        onChange={handleFileChange}
        className="hidden"
        accept="image/*"
        aria-label="Upload image file"
      />
    </div>
  );
}

function Avatar({ defaultImage }) {
  const { previewUrl, fileInputRef, handleThumbnailClick, handleFileChange } = useImageUpload();

  const currentImage = previewUrl || defaultImage;

  return (
    <div className="-mt-10 px-6">
      <div className="relative flex size-20 items-center justify-center overflow-hidden rounded-full border-4 border-background bg-muted shadow-xs shadow-black/10">
        {currentImage && (
          <img
            src={currentImage}
            className="h-full w-full object-cover"
            width={80}
            height={80}
            alt="Profile image"
          />
        )}
        <button
          type="button"
          className="absolute flex size-8 cursor-pointer items-center justify-center rounded-full bg-black/60 text-white outline-offset-2 transition-colors hover:bg-black/80 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring/70"
          onClick={handleThumbnailClick}
          aria-label="Change profile picture"
        >
          <ImagePlus size={16} strokeWidth={2} aria-hidden="true" />
        </button>
        <input
          type="file"
          ref={fileInputRef}
          onChange={handleFileChange}
          className="hidden"
          accept="image/*"
          aria-label="Upload profile picture"
        />
      </div>
    </div>
  );
}



================================================
FILE: components/comp-433.jsx
================================================
import { Badge } from '@/components/ui/badge';
import { ScrollArea, ScrollBar } from '@/components/ui/base/scroll-area';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/base/tabs';
import { Box, House, PanelsTopLeft } from 'lucide-react';

export default function Component() {
  return (
    <Tabs defaultValue="tab-1">
      <ScrollArea>
        <TabsList className="mb-3">
          <TabsTrigger value="tab-1">
            <House
              className="-ms-0.5 me-1.5 opacity-60"
              size={16}
              strokeWidth={2}
              aria-hidden="true"
            />
            Overview
          </TabsTrigger>
          <TabsTrigger value="tab-2" className="group">
            <PanelsTopLeft
              className="-ms-0.5 me-1.5 opacity-60"
              size={16}
              strokeWidth={2}
              aria-hidden="true"
            />
            Projects
            <Badge
              className="ms-1.5 min-w-5 bg-primary/15 px-1 transition-opacity group-data-[state=inactive]:opacity-50"
              variant="secondary"
            >
              3
            </Badge>
          </TabsTrigger>
          <TabsTrigger value="tab-3" className="group">
            <Box
              className="-ms-0.5 me-1.5 opacity-60"
              size={16}
              strokeWidth={2}
              aria-hidden="true"
            />
            Packages
            <Badge className="ms-1.5 transition-opacity group-data-[state=inactive]:opacity-50">
              New
            </Badge>
          </TabsTrigger>
        </TabsList>
        <ScrollBar orientation="horizontal" />
      </ScrollArea>
      <TabsContent value="tab-1">
        <p className="p-4 pt-1 text-center text-xs text-muted-foreground">Content for Tab 1</p>
      </TabsContent>
      <TabsContent value="tab-2">
        <p className="p-4 pt-1 text-center text-xs text-muted-foreground">Content for Tab 2</p>
      </TabsContent>
      <TabsContent value="tab-3">
        <p className="p-4 pt-1 text-center text-xs text-muted-foreground">Content for Tab 3</p>
      </TabsContent>
    </Tabs>
  );
}



================================================
FILE: components/magic-highlighter.tsx
================================================
'use client';

import React, { useEffect, useRef } from 'react';

type MagicHighlighterProps = {
  containerRef?: React.RefObject<HTMLElement | null>;
  className?: string;
};

const DEFAULTS = {
  size: 400,
  color: '#0086FF',
  opacity: 1,
};

function isMobilePointer(): boolean {
  if (typeof navigator !== 'undefined' && (navigator as any).maxTouchPoints > 0) return true;
  if (
    typeof window !== 'undefined' &&
    (window as any).matchMedia &&
    (window as any).matchMedia('(pointer: coarse)').matches
  )
    return true;
  return false;
}

function readAttrsFromElement(el: Element | null) {
  if (!el || !(el as HTMLElement).getAttribute) return DEFAULTS;
  const sizeAttr = (el as HTMLElement).getAttribute('data-cursor-size');
  const opacityAttr = (el as HTMLElement).getAttribute('data-cursor-opacity');
  const colorAttr = (el as HTMLElement).getAttribute('data-cursor-color');
  return {
    size: Number.parseInt(sizeAttr || `${DEFAULTS.size}`, 10) || DEFAULTS.size,
    opacity: Number.isNaN(Number.parseFloat(opacityAttr || ''))
      ? DEFAULTS.opacity
      : Math.max(0, Math.min(1, Number.parseFloat(opacityAttr || ''))),
    color: colorAttr || DEFAULTS.color,
  };
}

function findAttrsForTarget(target: EventTarget | null) {
  const node = target as HTMLElement | null;
  if (node && node.closest) {
    const el = node.closest('[data-cursor-size],[data-cursor-opacity],[data-cursor-color]');
    if (el) return readAttrsFromElement(el);
  }
  return DEFAULTS;
}

export default function MagicHighlighter({ containerRef, className }: MagicHighlighterProps) {
  const cursorRef = useRef<HTMLDivElement | null>(null);
  const lastXRef = useRef<number | null>(null);
  const lastYRef = useRef<number | null>(null);
  const collisionElementsRef = useRef<HTMLElement[] | null>(null);

  const updateCursorFromPoint = (clientX: number, clientY: number, attrs: typeof DEFAULTS) => {
    const cursor = cursorRef.current;
    if (!cursor) return;

    cursor.style.backgroundColor = attrs.color;
    cursor.style.width = `${attrs.size}px`;
    cursor.style.height = `${attrs.size}px`;

    const vw = window.innerWidth;
    const vh = window.innerHeight;
    const width = cursor.offsetWidth || attrs.size;
    const height = cursor.offsetHeight || attrs.size;
    const halfW = width / 2;
    const halfH = height / 2;
    let clampedX = Math.min(Math.max(clientX, halfW), vw - halfW);
    let clampedY = Math.min(Math.max(clientY, halfH), vh - halfH);

    if (collisionElementsRef.current == null) {
      collisionElementsRef.current = Array.from(
        document.querySelectorAll('[data-cursor-collision="true"]'),
      ) as HTMLElement[];
    }

    const elements = collisionElementsRef.current || [];
    if (elements.length) {
      let adjusted = true;
      let safety = 0;
      while (adjusted && safety < 4) {
        adjusted = false;
        safety += 1;
        for (let i = 0; i < elements.length; i += 1) {
          const el = elements[i];
          if (!el || !el.getBoundingClientRect) continue;
          const rect = el.getBoundingClientRect();
          if (rect.width === 0 || rect.height === 0) continue;
          const overlapsX = clampedX + halfW > rect.left && clampedX - halfW < rect.right;
          const overlapsY = clampedY + halfH > rect.top && clampedY - halfH < rect.bottom;
          if (overlapsX && overlapsY) {
            const pushLeft = clampedX + halfW - rect.left;
            const pushRight = rect.right - (clampedX - halfW);
            const pushUp = clampedY + halfH - rect.top;
            const pushDown = rect.bottom - (clampedY - halfH);
            const minPush = Math.min(pushLeft, pushRight, pushUp, pushDown);
            if (minPush === pushLeft) clampedX = rect.left - halfW - 0.5;
            else if (minPush === pushRight) clampedX = rect.right + halfW + 0.5;
            else if (minPush === pushUp) clampedY = rect.top - halfH - 0.5;
            else clampedY = rect.bottom + halfH + 0.5;

            clampedX = Math.min(Math.max(clampedX, halfW), vw - halfW);
            clampedY = Math.min(Math.max(clampedY, halfH), vh - halfH);
            adjusted = true;
          }
        }
      }
    }

    cursor.style.transform = `translate3d(${clampedX}px, ${clampedY}px, 0) translate(-50%, -50%)`;
    cursor.style.opacity = `${attrs.opacity}`;
  };

  useEffect(() => {
    if (isMobilePointer()) {
      if (cursorRef.current) cursorRef.current.style.display = 'none';
      return;
    }

    const targetEl: HTMLElement | Document = containerRef?.current || document;

    const handleMouseMove = (e: MouseEvent) => {
      if (isMobilePointer()) return;
      lastXRef.current = e.clientX;
      lastYRef.current = e.clientY;
      const attrs = findAttrsForTarget(e.target);
      updateCursorFromPoint(e.clientX, e.clientY, attrs);
    };

    const handleMouseLeave = () => {
      if (isMobilePointer()) return;
      const cursor = cursorRef.current;
      if (!cursor) return;
      cursor.style.opacity = '0';
    };

    const handleScrollOrResize = () => {
      const x = lastXRef.current;
      const y = lastYRef.current;
      if (x == null || y == null) return;
      const el = document.elementFromPoint(x, y);
      const attrs = findAttrsForTarget(el);
      updateCursorFromPoint(x, y, attrs);
      collisionElementsRef.current = null;
    };

    // @ts-ignore addEventListener exists on both Document and HTMLElement
    targetEl.addEventListener('mousemove', handleMouseMove, { passive: true });
    // @ts-ignore
    targetEl.addEventListener('mouseleave', handleMouseLeave, { passive: true });
    window.addEventListener('scroll', handleScrollOrResize, { passive: true });
    window.addEventListener('resize', handleScrollOrResize, { passive: true });

    return () => {
      // @ts-ignore
      targetEl.removeEventListener('mousemove', handleMouseMove);
      // @ts-ignore
      targetEl.removeEventListener('mouseleave', handleMouseLeave);
      window.removeEventListener('scroll', handleScrollOrResize);
      window.removeEventListener('resize', handleScrollOrResize);
    };
  }, [containerRef]);

  const baseClass =
    'pointer-events-none fixed left-0 top-0 w-[400px] h-[400px] rounded-2xl bg-[#0086FF] mix-blend-color blur-3xl opacity-0 transition-opacity duration-150 z-[70] will-change-transform hidden md:block transition-colors';

  return <div ref={cursorRef} className={className ? `${baseClass} ${className}` : baseClass} />;
}



================================================
FILE: components/react-scan.tsx
================================================
'use client';

import { scan } from 'react-scan';
import { JSX, useEffect } from 'react';

export function ReactScan(): JSX.Element {
  useEffect(() => {
    scan({
      enabled: true,
    });
  }, []);

  return <></>;
}



================================================
FILE: components/actions/youtube-video-validate.ts
================================================
'use server';

import { z } from 'zod';

const youtubeUrlSchema = z
  .string()
  .url()
  .refine(url => {
    const regExp =
      /^(?:https?:\/\/)?(?:www\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?v=)?(?:embed\/)?(?:v\/)?(?:shorts\/)?(?:\S+)$/;
    return regExp.test(url);
  }, 'Please enter a valid YouTube URL');

export async function validateAndSubmitYoutubeUrl(prevState: any, formData: FormData) {
  const url = Object.fromEntries(formData.entries()).youtubeUrl as string;

  try {
    youtubeUrlSchema.parse(url);
    // push to database
    console.log('Valid YouTube URL:', url);
    return { success: true, message: 'YouTube URL submitted successfully' };
  } catch (error) {
    if (error instanceof z.ZodError) {
      return { success: false, message: error.errors[0].message };
    }
    return { success: false, message: 'An unexpected error occurred' };
  }
}



================================================
FILE: components/forms/challenging-words-selector.jsx
================================================
'use client';

import { Label } from '@/components/ui/base/label';
import { Textarea } from '@/components/ui/base/textarea';
import { Skeleton } from '@/components/ui/base/skeleton';

export default function ChallengingWordsSelector({
  label = 'Challenging Words',
  value,
  onChange,
  required = false,
  className = '',
  placeholder = "Words you find difficult or confusing (e.g., 'thorough', 'entrepreneur', 'rural')",
  maxLength = 500,
  isPending = false,
  optional = false,
}) {
  const handleChange = e => {
    onChange(e.target.value);
  };

  if (isPending) {
    return (
      <div className={`space-y-2 ${className}`}>
        <Label className="text-sm font-medium ml-0.5">{label}</Label>
        <Skeleton className="h-20 w-full rounded-xl mt-1" />
        <Skeleton className="h-4 w-26 rounded-lg mt-1" />
      </div>
    );
  }

  return (
    <div className={`space-y-2 text-left ${className}`}>
      <Label htmlFor="challengingWords" className="mb-2">
        {label}
        {required && (
          <span className="text-sky-600 ml-1" aria-hidden="true">
            *
          </span>
        )}
        {optional && <span className="text-xs text-neutral-500 ml-1">(Optional)</span>}
      </Label>
      <Textarea
        id="challengingWords"
        placeholder={placeholder}
        value={value}
        onChange={handleChange}
        className="min-h-[100px] mt-1 rounded-xl resize-none p-3"
        maxLength={maxLength}
      />
      {maxLength && (
        <p className="text-xs text-neutral-400 mt-1">
          {value?.length || 0}/{maxLength} characters
        </p>
      )}
    </div>
  );
}



================================================
FILE: components/forms/city-selector.jsx
================================================
'use client';

import { Label } from '@/components/ui/base/label';
import { Button } from '@/components/ui/base/button';
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '@/components/ui/base/command';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/base/popover';
import { ChevronDownIcon } from 'lucide-react';
import { useState, useEffect, useId, useMemo } from 'react';

export default function CitySelector({
  label = 'Where did you spend the longest time learning this language?',
  value,
  onChange,
  required = false,
  optional = true,
  className = '',
  placeholder = 'Select a city',
}) {
  const [cities, setCities] = useState([]);
  const [citiesLoading, setCitiesLoading] = useState(true);
  const [citiesError, setCitiesError] = useState(false);
  const [cityOpen, setCityOpen] = useState(false);
  const [citySearchTerm, setCitySearchTerm] = useState('');
  const citySelectId = useId();

  useEffect(() => {
    const loadCities = async () => {
      try {
        setCitiesLoading(true);
        setCitiesError(false);
        const response = await fetch(
          '/world_cities_15000_(including_all_states_and_counties).json',
        );
        if (!response.ok) throw new Error('Failed to load cities');
        const citiesData = await response.json();
        setCities(citiesData);
      } catch (error) {
        console.error('Failed to load cities:', error);
        setCitiesError(true);
      } finally {
        setCitiesLoading(false);
      }
    };

    loadCities();
  }, []);

  const selectedCity = cities.find(city => {
    if (typeof value === 'string') {
      return city.name === value;
    }
    if (value?.name) {
      return (
        city.name === value.name && city.state === value.state && city.country === value.country
      );
    }
    return false;
  });

  const formatCountry = countryCode => {
    const regionNames = new Intl.DisplayNames(['en'], { type: 'region' });
    return regionNames.of(countryCode.toUpperCase());
  };

  const formatCityDisplay = city => {
    let display = city.name;
    if (city.state && city.state !== city.name) {
      display += `, ${city.state}`;
    }
    if (city.country) {
      display += `, ${formatCountry(city.country)}`;
    }
    return display;
  };

  const filteredCities = useMemo(() => {
    if (!citySearchTerm || citySearchTerm.length < 2) {
      return [];
    }

    const searchLower = citySearchTerm.toLowerCase();
    const results = cities
      .filter(city => {
        const cityName = city.name.toLowerCase();
        const stateName = city.state ? city.state.toLowerCase() : '';
        const countryCode = city.country ? city.country.toLowerCase() : '';

        return (
          cityName.includes(searchLower) ||
          stateName.includes(searchLower) ||
          countryCode.includes(searchLower)
        );
      })
      .sort((a, b) => {
        const aName = a.name.toLowerCase();
        const bName = b.name.toLowerCase();

        const aStartsWith = aName.startsWith(searchLower);
        const bStartsWith = bName.startsWith(searchLower);

        if (aStartsWith && !bStartsWith) return -1;
        if (!aStartsWith && bStartsWith) return 1;

        return aName.localeCompare(bName);
      })
      .slice(0, 30);

    return results;
  }, [cities, citySearchTerm]);

  return (
    <div className={`space-y-2 text-left ${className}`}>
      <Label htmlFor={citySelectId} className="mb-2">
        {label}
        {required && (
          <span className="text-sky-600 ml-1" aria-hidden="true">
            *
          </span>
        )}
        {optional && <span className="text-xs text-neutral-500 ml-1">(Optional)</span>}
      </Label>
      <Popover open={cityOpen} onOpenChange={setCityOpen}>
        <PopoverTrigger asChild>
          <Button
            id={citySelectId}
            variant="outline"
            role="combobox"
            aria-expanded={cityOpen}
            disabled={citiesError}
            className="bg-background hover:bg-background border-input w-full justify-between px-3 font-normal outline-offset-0 outline-none focus-visible:outline-[3px] h-10 mt-1 rounded-xl disabled:opacity-50"
          >
            {citiesLoading ? (
              <span className="text-muted-foreground">Loading cities...</span>
            ) : citiesError ? (
              <span className="text-muted-foreground">Information not needed at this time</span>
            ) : selectedCity ? (
              <span className="flex min-w-0 items-center">
                <span className="truncate">{formatCityDisplay(selectedCity)}</span>
              </span>
            ) : value && typeof value === 'string' ? (
              <span className="flex min-w-0 items-center">
                <span className="truncate">{value}</span>
              </span>
            ) : (
              <span className="text-muted-foreground">{placeholder}</span>
            )}
            <ChevronDownIcon
              size={16}
              className="text-muted-foreground/80 shrink-0 -mr-0.5"
              aria-hidden="true"
            />
          </Button>
        </PopoverTrigger>
        <PopoverContent
          className="border-input w-full min-w-[var(--radix-popper-anchor-width)] p-0 rounded-xl"
          align="start"
        >
          <Command className="rounded-xl" shouldFilter={false}>
            <CommandInput
              placeholder="Search city..."
              value={citySearchTerm}
              onValueChange={setCitySearchTerm}
            />
            <CommandList className="p-1 max-h-[200px]">
              {!citySearchTerm || citySearchTerm.length < 2 ? (
                <CommandEmpty>Type at least 2 characters to search...</CommandEmpty>
              ) : filteredCities.length === 0 ? (
                <CommandEmpty>No cities found.</CommandEmpty>
              ) : (
                <CommandGroup className="p-0">
                  {filteredCities.map((city, index) => (
                    <CommandItem
                      key={`${city.country}-${city.state}-${index}`}
                      value={city.country + ' ' + city.state + ' ' + city.name + ' ' + index}
                      className="rounded-lg"
                      onSelect={() => {
                        onChange({
                          name: city.name,
                          state: city.state,
                          country: city.country,
                        });
                        setCityOpen(false);
                        setCitySearchTerm('');
                      }}
                    >
                      {formatCityDisplay(city)}
                    </CommandItem>
                  ))}
                </CommandGroup>
              )}
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>
    </div>
  );
}



================================================
FILE: components/forms/country-selector.jsx
================================================
[Binary file]


================================================
FILE: components/forms/experience-level-selector.jsx
================================================
'use client';

import { Label } from '@/components/ui/base/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/base/select';

const experienceLevels = [
  { value: '0', emoji: '🌱', name: 'Complete Beginner (0 years)' },
  { value: '0-1', emoji: '🌿', name: 'Less than 1 year' },
  { value: '1-2', emoji: '🌳', name: '1-2 years' },
  { value: '2-5', emoji: '🎯', name: '2-5 years' },
  { value: '5-10', emoji: '🚀', name: '5-10 years' },
  { value: '10+', emoji: '⭐', name: 'More than 10 years' },
  { value: 'native-level', emoji: '👑', name: 'Native/Near-native level' },
];

export default function ExperienceLevelSelector({
  label = 'How many years have you studied this language?',
  value,
  onChange,
  required = false,
  className = '',
  placeholder = 'Select your experience level',
}) {
  const selectedExperience = experienceLevels.find(level => level.value === value);

  return (
    <div className={`space-y-2 text-left ${className}`}>
      <Label htmlFor="experienceLevel" className="mb-2">
        {label}
        {required && (
          <span className="text-sky-600 ml-1" aria-hidden="true">
            *
          </span>
        )}
      </Label>
      <Select onValueChange={onChange} value={value}>
        <SelectTrigger
          id="experienceLevel"
          className="h-10 mt-1 rounded-xl focus:ring-0 focus:ring-offset-0"
        >
          {selectedExperience ? (
            <SelectValue className="pl-2">
              <span className="flex items-center">
                <span className="mr-2">{selectedExperience.emoji}</span>
                <span>{selectedExperience.name}</span>
              </span>
            </SelectValue>
          ) : (
            <p className="text-muted-foreground">{placeholder}</p>
          )}
        </SelectTrigger>
        <SelectContent className="rounded-xl">
          {experienceLevels.map(level => (
            <SelectItem
              className="pl-2 rounded-lg"
              key={level.value}
              value={level.value}
              rightCheck={true}
            >
              <span className="flex items-center">
                <span className="mr-2">{level.emoji}</span>
                <span>{level.name}</span>
              </span>
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
    </div>
  );
}

export { experienceLevels };



================================================
FILE: components/forms/language-selector.jsx
================================================
'use client';

import { useState, useId, Fragment } from 'react';
import { Button } from '@/components/ui/base/button';
import { Label } from '@/components/ui/base/label';
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
} from '@/components/ui/base/command';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/base/popover';
import { ArrowUpRight, CheckIcon, ChevronDownIcon } from 'lucide-react';

const languageGroups = [
  {
    group: 'Most Common',
    languages: [
      {
        Code: 'en',
        NativeName: 'English (American)',
        Flag: '🇺🇸',
        EnglishName: 'English (American)',
      },
      { Code: 'es', NativeName: 'Español (España)', EnglishName: 'Spanish (Spain)', Flag: '🇪🇸' },
      { Code: 'zh', NativeName: '中文（简体）', EnglishName: 'Chinese (Simplified)', Flag: '🇨🇳' },
      { Code: 'hi', NativeName: 'हिन्दी', Flag: '🇮🇳', EnglishName: 'Hindi' },
      { Code: 'ar', NativeName: 'العربية', Flag: '🇸🇦', EnglishName: 'Arabic' },
      {
        Code: 'pt-PT',
        NativeName: 'Português (Portugal)',
        Flag: '🇵🇹',
        EnglishName: 'Portuguese (Portugal)',
      },
      { Code: 'ru', NativeName: 'Русский', Flag: '🇷🇺', EnglishName: 'Russian' },
      { Code: 'ja', NativeName: '日本語', Flag: '🇯🇵', EnglishName: 'Japanese' },
      { Code: 'de', NativeName: 'Deutsch', Flag: '🇩🇪', EnglishName: 'German' },
      { Code: 'fr-FR', NativeName: 'Français (France)', Flag: '🇫🇷', EnglishName: 'French' },
    ],
  },
  {
    group: 'Germanic Languages',
    languages: [
      {
        Code: 'en-AU',
        NativeName: 'English (Australia)',
        Flag: '🇦🇺',
        EnglishName: 'English (Australia)',
      },
      {
        Code: 'en-CA',
        NativeName: 'English (Canada)',
        Flag: '🇨🇦',
        EnglishName: 'English (Canada)',
      },
      {
        Code: 'en-GB',
        NativeName: 'English (United Kingdom)',
        Flag: '🇬🇧',
        EnglishName: 'English (UK)',
      },
      { Code: 'nl', NativeName: 'Nederlands', Flag: '🇳🇱', EnglishName: 'Dutch' },
      { Code: 'da', NativeName: 'Dansk', Flag: '🇩🇰', EnglishName: 'Danish' },
      { Code: 'no', NativeName: 'Norsk', Flag: '🇳🇴', EnglishName: 'Norwegian' },
      { Code: 'sv', NativeName: 'Svenska', EnglishName: 'Swedish', Flag: '🇸🇪' },
      { Code: 'is', NativeName: 'Íslenska', Flag: '🇮🇸', EnglishName: 'Icelandic' },
      { Code: 'af', NativeName: 'Afrikaans', Flag: '🇿🇦', EnglishName: 'Afrikaans' },
    ],
  },
  {
    group: 'Romance Languages',
    languages: [
      {
        Code: 'es-419',
        NativeName: 'Español (Latinoamérica)',
        EnglishName: 'Spanish (Latin America)',
        Flag: '🌎',
      },
      {
        Code: 'es-US',
        NativeName: 'Español (Estados Unidos)',
        EnglishName: 'Spanish (United States)',
        Flag: '🇺🇸',
      },
      {
        Code: 'fr-CA',
        NativeName: 'Français (Canada)',
        Flag: '🇨🇦',
        EnglishName: 'French (Canada)',
      },
      {
        Code: 'pt-BR',
        NativeName: 'Português (Brasil)',
        Flag: '🇧🇷',
        EnglishName: 'Portuguese (Brazil)',
      },
      { Code: 'it', NativeName: 'Italiano', Flag: '🇮🇹', EnglishName: 'Italian' },
      { Code: 'ro', NativeName: 'Română', Flag: '🇷🇴', EnglishName: 'Romanian' },
      { Code: 'ca', NativeName: 'Català', Flag: '🇪🇸', EnglishName: 'Catalan' },
      { Code: 'gl', NativeName: 'Galego', Flag: '🇪🇸', EnglishName: 'Galician' },
      { Code: 'rm', NativeName: 'Rumantsch', Flag: '🇨🇭', EnglishName: 'Romansh' },
    ],
  },
  {
    group: 'Slavic Languages',
    languages: [
      { Code: 'pl', NativeName: 'Polski', Flag: '🇵🇱', EnglishName: 'Polish' },
      { Code: 'uk', NativeName: 'Українська', Flag: '🇺🇦', EnglishName: 'Ukrainian' },
      { Code: 'cs', NativeName: 'Čeština', Flag: '🇨🇿', EnglishName: 'Czech' },
      { Code: 'sk', NativeName: 'Slovenčina', Flag: '🇸🇰', EnglishName: 'Slovak' },
      { Code: 'hr', NativeName: 'Hrvatski', Flag: '🇭🇷', EnglishName: 'Croatian' },
      { Code: 'sr', NativeName: 'Српски', Flag: '🇷🇸', EnglishName: 'Serbian' },
      { Code: 'sl', NativeName: 'Slovenščina', Flag: '🇸🇮', EnglishName: 'Slovenian' },
      { Code: 'bg', NativeName: 'Български', Flag: '🇧🇬', EnglishName: 'Bulgarian' },
      { Code: 'mk', NativeName: 'Македонски', Flag: '🇲🇰', EnglishName: 'Macedonian' },
      { Code: 'be', NativeName: 'Беларуская', Flag: '🇧🇾', EnglishName: 'Belarusian' },
    ],
  },
  {
    group: 'Asian Languages',
    languages: [
      {
        Code: 'zh-HK',
        NativeName: '中文（香港）',
        EnglishName: 'Chinese (Hong Kong)',
        Flag: '🇭🇰',
      },
      {
        Code: 'zh-TW',
        NativeName: '中文（繁體）',
        EnglishName: 'Chinese (Traditional)',
        Flag: '🇹🇼',
      },
      { Code: 'ko', NativeName: '한국어', Flag: '🇰🇷', EnglishName: 'Korean' },
      { Code: 'th', NativeName: 'ไทย', Flag: '🇹🇭', EnglishName: 'Thai' },
      { Code: 'vi', NativeName: 'Tiếng Việt', Flag: '🇻🇳', EnglishName: 'Vietnamese' },
      { Code: 'id', NativeName: 'Indonesia', Flag: '🇮🇩', EnglishName: 'Indonesian' },
      { Code: 'ms', NativeName: 'Bahasa Melayu', Flag: '🇲🇾', EnglishName: 'Malay' },
      {
        Code: 'ms-MY',
        NativeName: 'Bahasa Melayu (Malaysia)',
        Flag: '🇲🇾',
        EnglishName: 'Malay (Malaysia)',
      },
      { Code: 'tl', NativeName: 'Filipino', Flag: '🇵🇭', EnglishName: 'Filipino' },
      { Code: 'my', NativeName: 'ဗမာ', Flag: '🇲🇲', EnglishName: 'Burmese' },
      { Code: 'km', NativeName: 'ខ្មែរ', Flag: '🇰🇭', EnglishName: 'Khmer' },
      { Code: 'lo', NativeName: 'ລາວ', Flag: '🇱🇦', EnglishName: 'Lao' },
      { Code: 'mn', NativeName: 'Монгол', Flag: '🇲🇳', EnglishName: 'Mongolian' },
    ],
  },
  {
    group: 'Indian Languages',
    languages: [
      { Code: 'bn', NativeName: 'বাংলা', Flag: '🇧🇩', EnglishName: 'Bengali' },
      { Code: 'gu', NativeName: 'ગુજરાતી', Flag: '🇮🇳', EnglishName: 'Gujarati' },
      { Code: 'kn', NativeName: 'ಕನ್ನಡ', Flag: '🇮🇳', EnglishName: 'Kannada' },
      { Code: 'ml', NativeName: 'മലയാളം', Flag: '🇮🇳', EnglishName: 'Malayalam' },
      { Code: 'mr', NativeName: 'मराठी', Flag: '🇮🇳', EnglishName: 'Marathi' },
      { Code: 'pa', NativeName: 'ਪੰਜਾਬੀ', Flag: '🇮🇳', EnglishName: 'Punjabi' },
      { Code: 'ta', NativeName: 'தமிழ்', Flag: '🇮🇳', EnglishName: 'Tamil' },
      { Code: 'te', NativeName: 'తెలుగు', Flag: '🇮🇳', EnglishName: 'Telugu' },
      { Code: 'ne', NativeName: 'नेपाली', Flag: '🇳🇵', EnglishName: 'Nepali' },
      { Code: 'si', NativeName: 'සිංහල', Flag: '🇱🇰', EnglishName: 'Sinhala' },
      { Code: 'ur', NativeName: 'اردو', Flag: '🇵🇰', EnglishName: 'Urdu' },
    ],
  },
  {
    group: 'Other Languages',
    languages: [
      { Code: 'sq', NativeName: 'Shqip', Flag: '🇦🇱', EnglishName: 'Albanian' },
      { Code: 'am', NativeName: 'አማርኛ', Flag: '🇪🇹', EnglishName: 'Amharic' },
      { Code: 'hy', NativeName: 'Հայերեն', Flag: '🇦🇲', EnglishName: 'Armenian' },
      { Code: 'az', NativeName: 'Azərbaycan dili', Flag: '🇦🇿', EnglishName: 'Azerbaijani' },
      { Code: 'eu', NativeName: 'Euskara', Flag: '🇪🇸', EnglishName: 'Basque' },
      { Code: 'et', NativeName: 'Eesti', Flag: '🇪🇪', EnglishName: 'Estonian' },
      { Code: 'fi', NativeName: 'Suomi', Flag: '🇫🇮', EnglishName: 'Finnish' },
      { Code: 'ka', NativeName: 'ქართული', Flag: '🇬🇪', EnglishName: 'Georgian' },
      { Code: 'el', NativeName: 'Ελληνικά', EnglishName: 'Greek', Flag: '🇬🇷' },
      { Code: 'he', NativeName: 'עברית', Flag: '🇮🇱', EnglishName: 'Hebrew' },
      { Code: 'hu', NativeName: 'Magyar', Flag: '🇭🇺', EnglishName: 'Hungarian' },
      { Code: 'kk', NativeName: 'Қазақ тілі', Flag: '🇰🇿', EnglishName: 'Kazakh' },
      { Code: 'ky', NativeName: 'Кыргызча', Flag: '🇰🇬', EnglishName: 'Kyrgyz' },
      { Code: 'lt', NativeName: 'Lietuvių', Flag: '🇱🇹', EnglishName: 'Lithuanian' },
      { Code: 'lv', NativeName: 'Latviešu', Flag: '🇱🇻', EnglishName: 'Latvian' },
      { Code: 'fa', NativeName: 'فارسی', Flag: '🇮🇷', EnglishName: 'Persian' },
      { Code: 'sw', NativeName: 'Kiswahili', Flag: '🇹🇿', EnglishName: 'Swahili' },
      { Code: 'tr', NativeName: 'Türkçe', Flag: '🇹🇷', EnglishName: 'Turkish' },
      { Code: 'zu', NativeName: 'Zulu', Flag: '🇿🇦', EnglishName: 'Zulu' },
    ],
  },
];

export default function LanguageSelector({
  label,
  value,
  onChange,
  required = false,
  className = '',
  placeholder = 'Select language',
  showEnglishName = true,
}) {
  const [isOpen, setIsOpen] = useState(false);
  const selectId = useId();

  const selectedLanguage = languageGroups
    .flatMap(group => group.languages)
    .find(lang => lang.Code === value);

  const MandatoryStar = () => (
    <span className="text-sky-600" aria-hidden="true">
      *
    </span>
  );

  return (
    <div className={`space-y-2 text-left ${className}`}>
      <Label htmlFor={selectId} className="mb-2">
        {label} {required && <MandatoryStar />}
      </Label>
      <Popover open={isOpen} onOpenChange={setIsOpen}>
        <PopoverTrigger asChild>
          <Button
            id={selectId}
            variant="outline"
            role="combobox"
            aria-expanded={isOpen}
            className="bg-background hover:bg-background border-input w-full justify-between px-3 font-normal outline-offset-0 outline-none focus-visible:outline-[3px] h-10 mt-1 rounded-xl"
          >
            {selectedLanguage ? (
              <span className="flex min-w-0 items-center gap-2">
                <span className="text-lg leading-none">{selectedLanguage.Flag}</span>
                <span className="truncate">
                  {showEnglishName ? selectedLanguage.EnglishName : selectedLanguage.NativeName}
                </span>
              </span>
            ) : (
              <span className="text-muted-foreground">{placeholder}</span>
            )}
            <ChevronDownIcon
              size={16}
              className="text-muted-foreground/80 shrink-0 -mr-0.5"
              aria-hidden="true"
            />
          </Button>
        </PopoverTrigger>
        <PopoverContent
          className="border w-full min-w-[var(--radix-popper-anchor-width)] p-0 rounded-xl"
          align="start"
        >
          <Command className="rounded-xl relative">
            <CommandInput placeholder="Search language..." />
            <CommandList className="rounded-xl overflow-y-auto">
              <CommandEmpty>No language found.</CommandEmpty>
              <div className="p-3 w-full max-w-[608px] text-balance">
                <div className="border border-dashed rounded-xl p-3 ">
                  <span className="text-sm text-neutral-500 tracking-tight leading-[0.2]">
                    We are currently using the ISO 639-1 language code, with flag emojis from a
                    dataset. What are your thoughts about flags associated with languages?
                  </span>{' '}
                  <a
                    href="hhttps://docs.google.com/forms/d/e/1FAIpQLScGr_SkBidld82ghxYKvZeLnsbQI2j75-1wmLpDCwd32BAn2g/viewform"
                    target="_blank"
                    rel="noopener noreferrer"
                    className="text-sky-600 hover:underline inline-block text-sm items-center gap-1"
                  >
                    Submit feedback here!
                  </a>
                </div>
              </div>
              {languageGroups.map(group => (
                <Fragment key={group.group}>
                  <CommandGroup heading={group.group}>
                    {group.languages.map(language => (
                      <CommandItem
                        key={language.Code}
                        value={`${language.NativeName} ${language.EnglishName}`}
                        onSelect={() => {
                          onChange(language.Code);
                          setIsOpen(false);
                        }}
                      >
                        <span className="text-lg leading-none">{language.Flag}</span>{' '}
                        {showEnglishName ? language.EnglishName : language.NativeName}
                        {value === language.Code && <CheckIcon size={16} className="ml-auto" />}
                      </CommandItem>
                    ))}
                  </CommandGroup>
                </Fragment>
              ))}
            </CommandList>
          </Command>
        </PopoverContent>
      </Popover>
    </div>
  );
}

// Export language groups for other components that might need the data
export { languageGroups };



================================================
FILE: components/forms/target-language-selector.jsx
================================================
'use client';

import { Label } from '@/components/ui/base/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/base/select';
import { ArrowUpRight } from 'lucide-react';

const languages = [
  { value: 'english', name: 'English' },
  { value: 'spanish', name: 'Spanish (Coming Soon)', disabled: true },
  { value: 'german', name: 'German (Coming Soon)', disabled: true },
  { value: 'russian', name: 'Russian (Coming Soon)', disabled: true },
];

export default function TargetLanguageSelector({
  label = 'What language do you want to learn?',
  value,
  onChange,
  required = false,
  className = '',
}) {
  const selectedLanguage = languages.find(lang => lang.value === value);

  return (
    <div className={`space-y-2 text-left ${className}`}>
      <Label htmlFor="targetLanguage" className="mb-2">
        {label}
        {required && (
          <span className="text-sky-600 ml-1" aria-hidden="true">
            *
          </span>
        )}
      </Label>
      <div className="relative">
        <Select onValueChange={onChange} value={value}>
          <SelectTrigger
            id="targetLanguage"
            className="h-10 mt-1 rounded-xl focus:ring-0 focus:ring-offset-0"
          >
            <SelectValue>
              {selectedLanguage ? (
                <span className="flex items-center">
                  <span>{selectedLanguage.name}</span>
                </span>
              ) : (
                <span className="text-muted-foreground flex items-center">
                  <span>English</span>
                </span>
              )}
            </SelectValue>
          </SelectTrigger>
          <SelectContent className="rounded-xl bg-neutral-100 dark:bg-neutral-900" noPadding={true}>
            <div className="p-1 rounded-xl border-b bg-white">
              {languages.map(language => (
                <SelectItem
                  className="pl-2 rounded-lg"
                  key={language.value}
                  value={language.value}
                  disabled={language.disabled}
                  noCheck={true}
                >
                  <span className="flex items-center">
                    <span>{language.name}</span>
                  </span>
                </SelectItem>
              ))}
            </div>
            <div className="p-3 max-w-[608px] bg-neutral-100 dark:bg-neutral-900 text-balance">
              <p className="text-sm text-neutral-500 tracking-tight">
                During the beta phase, we're focusing on English. In the future, we plan to expand
                to other languages. Want to suggest what comes next?{' '}
                <a
                  href="https://docs.google.com/forms/d/e/1FAIpQLSeKziYp-3pTI1Ptnk70RSZ1ryQSDJfUrZagrAuIsDSKr3YvWw/viewform"
                  target="_blank"
                  rel="noopener noreferrer"
                  className="text-sky-600 hover:underline inline-block"
                >
                  Submit a request here
                  <ArrowUpRight
                    aria-hidden="true"
                    className="w-4 h-4 inline-block -mt-0.5 ml-0.5"
                  />
                </a>
              </p>
            </div>
          </SelectContent>
        </Select>
      </div>
    </div>
  );
}

// Export languages for other components
export { languages };



================================================
FILE: components/sections/1 - Hero.jsx
================================================
import React from 'react';
import { Button } from '@/components/ui/base/button';
import Header from '@/components/ui/header';
import { ChevronRight, UserRoundPlus } from 'lucide-react';
import Link from 'next/link';
import { Card } from '@/components/ui/base/card';
import HeroVideoDialog from '@/components/ui/magicui/hero-video-dialog';

export default function Hero() {
  return (
    <div className="relative">
      <div className="mx-auto md:px-6 pt-0 lg:px-8 py-32 relative">
        <div className="mx-auto p-4 max-w-3xl py-32">
          <div className="hidden sm:mb-8 sm:flex sm:justify-center"></div>
          <section aria-labelledby="hero-heading" className="text-center relative">
            <div className="flex flex-row justify-center items-center my-6">
              <p className="font-[400] text-md text-neutral-700">Backed by</p>
              <div className="h-6 bg-black w-6 rounded-md overflow-hidden ml-2 mr-1.5 p-0.5">
                <svg
                  aria-label="Mozilla Logo"
                  role="img"
                  xmlns="http://www.w3.org/2000/svg"
                  x="0"
                  y="0"
                  enableBackground="new 0 0 68 68"
                  version="1.1"
                  viewBox="0 0 68 68"
                  xmlSpace="preserve"
                >
                  {' '}
                  <path d="M0 0H68V68H0z"></path>{' '}
                  <path
                    d="M57.9 42.6h3.9V49H49.5V32.4c0-5.1-1.7-7-5-7-4 0-5.6 2.9-5.6 6.9v10.2h3.9v6.4H30.5V32.4c0-5.1-1.7-7-5-7-4 0-5.6 2.9-5.6 6.9v10.2h5.6v6.4h-18v-6.4h3.9V26H7.5v-6.4h12.3V24c1.8-3.1 4.8-5 8.9-5 4.2 0 8.1 2 9.5 6.3 1.6-3.9 4.9-6.3 9.5-6.3 5.3 0 10.1 3.2 10.1 10.1v13.5z"
                    className="st0 text-white fill-white bg-white"
                  ></path>{' '}
                </svg>{' '}
              </div>
              <p className="font-[400] text-md text-neutral-700">Mozilla</p>
            </div>

            <h1
              id="hero-heading"
              className="text-2xl sm:text-4xl font-semibold tracking-[-0.05em] sm:max-w-[500px] lg:max-w-[1400px] mx-auto text-pretty text-gray-900 lg:text-6xl overflow-visible"
            >
              Pioneering Speech Technology for Everyone
            </h1>

            <p className="mt-6 sm:text-lg leading-8 text-gray-600 max-w-xl mx-auto text-pretty">
              Practice, perfect, and pronounce like a native language speaker with fun, immersive
              movie and show clips at your fingertips.
            </p>
            <div className="mt-4 flex flex-col gap-2 sm:flex-row items-center justify-center gap-x-4 w-full">
              <Link
                href="#join-the-waitlist"
                className="w-full sm:w-auto"
                aria-label="Join the waitlist"
              >
                <Button className="w-full rounded-lg sm:w-40 bg-linear-to-b border border-double outline-white/50 outline-[0.1px] outline-offset-[-2px] border-black from-sky-900 to-blue-950">
                  Join the Waitlist
                </Button>
              </Link>
              <Link
                href="#learn-more"
                className="w-full sm:w-auto"
                aria-label="Learn more about Koel Labs"
              >
                <Button className="w-full sm:w-32" variant="outline">
                  Learn More
                </Button>
              </Link>
            </div>
          </section>
        </div>

        <div className="mx-auto absolute opacity-25 sm:opacity-100 top-0 left-0 right-0 bottom-0 lg:max-w-[1264px] h-full flex justify-between z-[-1]">
          <div className="h-full"></div>
          <div className="w-[1px] h-full bg-neutral-200 drops"></div>
          <div className="w-[1px] h-full bg-neutral-200 drops2"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="w-[1px] h-full bg-neutral-200 drops3"></div>
          <div className="w-[1px] h-full bg-neutral-200 drops4"></div>
          <div className="h-full"></div>
        </div>

        <div className="flex justify-center sm:overflow-visible overflow-hidden">
          <Card className=" max-w-[1200px] min-w-[500px] p-6 bg-white outline-1 outline-neutral-200 rounded-[32px] shadow-2xl w-full h-fit mx-auto  z-[0] relative ">
            <HeroVideoDialog
              className="rounded-[500px]"
              animationStyle="top-in-bottom-out"
              videoSrc="https://www.youtube.com/watch?v=s7yPjSUjU9s"
              thumbnailSrc="/images/demoPitchUpdated.png"
              thumbnailAlt="Hero Video"
            />
          </Card>
        </div>
      </div>
    </div>
  );
}



================================================
FILE: components/sections/2 - Bento.jsx
================================================
import React from 'react';
import { Button } from '@/components/ui/base/button';
import Header from '@/components/ui/header';
import { ChevronRight, UserRoundPlus } from 'lucide-react';
import Link from 'next/link';
import { Card } from '@/components/ui/base/card';

export default function Bento() {
  return (
    <div id="learn-more" className="relative">
      <div className="mx-auto relative">
        <div className="mx-auto absolute h-full flex justify-between z-[-1]"></div>

        <section
          aria-labelledby="features-heading"
          className="mx-auto w-full h-fit bg-neutral-50/20 backdrop-blur-md border-y border-neutral-200 relative overflow-hidden"
        >
          <div className="bg-white py-24 sm:py-32">
            <div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8 z-10">
              <p className="text-base/7 font-semibold text-sky-600 relative z-10">What is this?</p>
              <h2
                id="features-heading"
                className="mt-2 text-pretty text-4xl font-semibold tracking-tighter text-gray-950 sm:text-5xl relative z-10"
              >
                Your new favorite tool for pronunciation learning
              </h2>
              <ul
                role="list"
                className="mt-10 grid grid-cols-1 gap-4 sm:mt-16 lg:grid-cols-6 lg:grid-rows-2"
              >
                <li className="relative lg:col-span-3">
                  <div className="absolute inset-px rounded-lg bg-white max-lg:rounded-t-[2rem] lg:rounded-tl-[2rem]" />
                  <article className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] max-lg:rounded-t-[calc(2rem+1px)] lg:rounded-tl-[calc(2rem+1px)]">
                    <img
                      alt="Screenshot showing the massive library of content available to practice with"
                      src="/images/bentoClips.png"
                      className="h-80 top-0 object-cover object-top"
                    />
                    <div className="p-10 pt-4">
                      <h3 className="text-sm/4 font-semibold text-sky-600">Engaging Content</h3>
                      <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                        Your favorite movies and shows
                      </p>
                      <p className="mt-2 max-w-lg text-sm/6 text-gray-600">
                        Practicing pronunciation has never been easier or more fun. Start learning
                        today with engaging scenes from iconic movies and shows.
                      </p>
                    </div>
                  </article>
                  <div className="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5 max-lg:rounded-t-[2rem] lg:rounded-tl-[2rem]" />
                </li>
                <li className="relative lg:col-span-3">
                  <div className="absolute inset-px rounded-lg bg-white lg:rounded-tr-[2rem]" />
                  <article className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] lg:rounded-tr-[calc(2rem+1px)]">
                    <img
                      alt="Screenshot showing detailed pronunciation feedback interface"
                      src="/images/bentoActionable.png"
                      className="h-80 object-cover object-left lg:object-top"
                    />
                    <div className="p-10 pt-4">
                      <h3 className="text-sm/4 font-semibold text-sky-600">Extensive Feedback</h3>
                      <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                        Actionable, tailored insights
                      </p>
                      <p className="mt-2 max-w-lg text-sm/6 text-gray-600">
                        Learn faster with our curated, actionable feedback, designed for maximum
                        impact, that gives you everything you need to start improving immediately.
                      </p>
                    </div>
                  </article>
                  <div className="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5 lg:rounded-tr-[2rem]" />
                </li>
                <li className="relative lg:col-span-2">
                  <div className="absolute inset-px rounded-lg bg-white lg:rounded-bl-[2rem]" />
                  <article className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] lg:rounded-bl-[calc(2rem+1px)]">
                    <img
                      alt="Screenshot showing analysis interface"
                      src="/images/bentoFeedback.png"
                      className="h-80 object-cover object-center"
                    />
                    <div className="p-10 pt-4">
                      <h3 className="text-sm/4 font-semibold text-sky-600">Speed</h3>
                      <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                        Real-time analysis
                      </p>
                      <p className="mt-2 max-w-lg text-sm/6 text-gray-600">
                        Get the first layer of feedback almost immediately after speaking.
                      </p>
                    </div>
                  </article>
                  <div className="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5 lg:rounded-bl-[2rem]" />
                </li>
                <li className="relative lg:col-span-2">
                  <div className="absolute inset-px rounded-lg bg-white" />
                  <article className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)]">
                    <img
                      alt="Screenshot showing deep practice mode"
                      src="/images/bentoComplex.png"
                      className="h-80 object-cover"
                    />
                    <div className="p-10 pt-4">
                      <h3 className="text-sm/4 font-semibold text-sky-600">Dive in Deep</h3>
                      <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                        Master even the hardest words
                      </p>
                      <p className="mt-2 max-w-lg text-sm/6 text-gray-600">
                        Practice hard-to-pronounce words by breaking them down into multiple
                        practical chunks.
                      </p>
                    </div>
                  </article>
                  <div className="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5" />
                </li>
                <li className="relative lg:col-span-2">
                  <div className="absolute inset-px rounded-lg bg-white max-lg:rounded-b-[2rem] lg:rounded-br-[2rem]" />
                  <article className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] max-lg:rounded-b-[calc(2rem+1px)] lg:rounded-br-[calc(2rem+1px)]">
                    <img
                      alt="An image of the worlds map to highlight the diversity of dialects"
                      src="/images/bentoDialect.png"
                      className="h-80 object-cover"
                    />
                    <div className="p-10 pt-4">
                      <h3 className="text-sm/4 font-semibold text-sky-600">Dialect</h3>
                      <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                        Dialect-sensitive learning
                      </p>
                      <p className="mt-2 max-w-lg text-sm/6 text-gray-600">
                        Take control of your learning by choosing the dialect you want to practice.
                      </p>
                    </div>
                  </article>
                  <div className="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5 max-lg:rounded-b-[2rem] lg:rounded-br-[2rem]" />
                </li>
              </ul>
            </div>
          </div>
        </section>
      </div>
    </div>
  );
}



================================================
FILE: components/sections/3 - CTA.tsx
================================================
'use client';
import { ArrowRightIcon } from 'lucide-react';
import { Button } from '../ui/base/button';
import { useToast } from '@/hooks/use-toast';

export default function CTA({ hideBg = false }: { hideBg?: boolean }) {
  const { toast } = useToast();
  return (
    <div id="join-the-waitlist" className={`relative`}>
      <div
        className={`mx-auto absolute top-0 left-0 right-0 bottom-0 lg:max-w-[1264px] h-full flex justify-between z-[-1] ${hideBg ? 'hidden' : ''}`}
      >
        <div className="h-full"></div>
        <div className="w-[1px] h-full bg-neutral-200 drops"></div>
        <div className="w-[1px] h-full bg-neutral-200 drops2"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="h-full"></div>
        <div className="w-[1px] h-full bg-neutral-200 drops3"></div>
        <div className="w-[1px] h-full bg-neutral-200 drops4"></div>
        <div className="h-full"></div>
      </div>

      <div className="mx-auto max-w-7xl py-24 sm:px-6 sm:py-32 lg:px-8">
        <div className="sm:p-4 sm:border sm:border-neutral-200 bg-white/50 backdrop-blur-xs sm:rounded-[36px]">
          <section
            aria-labelledby="cta-heading"
            className="relative isolate overflow-hidden bg-white/50 border border-neutral-200 backdrop-blur-md px-6 py-16 shadow-xs sm:rounded-3xl sm:px-16 md:py-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0"
          >
            <svg
              aria-hidden="true"
              xmlns="http://www.w3.org/2000/svg"
              width="415"
              height="394"
              fill="none"
              className="absolute right-1/2 top-1/4 -z-10 size-[64rem] opacity-100 -translate-y-1/2 [mask-image:radial-gradient(closest-side,white,transparent)] sm:left-full sm:-ml-80 lg:left-1/2 lg:ml-0 lg:-translate-x-[90%] lg:translate-y-0"
              viewBox="0 0 415 394"
            >
              <circle
                cx="-17.089"
                cy="210.388"
                r="271.149"
                fill="url(#paint0_radial_2207_218)"
                fillOpacity="0.12"
                transform="rotate(-28.073 -17.09 210.388)"
              ></circle>
              <circle
                cx="-17.089"
                cy="210.388"
                r="270.649"
                stroke="#0284C7"
                strokeOpacity="0.1"
                transform="rotate(-28.073 -17.09 210.388)"
              ></circle>
              <ellipse
                cx="-16.646"
                cy="210.15"
                fill="url(#paint1_radial_2207_218)"
                fillOpacity="0.12"
                rx="319"
                ry="318.5"
                transform="rotate(-28.073 -16.646 210.15)"
              ></ellipse>
              <path
                stroke="#0284C7"
                strokeOpacity="0.1"
                d="M264.382 60.265c82.649 154.963 23.83 347.692-131.378 430.472s-348.029 24.261-430.678-130.702-23.83-347.692 131.378-430.472c155.209-82.78 348.029-24.261 430.678 130.702Z"
              ></path>
              <circle
                cx="-17.089"
                cy="210.387"
                r="221.872"
                fill="url(#paint2_radial_2207_218)"
                fillOpacity="0.12"
                transform="rotate(-28.073 -17.09 210.387)"
              ></circle>
              <circle
                cx="-17.089"
                cy="210.387"
                r="221.372"
                stroke="#0284C7"
                strokeOpacity="0.1"
                transform="rotate(-28.073 -17.09 210.387)"
              ></circle>
              <circle
                cx="-17.087"
                cy="210.385"
                r="164.5"
                fill="url(#paint3_radial_2207_218)"
                fillOpacity="0.12"
                transform="rotate(-28.073 -17.087 210.385)"
              ></circle>
              <circle
                cx="-17.087"
                cy="210.385"
                r="164"
                stroke="#0284C7"
                strokeOpacity="0.1"
                transform="rotate(-28.073 -17.087 210.385)"
              ></circle>
              <circle
                cx="-17.088"
                cy="210.387"
                r="104.5"
                fill="url(#paint4_radial_2207_218)"
                fillOpacity="0.12"
                transform="rotate(-28.073 -17.088 210.387)"
              ></circle>
              <circle
                cx="-17.088"
                cy="210.387"
                r="104"
                stroke="#0284C7"
                strokeOpacity="0.1"
                transform="rotate(-28.073 -17.088 210.387)"
              ></circle>
              <circle
                cx="-17.087"
                cy="210.385"
                r="41.5"
                fill="url(#paint5_radial_2207_218)"
                fillOpacity="0.12"
                transform="rotate(-28.073 -17.087 210.385)"
              ></circle>
              <circle
                cx="-17.087"
                cy="210.385"
                r="41"
                stroke="#0284C7"
                strokeOpacity="0.1"
                transform="rotate(-28.073 -17.087 210.385)"
              ></circle>
              <defs>
                <radialGradient
                  id="paint0_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="rotate(90 -113.739 96.65)scale(271.149)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
                <radialGradient
                  id="paint1_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="matrix(0 318.5 -319 0 -16.646 210.15)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
                <radialGradient
                  id="paint2_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="rotate(90 -113.738 96.649)scale(221.872)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
                <radialGradient
                  id="paint3_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="rotate(90 -113.737 96.65)scale(164.5)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
                <radialGradient
                  id="paint4_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="rotate(90 -113.737 96.65)scale(104.5)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
                <radialGradient
                  id="paint5_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="rotate(90 -113.736 96.649)scale(41.5)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
              </defs>
            </svg>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="415"
              height="394"
              fill="none"
              className="absolute right-1/2 top-1/4 scale-x-[-1] -z-10 size-[64rem] opacity-100 -translate-y-1/2 [mask-image:radial-gradient(closest-side,white,transparent)] sm:left-full sm:-ml-80 lg:left-1/2 lg:ml-0 lg:-translate-x-[10%] lg:translate-y-0"
              viewBox="0 0 415 394"
            >
              <circle
                cx="-17.089"
                cy="210.388"
                r="271.149"
                fill="url(#paint0_radial_2207_218)"
                fillOpacity="0.12"
                transform="rotate(-28.073 -17.09 210.388)"
              ></circle>
              <circle
                cx="-17.089"
                cy="210.388"
                r="270.649"
                stroke="#0284C7"
                strokeOpacity="0.1"
                transform="rotate(-28.073 -17.09 210.388)"
              ></circle>
              <ellipse
                cx="-16.646"
                cy="210.15"
                fill="url(#paint1_radial_2207_218)"
                fillOpacity="0.12"
                rx="319"
                ry="318.5"
                transform="rotate(-28.073 -16.646 210.15)"
              ></ellipse>
              <path
                stroke="#0284C7"
                strokeOpacity="0.1"
                d="M264.382 60.265c82.649 154.963 23.83 347.692-131.378 430.472s-348.029 24.261-430.678-130.702-23.83-347.692 131.378-430.472c155.209-82.78 348.029-24.261 430.678 130.702Z"
              ></path>
              <circle
                cx="-17.089"
                cy="210.387"
                r="221.872"
                fill="url(#paint2_radial_2207_218)"
                fillOpacity="0.12"
                transform="rotate(-28.073 -17.09 210.387)"
              ></circle>
              <circle
                cx="-17.089"
                cy="210.387"
                r="221.372"
                stroke="#0284C7"
                strokeOpacity="0.1"
                transform="rotate(-28.073 -17.09 210.387)"
              ></circle>
              <circle
                cx="-17.087"
                cy="210.385"
                r="164.5"
                fill="url(#paint3_radial_2207_218)"
                fillOpacity="0.12"
                transform="rotate(-28.073 -17.087 210.385)"
              ></circle>
              <circle
                cx="-17.087"
                cy="210.385"
                r="164"
                stroke="#0284C7"
                strokeOpacity="0.1"
                transform="rotate(-28.073 -17.087 210.385)"
              ></circle>
              <circle
                cx="-17.088"
                cy="210.387"
                r="104.5"
                fill="url(#paint4_radial_2207_218)"
                fillOpacity="0.12"
                transform="rotate(-28.073 -17.088 210.387)"
              ></circle>
              <circle
                cx="-17.088"
                cy="210.387"
                r="104"
                stroke="#0284C7"
                strokeOpacity="0.1"
                transform="rotate(-28.073 -17.088 210.387)"
              ></circle>
              <circle
                cx="-17.087"
                cy="210.385"
                r="41.5"
                fill="url(#paint5_radial_2207_218)"
                fillOpacity="0.12"
                transform="rotate(-28.073 -17.087 210.385)"
              ></circle>
              <circle
                cx="-17.087"
                cy="210.385"
                r="41"
                stroke="#0284C7"
                strokeOpacity="0.1"
                transform="rotate(-28.073 -17.087 210.385)"
              ></circle>
              <defs>
                <radialGradient
                  id="paint0_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="rotate(90 -113.739 96.65)scale(271.149)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
                <radialGradient
                  id="paint1_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="matrix(0 318.5 -319 0 -16.646 210.15)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
                <radialGradient
                  id="paint2_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="rotate(90 -113.738 96.649)scale(221.872)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
                <radialGradient
                  id="paint3_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="rotate(90 -113.737 96.65)scale(164.5)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
                <radialGradient
                  id="paint4_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="rotate(90 -113.737 96.65)scale(104.5)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
                <radialGradient
                  id="paint5_radial_2207_218"
                  cx="0"
                  cy="0"
                  r="1"
                  gradientTransform="rotate(90 -113.736 96.649)scale(41.5)"
                  gradientUnits="userSpaceOnUse"
                >
                  <stop stopColor="#0284C7"></stop>
                  <stop offset="1" stopColor="#0284C7"></stop>
                </radialGradient>
              </defs>
            </svg>
            <div className="mx-auto max-w-md text-center lg:flex-auto lg:py-32">
              <p className="text-sm/4 font-semibold text-sky-600 mb-2">Closed Beta</p>
              <h2
                id="cta-heading"
                className="text-balance text-3xl font-semibold tracking-tight text-black sm:text-4xl"
              >
                Join Our Waitlist
              </h2>
              <p className="mt-6 text-pretty text-lg/8 text-neutral-700">
                We are gearing up for our closed beta launch in 2025. Join the waitlist to secure
                your spot.
              </p>
              <div className="mt-8 flex items-center justify-center gap-x-6">
                <div className="relative w-full lg:mx-4">
                  <form
                    action="https://docs.google.com/forms/d/e/1FAIpQLScYXfLnmvyRogKKffPJ1R0c_sYWpAsAk_8lYWqEGWWSZGHX3Q/formResponse"
                    method="POST"
                    onSubmit={e => {
                      e.preventDefault();
                      const formData = new FormData(e.currentTarget);
                      fetch(e.currentTarget.action, {
                        method: 'POST',
                        body: formData,
                        mode: 'no-cors',
                      });
                      toast({
                        title: 'Submitted',
                        description: 'Thank you for joining the waitlist!',
                      });
                      e.currentTarget.reset();
                    }}
                  >
                    <label htmlFor="email-input" className="sr-only">
                      Email address
                    </label>
                    <input
                      id="email-input"
                      type="email"
                      name="entry.358867278"
                      placeholder="Email address"
                      aria-label="Email address"
                      className="block w-full rounded-2xl border border-neutral-200 bg-white/75 py-4 pl-6 pr-20 text-base/6 text-neutral-950 ring-4 ring-transparent transition placeholder:text-neutral-500 focus:border-sky-950 focus:outline-hidden focus:ring-sky-950/5"
                      required
                    />
                    <div className="absolute inset-y-1 right-1 flex justify-end">
                      <button
                        type="submit"
                        aria-label="Submit email to join waitlist"
                        className="flex aspect-square h-full items-center justify-center rounded-xl bg-sky-700 text-white transition hover:bg-sky-800 bg-linear-to-b border border-double outline-white/50 outline-offset-[-2px] border-black from-sky-900 to-blue-950"
                      >
                        <ArrowRightIcon className="w-4" aria-hidden="true" />
                      </button>
                    </div>
                  </form>
                </div>
              </div>
            </div>
          </section>
        </div>
      </div>
    </div>
  );
}



================================================
FILE: components/sections/4 - Footer.tsx
================================================
import { ArrowUpRightIcon } from 'lucide-react';

const navigation = {
  product: [{ name: 'Join Waitlist', href: '#join-the-waitlist' }],
  company: [
    { name: 'About', href: '/about' },
    { name: 'Blog', href: '/blog' },
    { name: 'Contact', href: '/contact' },
  ],
  legal: [
    { name: 'Terms of service', href: 'https://github.com/KoelLabs/.github/blob/main/TERMS.md' },
    { name: 'Privacy policy', href: 'https://github.com/KoelLabs/.github/blob/main/PRIVACY.md' },
    { name: 'License', href: 'https://github.com/KoelLabs#open-source-licensing' },
  ],
  social: [
    {
      name: 'LinkedIn',
      href: 'https://www.linkedin.com/company/koel-labs/',
      icon: props => (
        <svg fill="currentColor" viewBox="0 0 24 24" {...props}>
          <g clipPath="url(#clip0_2232_245)">
            <path d="M0 1.719C0 .769.789 0 1.763 0h20.475C23.21 0 24 .77 24 1.719v20.562c0 .95-.789 1.719-1.762 1.719H1.762C.788 24 0 23.23 0 22.281zm7.415 18.372V9.254H3.813V20.09zm-1.8-12.318c1.255 0 2.037-.831 2.037-1.872-.023-1.063-.78-1.872-2.014-1.872-1.232 0-2.038.81-2.038 1.872 0 1.041.781 1.872 1.99 1.872zm7.361 12.318v-6.052c0-.325.024-.649.12-.88.26-.646.852-1.317 1.848-1.317 1.304 0 1.824.993 1.824 2.451v5.798h3.602v-6.216c0-3.33-1.776-4.878-4.146-4.878-1.911 0-2.767 1.05-3.248 1.79v.037h-.024l.024-.037V9.254h-3.6c.046 1.017 0 10.837 0 10.837z"></path>
          </g>
          <defs>
            <clipPath id="clip0_2232_245">
              <path fill="#fff" d="M0 0h24v24H0z"></path>
            </clipPath>
          </defs>{' '}
        </svg>
      ),
    },
    {
      name: 'GitHub',
      href: 'https://github.com/koellabs',
      icon: props => (
        <svg fill="currentColor" viewBox="0 0 24 24" {...props}>
          <path
            fillRule="evenodd"
            d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
            clipRule="evenodd"
          />
        </svg>
      ),
    },
    {
      name: 'Instagram',
      href: 'https://www.instagram.com/koellabs/',
      icon: props => (
        <svg fill="currentColor" viewBox="0 0 24 24" {...props}>
          <path
            fillRule="evenodd"
            d="M12.315 2c2.43 0 2.784.013 3.808.06 1.064.049 1.791.218 2.427.465a4.902 4.902 0 011.772 1.153 4.902 4.902 0 011.153 1.772c.247.636.416 1.363.465 2.427.048 1.067.06 1.407.06 4.123v.08c0 2.643-.012 2.987-.06 4.043-.049 1.064-.218 1.791-.465 2.427a4.902 4.902 0 01-1.153 1.772 4.902 4.902 0 01-1.772 1.153c-.636.247-1.363.416-2.427.465-1.067.048-1.407.06-4.123.06h-.08c-2.643 0-2.987-.012-4.043-.06-1.064-.049-1.791-.218-2.427-.465a4.902 4.902 0 01-1.772-1.153 4.902 4.902 0 01-1.153-1.772c-.247-.636-.416-1.363-.465-2.427-.047-1.024-.06-1.379-.06-3.808v-.63c0-2.43.013-2.784.06-3.808.049-1.064.218-1.791.465-2.427a4.902 4.902 0 011.153-1.772A4.902 4.902 0 015.45 2.525c.636-.247 1.363-.416 2.427-.465C8.901 2.013 9.256 2 11.685 2h.63zm-.081 1.802h-.468c-2.456 0-2.784.011-3.807.058-.975.045-1.504.207-1.857.344-.467.182-.8.398-1.15.748-.35.35-.566.683-.748 1.15-.137.353-.3.882-.344 1.857-.047 1.023-.058 1.351-.058 3.807v.468c0 2.456.011 2.784.058 3.807.045.975.207 1.504.344 1.857.182.466.399.8.748 1.15.35.35.683.566 1.15.748.353.137.882.3 1.857.344 1.054.048 1.37.058 4.041.058h.08c2.597 0 2.917-.01 3.96-.058.976-.045 1.505-.207 1.858-.344.466-.182.8-.398 1.15-.748.35-.35.566-.683.748-1.15.137-.353.3-.882.344-1.857.048-1.055.058-1.37.058-4.041v-.08c0-2.597-.01-2.917-.058-3.96-.045-.976-.207-1.505-.344-1.858a3.097 3.097 0 00-.748-1.15 3.098 3.098 0 00-1.15-.748c-.353-.137-.882-.3-1.857-.344-1.023-.047-1.351-.058-3.807-.058zM12 6.865a5.135 5.135 0 110 10.27 5.135 5.135 0 010-10.27zm0 1.802a3.333 3.333 0 100 6.666 3.333 3.333 0 000-6.666zm5.338-3.205a1.2 1.2 0 110 2.4 1.2 1.2 0 010-2.4z"
            clipRule="evenodd"
          />
        </svg>
      ),
    },
    {
      name: 'X',
      href: 'https://x.com/koellabs',
      icon: props => (
        <svg fill="currentColor" viewBox="0 0 24 24" {...props}>
          <path d="M13.6823 10.6218L20.2391 3H18.6854L12.9921 9.61788L8.44486 3H3.2002L10.0765 13.0074L3.2002 21H4.75404L10.7663 14.0113L15.5685 21H20.8131L13.6819 10.6218H13.6823ZM11.5541 13.0956L10.8574 12.0991L5.31391 4.16971H7.70053L12.1742 10.5689L12.8709 11.5655L18.6861 19.8835H16.2995L11.5541 13.096V13.0956Z" />
        </svg>
      ),
    },
    {
      name: 'YouTube',
      href: 'https://www.youtube.com/@koellabs',
      icon: props => (
        <svg fill="currentColor" viewBox="0 0 24 24" {...props}>
          <path
            fillRule="evenodd"
            d="M19.812 5.418c.861.23 1.538.907 1.768 1.768C21.998 8.746 22 12 22 12s0 3.255-.418 4.814a2.504 2.504 0 0 1-1.768 1.768c-1.56.419-7.814.419-7.814.419s-6.255 0-7.814-.419a2.505 2.505 0 0 1-1.768-1.768C2 15.255 2 12 2 12s0-3.255.417-4.814a2.507 2.507 0 0 1 1.768-1.768C5.744 5 11.998 5 11.998 5s6.255 0 7.814.418ZM15.194 12 10 15V9l5.194 3Z"
            clipRule="evenodd"
          />
        </svg>
      ),
    },
  ],
};

export default function Footer() {
  return (
    <footer className="bg-white/50 border backdrop-blur-md border-neutral-200">
      <div className="mx-auto max-w-7xl px-6 pt-16 sm:pt-24 lg:px-8 lg:pt-32">
        <div className="xl:grid xl:grid-cols-3 xl:gap-8">
          <a href="/" className="text-2xl font-semibold  tracking-[-0.04em] h-fit w-fit">
            <svg
              width="770"
              height="859"
              viewBox="0 0 770 859"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
              className="h-8 w-8 mr-1 -mt-1.5 inline-block"
            >
              <rect width="769.162" height="859" fill="white" />
              <rect
                x="686.844"
                y="353.266"
                width="263.361"
                height="527.953"
                rx="131.681"
                transform="rotate(90 686.844 353.266)"
                fill="#154063"
              />
              <rect
                x="664.07"
                y="672.516"
                width="263.361"
                height="527.953"
                rx="131.681"
                transform="rotate(135 664.07 672.516)"
                fill="#3779B5"
              />
              <mask
                id="mask0_3106_273"
                style={{ maskType: 'alpha' }}
                maskUnits="userSpaceOnUse"
                x="158"
                y="353"
                width="529"
                height="264"
              >
                <rect
                  x="686.844"
                  y="353.266"
                  width="263.361"
                  height="527.953"
                  rx="131.681"
                  transform="rotate(90 686.844 353.266)"
                  fill="white"
                />
              </mask>
              <g mask="url(#mask0_3106_273)">
                <rect
                  x="664.07"
                  y="672.516"
                  width="263.361"
                  height="527.953"
                  rx="131.681"
                  transform="rotate(135 664.07 672.516)"
                  fill="#122438"
                />
              </g>
              <path
                d="M209.534 317.593C141.351 292.296 78.7053 137.133 81.4879 129.634C84.2704 122.134 232.961 45.3817 301.145 70.6792C369.328 95.9767 404.094 171.758 378.796 239.941C353.499 308.125 277.718 342.891 209.534 317.593Z"
                fill="black"
              />
            </svg>
            Koel Labs
          </a>
          <div className="mt-16 grid grid-cols-2 gap-8 xl:col-span-2 xl:mt-0 grid-flow-col">
            <div className="md:grid md:grid-cols-2 md:gap-8 ">
              <div></div>
              <div className="">
                <h3 className="text-sm/6 font-semibold text-neutral-900">Product</h3>
                <ul role="list" className="mt-6 space-y-4">
                  {navigation.product.map(item => (
                    <li key={item.name}>
                      <a
                        href={item.href}
                        className="text-sm/6 text-neutral-600 hover:text-neutral-900"
                      >
                        {item.name}
                      </a>
                    </li>
                  ))}
                </ul>
              </div>
            </div>

            <div className="md:grid md:grid-cols-2 md:gap-8">
              <div>
                <h3 className="text-sm/6 font-semibold text-neutral-900">Company</h3>
                <ul role="list" className="mt-6 space-y-4">
                  {navigation.company.map(item => (
                    <li key={item.name}>
                      <a
                        href={item.href}
                        className="text-sm/6 text-neutral-600 hover:text-neutral-900"
                      >
                        {item.name}
                      </a>
                    </li>
                  ))}
                </ul>
              </div>
              <div className="mt-10 md:mt-0">
                <h3 className="text-sm/6 font-semibold text-neutral-900">Legal</h3>
                <ul role="list" className="mt-6 space-y-4">
                  {navigation.legal.map(item => (
                    <li key={item.name}>
                      <a
                        href={item.href}
                        target="_blank"
                        className="text-sm/6 text-neutral-600 hover:text-neutral-900"
                      >
                        {item.name}
                        <ArrowUpRightIcon className="size-4 inline-block ml-1 mb-0.5 text-neutral-600" />
                      </a>
                    </li>
                  ))}
                </ul>
              </div>
            </div>
          </div>
        </div>
        {/* <div className="mt-16 border-t border-neutral-900/10 pt-8 sm:mt-20 lg:mt-24 lg:flex lg:items-center lg:justify-between">
          <div>
            <h3 className="text-sm/6 font-semibold text-neutral-900">
              Subscribe to our newsletter
            </h3>
            <p className="mt-2 text-sm/6 text-neutral-600">
              The latest news, articles, and resources, sent to your inbox weekly.
            </p>
          </div>
          <form className="mt-6 sm:flex sm:max-w-md lg:mt-0">
            <label htmlFor="email-address" className="sr-only">
              Email address
            </label>
            <input
              id="email-address"
              name="email-address"
              type="email"
              required
              placeholder="Enter your email"
              autoComplete="email"
              className="w-full min-w-0 rounded-md bg-white px-3 py-1.5 text-base text-neutral-900 outline outline-1 -outline-offset-1 outline-neutral-300 placeholder:text-neutral-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:w-56 sm:text-sm/6"
            />
            <div className="mt-4 sm:ml-4 sm:mt-0 sm:shrink-0">
              <button
                type="submit"
                className="flex w-full items-center justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
              >
                Subscribe
              </button>
            </div>
          </form>
        </div> */}
        <div className="mt-12 border-y border-neutral-900/10 py-8 md:flex md:items-center md:justify-between">
          <div className="flex gap-x-6 md:order-2">
            {navigation.social.map(item => (
              <a
                key={item.name}
                href={item.href}
                className="text-neutral-600 hover:text-neutral-800"
              >
                <span className="sr-only">{item.name}</span>
                <item.icon aria-hidden="true" className="size-6" />
              </a>
            ))}
          </div>
          <p className="mt-8 text-sm/6 text-neutral-600 md:order-1 md:mt-0">
            &copy; {new Date().getFullYear()} Koel Labs. All rights reserved.
          </p>
        </div>
        <div className="max-h-[224px] h-full w-full overflow-hidden bg-linear-to-b relative">
          <div className="absolute bottom-0 left-0 w-full h-full bg-linear-to-b from-transparent via-transparent to-white z-10"></div>
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="100%"
            height="100%"
            fill="none"
            className="mt-10 opacity-15"
            viewBox="0 0 911 164"
          >
            <path
              className="path-trace"
              stroke="#878787"
              d="m907.047 75.174-30.484 1.876q-.782-3.908-3.361-7.035-2.58-3.204-6.8-5.08-4.143-1.954-9.927-1.954-7.738 0-13.054 3.282-5.315 3.205-5.315 8.599 0 4.299 3.439 7.269t11.803 4.768l21.73 4.377q17.509 3.596 26.107 11.568 8.598 7.974 8.598 20.948 0 11.803-6.957 20.714-6.879 8.91-18.916 13.913-11.958 4.924-27.592 4.924-23.84 0-37.987-9.926-14.07-10.005-16.493-27.202l32.751-1.719q1.485 7.27 7.191 11.099 5.706 3.752 14.616 3.752 8.755 0 14.07-3.361 5.393-3.44 5.472-8.833-.079-4.533-3.831-7.425-3.751-2.97-11.568-4.534l-20.792-4.142q-17.586-3.518-26.185-12.194-8.519-8.677-8.519-22.12 0-11.57 6.253-19.932 6.331-8.364 17.743-12.897 11.49-4.534 26.888-4.534q22.746 0 35.8 9.614 13.131 9.615 15.32 26.185ZM681.051 160.998V.918h33.298v60.186h1.016q2.188-4.845 6.331-9.848 4.221-5.08 10.943-8.442 6.801-3.44 16.884-3.44 13.131 0 24.231 6.88 11.099 6.8 17.743 20.556 6.644 13.68 6.644 34.315 0 20.087-6.488 33.923-6.41 13.757-17.509 20.87-11.02 7.034-24.699 7.034-9.693 0-16.493-3.204-6.723-3.205-11.021-8.051-4.3-4.924-6.566-9.927h-1.485v19.228zm32.594-60.03q0 10.709 2.971 18.681t8.598 12.429q5.628 4.377 13.678 4.377 8.13 0 13.757-4.456 5.628-4.533 8.52-12.506 2.97-8.05 2.97-18.525 0-10.395-2.892-18.29t-8.52-12.35q-5.627-4.456-13.835-4.456-8.129 0-13.757 4.3-5.549 4.298-8.519 12.193-2.971 7.895-2.971 18.603ZM600.186 163.265q-11.49 0-20.479-3.986-8.99-4.065-14.226-11.959-5.159-7.972-5.159-19.854 0-10.005 3.674-16.805t10.005-10.943 14.382-6.253q8.13-2.11 17.04-2.97 10.474-1.094 16.884-2.033 6.41-1.016 9.301-2.97t2.892-5.784v-.47q0-7.425-4.69-11.49-4.611-4.064-13.131-4.064-8.99 0-14.304 3.986-5.316 3.909-7.035 9.85l-30.797-2.502q2.345-10.942 9.224-18.916 6.878-8.05 17.743-12.35 10.943-4.377 25.325-4.377q10.005 0 19.15 2.345 9.224 2.344 16.337 7.27 7.191 4.923 11.333 12.662 4.143 7.66 4.143 18.368V161H636.22V144.35h-.938q-2.892 5.627-7.738 9.926-4.846 4.221-11.647 6.644-6.8 2.345-15.711 2.345Zm9.536-22.98q7.347 0 12.975-2.892 5.628-2.97 8.833-7.973 3.204-5.002 3.205-11.334v-12.74q-1.565 1.015-4.299 1.876a79 79 0 0 1-6.019 1.485q-3.361.625-6.722 1.172-3.361.469-6.097.86-5.862.86-10.24 2.736-4.377 1.875-6.8 5.08-2.423 3.127-2.423 7.817 0 6.8 4.924 10.396 5.003 3.517 12.663 3.517ZM454.896 160.998V.918h33.846v132.176h68.628v27.904zM403.067.918v160.08H369.77V.918zM361.245 109.488v-9.145q0-15.32-4.299-26.732-4.299-11.49-12.037-19.072-7.66-7.582-17.978-11.334-10.24-3.83-22.121-3.83-17.665 0-30.796 7.816Q260.96 55.007 253.769 69t-7.191 32.517q0 18.993 7.191 32.907 7.192 13.834 20.479 21.417 13.366 7.503 31.891 7.503q14.851 0 26.185-4.533 11.412-4.612 18.603-12.819 7.27-8.285 9.615-19.385l-30.797-2.032q-1.72 4.534-5.003 7.66-3.282 3.126-7.894 4.69-4.612 1.563-10.162 1.563-8.363 0-14.46-3.517-6.096-3.518-9.458-10.005-3.282-6.487-3.283-15.399zm0 0h-81.76m.032-20.635h50.384q0-7.191-3.126-12.74t-8.677-8.677q-5.47-3.205-12.74-3.205-7.582 0-13.445 3.518-5.784 3.439-9.067 9.301c-2.188 3.856-3.277 7.061-3.329 11.803ZM183.889 163.343q-18.212 0-31.5-7.738-13.21-7.817-20.401-21.729-7.191-13.992-7.191-32.439 0-18.602 7.191-32.516 7.19-13.991 20.401-21.73 13.288-7.815 31.5-7.816 18.213 0 31.422 7.816 13.288 7.739 20.479 21.73 7.191 13.914 7.191 32.516 0 18.447-7.191 32.439-7.19 13.912-20.479 21.729-13.209 7.738-31.422 7.738Zm.156-25.794q8.286 0 13.835-4.69 5.55-4.767 8.364-12.975 2.892-8.207 2.892-18.681t-2.892-18.681q-2.814-8.208-8.364-12.976-5.549-4.767-13.835-4.768-8.363 0-14.069 4.768-5.628 4.769-8.52 12.976-2.814 8.206-2.814 18.681t2.814 18.681q2.892 8.208 8.52 12.975 5.706 4.69 14.069 4.69Z"
            ></path>
            <path
              className="path-trace"
              stroke="#878787"
              d="M.531 160.998V.918h33.845V71.5h2.11L94.095.918h40.567L75.256 72.595l60.109 88.403h-40.49l-43.85-65.814-16.649 20.323v45.491z"
            ></path>

            <g className="" mask="url(#mask)">
              <circle className="pulse-effect path-trace-footer" cx="50" cy="50" r="25"></circle>
            </g>
          </svg>
        </div>
      </div>
    </footer>
  );
}



================================================
FILE: components/sections/bento.tsx
================================================
import React from 'react';
import { Button } from '@/components/ui/base/button';
import Header from '@/components/ui/header';
import { ChevronRight, UserRoundPlus } from 'lucide-react';
import Link from 'next/link';
import { Card } from '@/components/ui/base/card';

export default function Bento() {
  return (
    <div id="learn-more" className="relative">
      <div className="mx-auto relative">
        <div className="mx-auto absolute h-full flex justify-between z-[-1]"></div>

        <section
          aria-labelledby="features-heading"
          className="mx-auto w-full h-fit bg-neutral-50/20 backdrop-blur-md border-y border-neutral-200 relative overflow-hidden"
        >
          <div className="bg-white py-24 sm:py-32">
            <div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8 z-10">
              <p className="text-base/7 font-semibold text-sky-600 relative z-10">What is this?</p>
              <h2
                id="features-heading"
                className="mt-2 text-pretty text-4xl font-semibold tracking-tighter text-gray-950 sm:text-5xl relative z-10"
              >
                Your new favorite tool for pronunciation learning
              </h2>
              <ul
                role="list"
                className="mt-10 grid grid-cols-1 gap-4 sm:mt-16 lg:grid-cols-6 lg:grid-rows-2"
              >
                <li className="relative lg:col-span-3">
                  <div className="absolute inset-px rounded-lg bg-white max-lg:rounded-t-[2rem] lg:rounded-tl-[2rem]" />
                  <article className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] max-lg:rounded-t-[calc(2rem+1px)] lg:rounded-tl-[calc(2rem+1px)]">
                    <img
                      alt="Screenshot showing the massive library of content available to practice with"
                      src="/images/bentoClips.png"
                      className="h-80 top-0 object-cover object-top"
                    />
                    <div className="p-10 pt-4">
                      <h3 className="text-sm/4 font-semibold text-sky-600">Engaging Content</h3>
                      <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                        Your favorite movies and shows
                      </p>
                      <p className="mt-2 max-w-lg text-sm/6 text-gray-600">
                        Practicing pronunciation has never been easier or more fun. Start learning
                        today with engaging scenes from iconic movies and shows.
                      </p>
                    </div>
                  </article>
                  <div className="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5 max-lg:rounded-t-[2rem] lg:rounded-tl-[2rem]" />
                </li>
                <li className="relative lg:col-span-3">
                  <div className="absolute inset-px rounded-lg bg-white lg:rounded-tr-[2rem]" />
                  <article className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] lg:rounded-tr-[calc(2rem+1px)]">
                    <img
                      alt="Screenshot showing detailed pronunciation feedback interface"
                      src="/images/bentoActionable.png"
                      className="h-80 object-cover object-left lg:object-top"
                    />
                    <div className="p-10 pt-4">
                      <h3 className="text-sm/4 font-semibold text-sky-600">Extensive Feedback</h3>
                      <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                        Actionable, tailored insights
                      </p>
                      <p className="mt-2 max-w-lg text-sm/6 text-gray-600">
                        Learn faster with our curated, actionable feedback, designed for maximum
                        impact, that gives you everything you need to start improving immediately.
                      </p>
                    </div>
                  </article>
                  <div className="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5 lg:rounded-tr-[2rem]" />
                </li>
                <li className="relative lg:col-span-2">
                  <div className="absolute inset-px rounded-lg bg-white lg:rounded-bl-[2rem]" />
                  <article className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] lg:rounded-bl-[calc(2rem+1px)]">
                    <img
                      alt="Screenshot showing analysis interface"
                      src="/images/bentoFeedback.png"
                      className="h-80 object-cover object-center"
                    />
                    <div className="p-10 pt-4">
                      <h3 className="text-sm/4 font-semibold text-sky-600">Speed</h3>
                      <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                        Real-time analysis
                      </p>
                      <p className="mt-2 max-w-lg text-sm/6 text-gray-600">
                        Get the first layer of feedback almost immediately after speaking.
                      </p>
                    </div>
                  </article>
                  <div className="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5 lg:rounded-bl-[2rem]" />
                </li>
                <li className="relative lg:col-span-2">
                  <div className="absolute inset-px rounded-lg bg-white" />
                  <article className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)]">
                    <img
                      alt="Screenshot showing deep practice mode"
                      src="/images/bentoComplex.png"
                      className="h-80 object-cover"
                    />
                    <div className="p-10 pt-4">
                      <h3 className="text-sm/4 font-semibold text-sky-600">Dive in Deep</h3>
                      <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                        Master even the hardest words
                      </p>
                      <p className="mt-2 max-w-lg text-sm/6 text-gray-600">
                        Practice hard-to-pronounce words by breaking them down into multiple
                        practical chunks.
                      </p>
                    </div>
                  </article>
                  <div className="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5" />
                </li>
                <li className="relative lg:col-span-2">
                  <div className="absolute inset-px rounded-lg bg-white max-lg:rounded-b-[2rem] lg:rounded-br-[2rem]" />
                  <article className="relative flex h-full flex-col overflow-hidden rounded-[calc(var(--radius-lg)+1px)] max-lg:rounded-b-[calc(2rem+1px)] lg:rounded-br-[calc(2rem+1px)]">
                    <img
                      alt="An image of the worlds map to highlight the diversity of dialects"
                      src="/images/bentoDialect.png"
                      className="h-80 object-cover"
                    />
                    <div className="p-10 pt-4">
                      <h3 className="text-sm/4 font-semibold text-sky-600">Dialect</h3>
                      <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                        Dialect-sensitive learning
                      </p>
                      <p className="mt-2 max-w-lg text-sm/6 text-gray-600">
                        Take control of your learning by choosing the dialect you want to practice.
                      </p>
                    </div>
                  </article>
                  <div className="pointer-events-none absolute inset-px rounded-lg shadow-sm ring-1 ring-black/5 max-lg:rounded-b-[2rem] lg:rounded-br-[2rem]" />
                </li>
              </ul>
            </div>
          </div>
        </section>
      </div>
    </div>
  );
}



================================================
FILE: components/sections/cta.tsx
================================================
'use client';
import { ArrowRightIcon } from 'lucide-react';
import { useToast } from '@/hooks/use-toast';

export default function CTA({ hideBg = false }: { hideBg?: boolean }) {
  const { toast } = useToast();
  return (
    <div id="join-the-waitlist" className={`relative overflow-hidden`}>
      <div className="mx-auto max-w-[1321px] sm:px-6 lg:px-[47.5px] relative">
        <svg
          width="1529"
          height="595"
          viewBox="0 0 1529 595"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
          className="absolute -left-[118.1%] top-0"
        >
          <rect
            x="1508.57"
            y="571.575"
            width="1275.15"
            height="550.149"
            rx="21.6909"
            transform="rotate(-180 1508.57 571.575)"
            fill="white"
            stroke="#E5E5E5"
            strokeWidth="0.850625"
          />
        </svg>

        <svg
          width="1529"
          height="595"
          viewBox="0 0 1529 595"
          fill="none"
          xmlns="http://www.w3.org/2000/svg"
          className="absolute -right-[118.1%] top-0"
        >
          <rect
            x="20.4253"
            y="23.4253"
            width="1275.15"
            height="550.149"
            rx="21.6909"
            fill="white"
            stroke="#E5E5E5"
            strokeWidth="0.850625"
          />
        </svg>

        <div className="absolute left-[-27px] top-0 h-full w-px bg-neutral-200"> </div>
        <div className="absolute right-[-27.5px] top-0 h-full w-px bg-neutral-200"> </div>

        <div className="absolute left-0 top-0 w-[43.5px] ml-px h-[43.5px] bg-neutral-50 p-1 z-[2] hidden 2xl:block">
          <div className="rounded-full w-full h-full border bg-white"></div>
        </div>

        <div className="absolute -right-[0.25px] top-0 w-[44px] mr-px h-[43.5px] bg-neutral-50 p-1 z-[2] hidden 2xl:block">
          <div className="rounded-full w-full h-full border bg-white"></div>
        </div>

        <div className="absolute left-0 bottom-0 w-[43.5px] ml-px h-[43.5px] bg-neutral-50 p-1 z-[2] hidden 2xl:block">
          <div className="rounded-full w-full h-full border bg-white"></div>
        </div>

        <div className="absolute right-0 bottom-0 w-[43.5px] mr-px h-[43.5px] bg-neutral-50 p-1 z-[2] hidden 2xl:block">
          <div className="rounded-full w-full h-full border bg-white"></div>
        </div>
        <div className="absolute -right-[0.5px] top-0 w-[46px] h-full overflow-hidden items-start justify-center bg-neutral-50 border-x z-[1] hidden 2xl:flex">
          <div className="flex-col h-full items-start gap-[8px] -mt-px flex">
            {Array(63)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`right-${i}`}
                  className="h-px w-[50.5px] bg-neutral-200 dark:bg-neutral-800"
                ></div>
              ))}
          </div>
        </div>
        <div className="absolute left-0 top-0 w-[45.5px] h-full overflow-hidden items-start justify-center bg-neutral-50 border-x z-[1] hidden 2xl:flex">
          <div className="flex-col h-full items-start gap-[8px] -mt-px flex">
            {Array(63)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`right-${i}`}
                  className="h-px w-[50.5px] bg-neutral-200 dark:bg-neutral-800"
                ></div>
              ))}
          </div>
        </div>
        <div className="sm:px-6 bg-white">
          <section
            aria-labelledby="cta-heading"
            className="relative isolate overflow-hidden bg-white bg-[url('/cta-bg.svg')] [background-size:300%] sm:[background-size:148%] bg-[50%_52.5%] px-6 py-16 sm:px-16 md:py-24 lg:flex lg:gap-x-20 lg:px-24 lg:py-12 border-x"
          >
            <div className="absolute left-0 top-0 w-full h-full bg-radial from-transparent via-white/10 to-white"></div>
            <div
              className="mx-auto max-w-md text-center lg:flex-auto lg:my-16 lg:mt-16 lg:pb-18 lg:pt-14 z-10 relative"
              data-cursor-size="2"
              data-cursor-collision="true"
            >
              <p className="text-sm/4 font-semibold text-sky-800 mb-2">Early Access</p>
              <h2
                id="cta-heading"
                className="text-balance text-3xl font-semibold tracking-tight text-black sm:text-4xl"
              >
                Be First in Line
              </h2>
              <p className="mt-6 text-pretty text-lg/8 text-neutral-700">
                We’re inviting a small group for early access to our research previews. Reserve your
                spot today.
              </p>
              <div className="mt-8 flex items-center justify-center gap-x-6">
                <div className="relative w-full lg:mx-4">
                  <form
                    action="https://docs.google.com/forms/d/e/1FAIpQLScYXfLnmvyRogKKffPJ1R0c_sYWpAsAk_8lYWqEGWWSZGHX3Q/formResponse"
                    method="POST"
                    onSubmit={e => {
                      e.preventDefault();
                      const formData = new FormData(e.currentTarget);
                      fetch(e.currentTarget.action, {
                        method: 'POST',
                        body: formData,
                        mode: 'no-cors',
                      });
                      toast({
                        title: 'Submitted',
                        description: 'Thank you for joining the waitlist!',
                      });
                      e.currentTarget.reset();
                    }}
                  >
                    <label htmlFor="email-input" className="sr-only">
                      Email address
                    </label>
                    <input
                      id="email-input"
                      type="email"
                      name="entry.358867278"
                      placeholder="Email address"
                      aria-label="Email address"
                      className="block w-full rounded-2xl border border-neutral-200 bg-white/75 py-4 pl-6 pr-20 text-base/6 text-neutral-950 ring-4 ring-transparent transition placeholder:text-neutral-500 focus:border-sky-950 focus:outline-hidden focus:ring-sky-950/5"
                      required
                    />
                    <div className="absolute inset-y-1 right-1 flex justify-end">
                      <button
                        type="submit"
                        aria-label="Submit email to join waitlist"
                        className="flex aspect-square h-full items-center justify-center rounded-xl text-white transition hover:bg-sky-800 bg-sky-950 cursor-pointer"
                      >
                        <ArrowRightIcon className="w-4" aria-hidden="true" />
                      </button>
                    </div>
                  </form>
                </div>
              </div>
            </div>
          </section>
        </div>
      </div>
    </div>
  );
}



================================================
FILE: components/sections/footer.tsx
================================================
import { ArrowUpRightIcon } from 'lucide-react';

const navigation = {
  research: [
    { name: 'Previews', href: '/previews' },
    { name: 'Publications', href: '/research' },
  ],
  lab: [
    { name: 'About', href: '/about' },
    { name: 'Blog', href: '/blog' },
    { name: 'Contact', href: '/contact' },
  ],
  legal: [
    { name: 'Terms of service', href: 'https://github.com/KoelLabs/.github/blob/main/TERMS.md' },
    { name: 'Privacy policy', href: 'https://github.com/KoelLabs/.github/blob/main/PRIVACY.md' },
    { name: 'License', href: 'https://github.com/KoelLabs#open-source-licensing' },
  ],
  social: [
    {
      name: 'LinkedIn',
      href: 'https://www.linkedin.com/company/koel-labs/',
      icon: props => (
        <svg fill="currentColor" viewBox="0 0 24 24" {...props}>
          <g clipPath="url(#clip0_2232_245)">
            <path d="M0 1.719C0 .769.789 0 1.763 0h20.475C23.21 0 24 .77 24 1.719v20.562c0 .95-.789 1.719-1.762 1.719H1.762C.788 24 0 23.23 0 22.281zm7.415 18.372V9.254H3.813V20.09zm-1.8-12.318c1.255 0 2.037-.831 2.037-1.872-.023-1.063-.78-1.872-2.014-1.872-1.232 0-2.038.81-2.038 1.872 0 1.041.781 1.872 1.99 1.872zm7.361 12.318v-6.052c0-.325.024-.649.12-.88.26-.646.852-1.317 1.848-1.317 1.304 0 1.824.993 1.824 2.451v5.798h3.602v-6.216c0-3.33-1.776-4.878-4.146-4.878-1.911 0-2.767 1.05-3.248 1.79v.037h-.024l.024-.037V9.254h-3.6c.046 1.017 0 10.837 0 10.837z"></path>
          </g>
          <defs>
            <clipPath id="clip0_2232_245">
              <path fill="#fff" d="M0 0h24v24H0z"></path>
            </clipPath>
          </defs>{' '}
        </svg>
      ),
    },
    {
      name: 'GitHub',
      href: 'https://github.com/koellabs',
      icon: props => (
        <svg fill="currentColor" viewBox="0 0 24 24" {...props}>
          <path
            fillRule="evenodd"
            d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
            clipRule="evenodd"
          />
        </svg>
      ),
    },
    {
      name: 'Instagram',
      href: 'https://www.instagram.com/koellabs/',
      icon: props => (
        <svg fill="currentColor" viewBox="0 0 24 24" {...props}>
          <path
            fillRule="evenodd"
            d="M12.315 2c2.43 0 2.784.013 3.808.06 1.064.049 1.791.218 2.427.465a4.902 4.902 0 011.772 1.153 4.902 4.902 0 011.153 1.772c.247.636.416 1.363.465 2.427.048 1.067.06 1.407.06 4.123v.08c0 2.643-.012 2.987-.06 4.043-.049 1.064-.218 1.791-.465 2.427a4.902 4.902 0 01-1.153 1.772 4.902 4.902 0 01-1.772 1.153c-.636.247-1.363.416-2.427.465-1.067.048-1.407.06-4.123.06h-.08c-2.643 0-2.987-.012-4.043-.06-1.064-.049-1.791-.218-2.427-.465a4.902 4.902 0 01-1.772-1.153 4.902 4.902 0 01-1.153-1.772c-.247-.636-.416-1.363-.465-2.427-.047-1.024-.06-1.379-.06-3.808v-.63c0-2.43.013-2.784.06-3.808.049-1.064.218-1.791.465-2.427a4.902 4.902 0 011.153-1.772A4.902 4.902 0 015.45 2.525c.636-.247 1.363-.416 2.427-.465C8.901 2.013 9.256 2 11.685 2h.63zm-.081 1.802h-.468c-2.456 0-2.784.011-3.807.058-.975.045-1.504.207-1.857.344-.467.182-.8.398-1.15.748-.35.35-.566.683-.748 1.15-.137.353-.3.882-.344 1.857-.047 1.023-.058 1.351-.058 3.807v.468c0 2.456.011 2.784.058 3.807.045.975.207 1.504.344 1.857.182.466.399.8.748 1.15.35.35.683.566 1.15.748.353.137.882.3 1.857.344 1.054.048 1.37.058 4.041.058h.08c2.597 0 2.917-.01 3.96-.058.976-.045 1.505-.207 1.858-.344.466-.182.8-.398 1.15-.748.35-.35.566-.683.748-1.15.137-.353.3-.882.344-1.857.048-1.055.058-1.37.058-4.041v-.08c0-2.597-.01-2.917-.058-3.96-.045-.976-.207-1.505-.344-1.858a3.097 3.097 0 00-.748-1.15 3.098 3.098 0 00-1.15-.748c-.353-.137-.882-.3-1.857-.344-1.023-.047-1.351-.058-3.807-.058zM12 6.865a5.135 5.135 0 110 10.27 5.135 5.135 0 010-10.27zm0 1.802a3.333 3.333 0 100 6.666 3.333 3.333 0 000-6.666zm5.338-3.205a1.2 1.2 0 110 2.4 1.2 1.2 0 010-2.4z"
            clipRule="evenodd"
          />
        </svg>
      ),
    },
    {
      name: 'X',
      href: 'https://x.com/koellabs',
      icon: props => (
        <svg fill="currentColor" viewBox="0 0 24 24" {...props}>
          <path d="M13.6823 10.6218L20.2391 3H18.6854L12.9921 9.61788L8.44486 3H3.2002L10.0765 13.0074L3.2002 21H4.75404L10.7663 14.0113L15.5685 21H20.8131L13.6819 10.6218H13.6823ZM11.5541 13.0956L10.8574 12.0991L5.31391 4.16971H7.70053L12.1742 10.5689L12.8709 11.5655L18.6861 19.8835H16.2995L11.5541 13.096V13.0956Z" />
        </svg>
      ),
    },
    {
      name: 'YouTube',
      href: 'https://www.youtube.com/@koellabs',
      icon: props => (
        <svg fill="currentColor" viewBox="0 0 24 24" {...props}>
          <path
            fillRule="evenodd"
            d="M19.812 5.418c.861.23 1.538.907 1.768 1.768C21.998 8.746 22 12 22 12s0 3.255-.418 4.814a2.504 2.504 0 0 1-1.768 1.768c-1.56.419-7.814.419-7.814.419s-6.255 0-7.814-.419a2.505 2.505 0 0 1-1.768-1.768C2 15.255 2 12 2 12s0-3.255.417-4.814a2.507 2.507 0 0 1 1.768-1.768C5.744 5 11.998 5 11.998 5s6.255 0 7.814.418ZM15.194 12 10 15V9l5.194 3Z"
            clipRule="evenodd"
          />
        </svg>
      ),
    },
  ],
};

export default function Footer() {
  return (
    <footer
      data-cursor-opacity="0.1"
      data-cursor-size="20"
      className="bg-white/50 backdrop-blur-md border-neutral-200 z-[999] relative"
    >
      <div className="mx-auto max-w-7xl px-6 pt-16 sm:pt-24 lg:px-8 lg:pt-32">
        <div className="xl:grid xl:grid-cols-3 xl:gap-8">
          <a href="/" className="text-2xl font-semibold  tracking-[-0.04em] h-fit w-fit">
            <svg
              width="770"
              height="859"
              viewBox="0 0 770 859"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
              className="h-8 w-8 mr-1 -mt-1.5 inline-block"
            >
              <rect width="769.162" height="859" fill="white" />
              <rect
                x="686.844"
                y="353.266"
                width="263.361"
                height="527.953"
                rx="131.681"
                transform="rotate(90 686.844 353.266)"
                fill="#154063"
              />
              <rect
                x="664.07"
                y="672.516"
                width="263.361"
                height="527.953"
                rx="131.681"
                transform="rotate(135 664.07 672.516)"
                fill="#3779B5"
              />
              <mask
                id="mask0_3106_273"
                style={{ maskType: 'alpha' }}
                maskUnits="userSpaceOnUse"
                x="158"
                y="353"
                width="529"
                height="264"
              >
                <rect
                  x="686.844"
                  y="353.266"
                  width="263.361"
                  height="527.953"
                  rx="131.681"
                  transform="rotate(90 686.844 353.266)"
                  fill="white"
                />
              </mask>
              <g mask="url(#mask0_3106_273)">
                <rect
                  x="664.07"
                  y="672.516"
                  width="263.361"
                  height="527.953"
                  rx="131.681"
                  transform="rotate(135 664.07 672.516)"
                  fill="#122438"
                />
              </g>
              <path
                d="M209.534 317.593C141.351 292.296 78.7053 137.133 81.4879 129.634C84.2704 122.134 232.961 45.3817 301.145 70.6792C369.328 95.9767 404.094 171.758 378.796 239.941C353.499 308.125 277.718 342.891 209.534 317.593Z"
                fill="black"
              />
            </svg>
            Koel Labs
          </a>
          <div className="mt-16 grid grid-cols-2 gap-8 xl:col-span-2 xl:mt-0 grid-flow-col">
            <div className="md:grid md:grid-cols-2 md:gap-8 ">
              <div></div>
              <div className="">
                <h3 className="text-sm/6 font-semibold text-neutral-900">Research</h3>
                <ul role="list" className="mt-6 space-y-4">
                  {navigation.research.map(item => (
                    <li key={item.name}>
                      <a
                        href={item.href}
                        className="text-sm/6 text-neutral-600 hover:text-neutral-900"
                      >
                        {item.name}
                      </a>
                    </li>
                  ))}
                </ul>
              </div>
            </div>

            <div className="md:grid md:grid-cols-2 md:gap-8">
              <div>
                <h3 className="text-sm/6 font-semibold text-neutral-900">Lab</h3>
                <ul role="list" className="mt-6 space-y-4">
                  {navigation.lab.map(item => (
                    <li key={item.name}>
                      <a
                        href={item.href}
                        className="text-sm/6 text-neutral-600 hover:text-neutral-900"
                      >
                        {item.name}
                      </a>
                    </li>
                  ))}
                </ul>
              </div>
              <div className="mt-10 md:mt-0">
                <h3 className="text-sm/6 font-semibold text-neutral-900">Legal</h3>
                <ul role="list" className="mt-6 space-y-4">
                  {navigation.legal.map(item => (
                    <li key={item.name}>
                      <a
                        href={item.href}
                        target="_blank"
                        className="text-sm/6 text-neutral-600 hover:text-neutral-900"
                      >
                        {item.name}
                        <ArrowUpRightIcon className="size-4 inline-block ml-1 mb-0.5 text-neutral-600" />
                      </a>
                    </li>
                  ))}
                </ul>
              </div>
            </div>
          </div>
        </div>
        {/* <div className="mt-16 border-t border-neutral-900/10 pt-8 sm:mt-20 lg:mt-24 lg:flex lg:items-center lg:justify-between">
          <div>
            <h3 className="text-sm/6 font-semibold text-neutral-900">
              Subscribe to our newsletter
            </h3>
            <p className="mt-2 text-sm/6 text-neutral-600">
              The latest news, articles, and resources, sent to your inbox weekly.
            </p>
          </div>
          <form className="mt-6 sm:flex sm:max-w-md lg:mt-0">
            <label htmlFor="email-address" className="sr-only">
              Email address
            </label>
            <input
              id="email-address"
              name="email-address"
              type="email"
              required
              placeholder="Enter your email"
              autoComplete="email"
              className="w-full min-w-0 rounded-md bg-white px-3 py-1.5 text-base text-neutral-900 outline outline-1 -outline-offset-1 outline-neutral-300 placeholder:text-neutral-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:w-56 sm:text-sm/6"
            />
            <div className="mt-4 sm:ml-4 sm:mt-0 sm:shrink-0">
              <button
                type="submit"
                className="flex w-full items-center justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
              >
                Subscribe
              </button>
            </div>
          </form>
        </div> */}
        <div className="mt-12 border-y border-neutral-900/10 py-8 md:flex md:items-center md:justify-between">
          <div className="flex gap-x-6 md:order-2">
            {navigation.social.map(item => (
              <a
                key={item.name}
                href={item.href}
                className="text-neutral-600 hover:text-neutral-800"
              >
                <span className="sr-only">{item.name}</span>
                <item.icon aria-hidden="true" className="size-6" />
              </a>
            ))}
          </div>
          <p className="mt-8 text-sm/6 text-neutral-600 md:order-1 md:mt-0">
            &copy; {new Date().getFullYear()} Koel Labs. All rights reserved.
          </p>
        </div>
        <div className="max-h-[224px] h-full w-full overflow-hidden bg-linear-to-b relative">
          <div className="absolute bottom-0 left-0 w-full h-full bg-linear-to-b from-transparent via-transparent to-white z-10"></div>
          <svg
            xmlns="http://www.w3.org/2000/svg"
            width="100%"
            height="100%"
            fill="none"
            className="mt-10 opacity-15"
            viewBox="0 0 911 164"
          >
            <path
              className="path-trace"
              stroke="#878787"
              d="m907.047 75.174-30.484 1.876q-.782-3.908-3.361-7.035-2.58-3.204-6.8-5.08-4.143-1.954-9.927-1.954-7.738 0-13.054 3.282-5.315 3.205-5.315 8.599 0 4.299 3.439 7.269t11.803 4.768l21.73 4.377q17.509 3.596 26.107 11.568 8.598 7.974 8.598 20.948 0 11.803-6.957 20.714-6.879 8.91-18.916 13.913-11.958 4.924-27.592 4.924-23.84 0-37.987-9.926-14.07-10.005-16.493-27.202l32.751-1.719q1.485 7.27 7.191 11.099 5.706 3.752 14.616 3.752 8.755 0 14.07-3.361 5.393-3.44 5.472-8.833-.079-4.533-3.831-7.425-3.751-2.97-11.568-4.534l-20.792-4.142q-17.586-3.518-26.185-12.194-8.519-8.677-8.519-22.12 0-11.57 6.253-19.932 6.331-8.364 17.743-12.897 11.49-4.534 26.888-4.534q22.746 0 35.8 9.614 13.131 9.615 15.32 26.185ZM681.051 160.998V.918h33.298v60.186h1.016q2.188-4.845 6.331-9.848 4.221-5.08 10.943-8.442 6.801-3.44 16.884-3.44 13.131 0 24.231 6.88 11.099 6.8 17.743 20.556 6.644 13.68 6.644 34.315 0 20.087-6.488 33.923-6.41 13.757-17.509 20.87-11.02 7.034-24.699 7.034-9.693 0-16.493-3.204-6.723-3.205-11.021-8.051-4.3-4.924-6.566-9.927h-1.485v19.228zm32.594-60.03q0 10.709 2.971 18.681t8.598 12.429q5.628 4.377 13.678 4.377 8.13 0 13.757-4.456 5.628-4.533 8.52-12.506 2.97-8.05 2.97-18.525 0-10.395-2.892-18.29t-8.52-12.35q-5.627-4.456-13.835-4.456-8.129 0-13.757 4.3-5.549 4.298-8.519 12.193-2.971 7.895-2.971 18.603ZM600.186 163.265q-11.49 0-20.479-3.986-8.99-4.065-14.226-11.959-5.159-7.972-5.159-19.854 0-10.005 3.674-16.805t10.005-10.943 14.382-6.253q8.13-2.11 17.04-2.97 10.474-1.094 16.884-2.033 6.41-1.016 9.301-2.97t2.892-5.784v-.47q0-7.425-4.69-11.49-4.611-4.064-13.131-4.064-8.99 0-14.304 3.986-5.316 3.909-7.035 9.85l-30.797-2.502q2.345-10.942 9.224-18.916 6.878-8.05 17.743-12.35 10.943-4.377 25.325-4.377q10.005 0 19.15 2.345 9.224 2.344 16.337 7.27 7.191 4.923 11.333 12.662 4.143 7.66 4.143 18.368V161H636.22V144.35h-.938q-2.892 5.627-7.738 9.926-4.846 4.221-11.647 6.644-6.8 2.345-15.711 2.345Zm9.536-22.98q7.347 0 12.975-2.892 5.628-2.97 8.833-7.973 3.204-5.002 3.205-11.334v-12.74q-1.565 1.015-4.299 1.876a79 79 0 0 1-6.019 1.485q-3.361.625-6.722 1.172-3.361.469-6.097.86-5.862.86-10.24 2.736-4.377 1.875-6.8 5.08-2.423 3.127-2.423 7.817 0 6.8 4.924 10.396 5.003 3.517 12.663 3.517ZM454.896 160.998V.918h33.846v132.176h68.628v27.904zM403.067.918v160.08H369.77V.918zM361.245 109.488v-9.145q0-15.32-4.299-26.732-4.299-11.49-12.037-19.072-7.66-7.582-17.978-11.334-10.24-3.83-22.121-3.83-17.665 0-30.796 7.816Q260.96 55.007 253.769 69t-7.191 32.517q0 18.993 7.191 32.907 7.192 13.834 20.479 21.417 13.366 7.503 31.891 7.503q14.851 0 26.185-4.533 11.412-4.612 18.603-12.819 7.27-8.285 9.615-19.385l-30.797-2.032q-1.72 4.534-5.003 7.66-3.282 3.126-7.894 4.69-4.612 1.563-10.162 1.563-8.363 0-14.46-3.517-6.096-3.518-9.458-10.005-3.282-6.487-3.283-15.399zm0 0h-81.76m.032-20.635h50.384q0-7.191-3.126-12.74t-8.677-8.677q-5.47-3.205-12.74-3.205-7.582 0-13.445 3.518-5.784 3.439-9.067 9.301c-2.188 3.856-3.277 7.061-3.329 11.803ZM183.889 163.343q-18.212 0-31.5-7.738-13.21-7.817-20.401-21.729-7.191-13.992-7.191-32.439 0-18.602 7.191-32.516 7.19-13.991 20.401-21.73 13.288-7.815 31.5-7.816 18.213 0 31.422 7.816 13.288 7.739 20.479 21.73 7.191 13.914 7.191 32.516 0 18.447-7.191 32.439-7.19 13.912-20.479 21.729-13.209 7.738-31.422 7.738Zm.156-25.794q8.286 0 13.835-4.69 5.55-4.767 8.364-12.975 2.892-8.207 2.892-18.681t-2.892-18.681q-2.814-8.208-8.364-12.976-5.549-4.767-13.835-4.768-8.363 0-14.069 4.768-5.628 4.769-8.52 12.976-2.814 8.206-2.814 18.681t2.814 18.681q2.892 8.208 8.52 12.975 5.706 4.69 14.069 4.69Z"
            ></path>
            <path
              className="path-trace"
              stroke="#878787"
              d="M.531 160.998V.918h33.845V71.5h2.11L94.095.918h40.567L75.256 72.595l60.109 88.403h-40.49l-43.85-65.814-16.649 20.323v45.491z"
            ></path>

            <g className="" mask="url(#mask)">
              <circle className="pulse-effect path-trace-footer" cx="50" cy="50" r="25"></circle>
            </g>
          </svg>
        </div>
      </div>
    </footer>
  );
}



================================================
FILE: components/sections/hero.tsx
================================================
'use client';
import React from 'react';
import { ArrowUpRight } from 'lucide-react';
import { Card } from '@/components/ui/base/card';
import HeroVideoDialog from '@/components/ui/magicui/hero-video-dialog';
import { Button } from '@/components/ui/base/button';
import Link from 'next/link';

export default function HeroNew() {
  return (
    <div className="relative min-h-[900px] h-full">
      <div className="absolute right-0 -top-20 w-full h-[500px] bg-gradient-to-b from-white via-10% via-white to-transparent z-[0]"></div>

      <div className="absolute left-0 bottom-0 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[2] hidden 2xl:block">
        <div className="rounded-full w-full h-full border bg-white"></div>
      </div>

      <div className="absolute right-0 bottom-0 w-[49.3px] h-[49px] bg-neutral-50 p-1 z-[2] hidden 2xl:block">
        <div className="rounded-full w-full h-full border bg-white"></div>
      </div>
      {/* <div className="absolute right-0 -top-20 w-full h-[110%] bg-gradient-to-b from-[#0086FF] to-[#2A4BCC] z-[2] mix-blend-color pointer-events-none"></div> */}
      {/* <div className="absolute left-0 -top-20 w-[60px] h-[110%] bg-gradient-to-b from-[#0086FF] to-[#2A4BCC] z-[2] mix-blend-color"></div> */}

      <div className="absolute right-0 -top-20 w-[50.5px] h-[110%] overflow-hidden items-start justify-center bg-neutral-50 border-x z-[-1] hidden 2xl:flex shadow-xl">
        <div className="flex-col h-full items-start gap-[8px] mt-[2px] flex">
          {Array(165)
            .fill(0)
            .map((_, i) => (
              <div
                key={`right-${i}`}
                className="h-px w-[50.5px] bg-neutral-200 dark:bg-neutral-800"
              ></div>
            ))}
        </div>
      </div>
      <div className="absolute left-0 -top-20 w-[50.5px] h-[110%] overflow-hidden items-start justify-center bg-neutral-50 border-x z-[-1] hidden 2xl:flex shadow-xl">
        <div className="flex-col h-full items-start gap-[8px] mt-[2px] flex">
          {Array(165)
            .fill(0)
            .map((_, i) => (
              <div
                key={`right-${i}`}
                className="h-px w-[50.5px] bg-neutral-200 dark:bg-neutral-800"
              ></div>
            ))}
        </div>
      </div>
      <div className="mx-auto md:px-6 pt-0 lg:px-8 py-32 pb-0">
        <div className="mx-auto p-4 max-w-4xl py-32 z-[999] relative">
          <section aria-labelledby="hero-heading" className="text-center relative">
            {/* <div className="flex flex-row justify-center items-center my-8"></div> */}
            <div className="hidden sm:mb-8 sm:flex sm:justify-center relative z-10 max-w-sm mx-auto">
              <div className="relative rounded-full px-2 py-0.5 pr-4.5 text-sm/6 text-gray-600 border-y border-l rounded-r-none">
                A new look for Koel Labs{' '}
              </div>
              <a
                href="/blog/new-look-for-koel-labs"
                className="font-semibold text-sky-600 rounded-full shadow-xs bg-white -ml-3 pl-2.5 border-l-none border text-sm/6 px-2 py-0.5 inset-0"
              >
                <span aria-hidden="true" className="absolute inset-0 tracking-tight" />
                Read more <ArrowUpRight className="w-4 h-4 inline-block -ml-0.5" strokeWidth={3} />
              </a>
            </div>
            <h1
              id="hero-heading"
              className=" text-4xl font-semibold tracking-tighter text-gray-950 sm:text-6xl relative text-balance ligat"
            >
              Pioneering Inclusive Speech Technology for Everyone
            </h1>

            <p className="mt-6 sm:text-lg leading-7 sm:leading-8 text-neutral-600 max-w-xl mx-auto text-pretty">
              We are building out state-of-the-art models, tools, and datasets to make speech
              technologies more inclusive for all dialects.
            </p>
            <div className="mt-6 flex flex-col gap-2 sm:flex-row items-center justify-center gap-x-4 w-full">
              <Link href="/research" className="w-full sm:w-auto">
                <Button
                  variant="outline"
                  className="active:scale-[97%] transition-all duration-50 w-full sm:w-auto"
                >
                  Read our research
                </Button>
              </Link>
              <Link href="/previews" className="w-full sm:w-auto">
                <Button className="active:scale-[97%] transition-all duration-50 w-full sm:w-auto">
                  View our demos
                </Button>
              </Link>
            </div>
          </section>
        </div>

        {/* <div className="absolute -bottom-2  h-[65px] w-[90%] bg-gradient-to-b from-[#0086FF] to-[#2A4BCC] z-[3] mix-blend-color"></div> */}

        {/* <div className="absolute bottom-0 left-0 w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-t">
          <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div> */}
        <div className="mx-auto absolute opacity-25 sm:opacity-100 top-0 left-0 right-0 bottom-0 lg:max-w-[1264px] flex justify-between z-[-1] h-[1600px]">
          <div className="h-full"></div>
          <div className="w-[1px] h-full bg-gradient-to-b from-white via-30% via-neutral-200 to-neutral-200"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="h-full"></div>
          <div className="w-[1px] h-full bg-gradient-to-b from-white via-30% via-neutral-200 to-neutral-200"></div>
          <div className="h-full"></div>
        </div>
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="141"
          height="906"
          fill="none"
          className="absolute -bottom-28 xl:right-0 hidden 2xl:block z-[-3]"
          viewBox="0 0 141 906"
        >
          <path
            stroke="#E5E5E5"
            d="M140.505 0C140.505 97.5.721-.44.707 97.06c-.008 57.199 0 447.333 0 610.999m139.798 197.003c0-97.5-139.784.441-139.798-97.059-.008-57.2 0-447.333 0-611"
          ></path>
        </svg>
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="141"
          height="906"
          fill="none"
          className="absolute rotate-180 -bottom-28 xl:left-0 hidden 2xl:block z-[-3]"
          viewBox="0 0 141 906"
        >
          <path
            stroke="#E5E5E5"
            d="M140.505 0C140.505 97.5.721-.44.707 97.06c-.008 57.199 0 447.333 0 610.999m139.798 197.003c0-97.5-139.784.441-139.798-97.059-.008-57.2 0-447.333 0-611"
          ></path>
        </svg>

        <div className="flex justify-center sm:overflow-visible overflow-hidden mb-[127px]">
          <Card
            data-cursor-size="200"
            className=" max-w-[1200px] min-w-[500px] p-6 bg-white rounded-[32px] shadow-xl w-full h-fit mx-auto  z-[30] "
          >
            {/* <div className="flex flex-col items-center justify-center aspect-video w-full h-full border rounded-[12px] shadow-lg"></div> */}
            <HeroVideoDialog
              className="rounded-[500px] z-[30] relative"
              animationStyle="top-in-bottom-out"
              videoSrc="https://www.youtube.com/watch?v=s7yPjSUjU9s"
              thumbnailSrc="/images/demoPitchUpdated.png"
              thumbnailAlt="Hero Video"
            />
          </Card>
        </div>
      </div>
    </div>
  );
}



================================================
FILE: components/sections/models.tsx
================================================
import React from 'react';
import { Button } from '@/components/ui/base/button';
import Link from 'next/link';

export default function Models() {
  return (
    <div id="models" className="relative">
      <svg
        width="75"
        height="905"
        viewBox="0 0 75 905"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
        className="absolute top-4 left-0 z-[1] hidden 2xl:block"
      >
        <g clipPath="url(#clip0_3877_301)">
          <path
            d="M69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433C-69.6808 97.3525 69.9825 -0.460876 69.9963 96.9968C70.0013 132.346 70.0002 294.846 69.9986 452.469C70.0002 610.092 70.0014 772.592 69.9964 807.941Z"
            fill="#ffffff"
          />
          <path
            d="M69.9963 196.941C69.9963 360.607 70.0045 750.741 69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433M-69.8022 -0.0624878C-69.8022 -0.0201653 -69.8022 0.0220944 -69.8022 0.0643433M69.9964 707.997C69.9964 544.33 70.0044 154.197 69.9963 96.9968C69.9825 -0.460854 -69.6808 97.3525 -69.8022 0.0643433"
            stroke="#E5E5E5"
          />
        </g>
        <defs>
          <clipPath id="clip0_3877_301">
            <rect
              width="75.0001"
              height="905"
              fill="white"
              transform="translate(75 905) rotate(180)"
            />
          </clipPath>
        </defs>
      </svg>

      <svg
        width="75"
        height="905"
        viewBox="0 0 75 905"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
        className="absolute top-4 right-0 z-[1] rotate-180 hidden 2xl:block"
      >
        <g clipPath="url(#clip0_3877_301)">
          <path
            d="M69.9963 196.941C69.9963 360.607 70.0045 750.741 69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433M-69.8022 -0.0624878C-69.8022 -0.0201653 -69.8022 0.0220944 -69.8022 0.0643433M69.9964 707.997C69.9964 544.33 70.0044 154.197 69.9963 96.9968C69.9825 -0.460854 -69.6808 97.3525 -69.8022 0.0643433"
            stroke="#E5E5E5"
          />
        </g>
        <defs>
          <clipPath id="clip0_3877_301">
            <rect
              width="75.0001"
              height="905"
              fill="white"
              transform="translate(75 905) rotate(180)"
            />
          </clipPath>
        </defs>
      </svg>

      <div className="mx-auto">
        <div className="mx-auto absolute h-full flex justify-between z-[-1]"></div>

        <section
          aria-labelledby="features-heading"
          className="mx-auto w-full h-fit bg-neutral-50/20 backdrop-blur-md border-y border-neutral-200 overflow-hidden"
        >
          <div
            data-cursor-opacity="0.8"
            data-cursor-size="240"
            data-cursor-color="#2A4BCC"
            className="bg-white py-24 sm:py-32"
          >
            <div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8 z-[1000] relative">
              <p className="text-base/7 font-semibold text-sky-600 relative z-10">Models</p>
              <h2
                id="features-heading"
                className="mt-2 text-balance text-4xl font-semibold tracking-tighter text-gray-950 sm:text-5xl relative z-10 sm:block hidden"
              >
                The latest and greatest in phonetic models
              </h2>
              <h2
                id="features-heading"
                className="mt-2 text-balance text-4xl font-semibold tracking-tighter text-gray-950 sm:text-5xl relative z-10 sm:hidden block"
              >
                The greatest in phonetic models
              </h2>
              <ul
                role="list"
                data-cursor-opacity="1"
                data-cursor-size="340"
                className="mt-12 grid lg:p-2 z-10 grid-cols-1 lg:grid-cols-2 relative gap-10 `"
              >
                <li className="relative group">
                  <Link href="/research">
                    <div className="relative p-2 aspect-square rounded-[32px] bg-white border overflow-hidden">
                      <img
                        alt="Screenshot showing the massive library of content available to practice with"
                        src="/images/models.webp"
                        className="h-full aspect-video object-cover object-top rounded-3xl border bg-white border-black/10 saturate-200"
                      />
                    </div>
                  </Link>
                </li>
                <li
                  data-cursor-opacity="0.5"
                  data-cursor-size="100"
                  data-cursor-collision="true"
                  className="px-2 md:px-6 lg:px-0 lg:pr-4 lg:pt-4"
                >
                  <div className="mx-auto max-w-2xl lg:mx-0 lg:max-w-lg">
                    <p className="lg:-mt-4 xl:mt-4 text-md/8 text-neutral-600 text-pretty">
                      We introduce a state-of-the-art phonetic transcription model, XLSR-English-01,
                      which transcribes both standard and non-standard English speech, achieving a
                      60% improvement in feature error rate over other phonetic models, including
                      Facebook's model, Facebook 60.
                    </p>
                    <p className="mt-6 text-md/8 text-neutral-600 text-pretty">
                      To develop truly inclusive speech technology, models should be able to
                      accurately transcribe diverse speaker profiles, from speech impediments to
                      non-native speech.
                    </p>
                    <p className="mt-6 text-md/8 text-neutral-600 text-pretty">
                      In light of this, we test our model on speech aphasia data (PSST) and
                      non-native speech spanning from Italian and German (ISLE) to Mandarin
                      (SpeechOcean) accented speech.
                    </p>
                    <p className="mt-6 text-md/8 text-neutral-600 text-pretty">
                      This model marks our second major update from our previous SoTA model
                      (Koel-Labs-B0), and we aim to continuously improve upon phonetic transcription
                      models in both their transcription quality and inference time.
                    </p>
                    <div className="mt-6 border rounded-[20px] p-2 w-full flex flex-col sm:flex-row gap-2">
                      <Link href="https://koellabs.com/blog#technical-reports" className="w-full">
                        <Button
                          variant="outline"
                          className="w-full active:scale-[97%] transition-all duration-50 "
                        >
                          <p>View Technical Reports</p>
                        </Button>
                      </Link>
                      <Link
                        href="https://huggingface.co/KoelLabs/xlsr-english-01"
                        className="w-full"
                      >
                        <Button className="w-full active:scale-[97%] transition-all duration-50 ">
                          <p>View on Huggingface</p>
                        </Button>
                      </Link>
                    </div>
                    {/* <div className="mt-6 border rounded-3xl p-2 w-full flex flex-row gap-2">
                      <div className="size-24 rounded-2xl border"></div>
                    </div>
                    <div className="mt-6 border rounded-3xl p-2 w-full flex flex-row gap-2">
                      <div className="size-24 rounded-2xl border"></div>
                    </div>
                    <div className="mt-6 border rounded-3xl p-2 w-full flex flex-row gap-2">
                      <div className="size-24 rounded-2xl border"></div>
                    </div> */}
                  </div>
                </li>
              </ul>
            </div>
          </div>
        </section>
      </div>
    </div>
  );
}



================================================
FILE: components/sections/previews.tsx
================================================
const previews = [
  {
    title: 'Phonetic Models',
    status: 'Available',
    description:
      'XLSR-English-01, the state-of-the-art model for phonetic transcription, is available on Huggingface, alongside our other models, various datasets, and our IPA transcription leaderboard.',
    image: '/images/card-one.svg',
  },
  {
    title: 'Phrase Segmentation',
    status: 'In Beta',
    description:
      'Phrase Segmentation, our demonstration tool for how phonetic transcription models will eventually interact with users in conjunction with language learning materials, is now available in closed beta.  ',
    image: '/images/card-two.svg',
  },
  {
    title: 'Speech Analysis',
    status: 'Upcoming',
    description:
      'A robust and open speech analysis tool, powered by our own models, to allow for real-time feedback to users about speech, based on an actor reference, not a restricted, arbitrary standard.',
    image: '/images/card-three.svg',
  },
];

export default function Previews() {
  return (
    <div id="previews" className=" relative">
      <svg
        width="75"
        height="905"
        viewBox="0 0 75 905"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
        className="absolute top-24 left-0 z-[1] hidden 2xl:block"
      >
        <g clipPath="url(#clip0_3877_301)">
          <path
            d="M69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433C-69.6808 97.3525 69.9825 -0.460876 69.9963 96.9968C70.0013 132.346 70.0002 294.846 69.9986 452.469C70.0002 610.092 70.0014 772.592 69.9964 807.941Z"
            fill="#ffffff"
          />
          <path
            d="M69.9963 196.941C69.9963 360.607 70.0045 750.741 69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433M-69.8022 -0.0624878C-69.8022 -0.0201653 -69.8022 0.0220944 -69.8022 0.0643433M69.9964 707.997C69.9964 544.33 70.0044 154.197 69.9963 96.9968C69.9825 -0.460854 -69.6808 97.3525 -69.8022 0.0643433"
            stroke="#E5E5E5"
          />
        </g>
        <defs>
          <clipPath id="clip0_3877_301">
            <rect
              width="75.0001"
              height="905"
              fill="white"
              transform="translate(75 905) rotate(180)"
            />
          </clipPath>
        </defs>
      </svg>

      <svg
        width="75"
        height="905"
        viewBox="0 0 75 905"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
        className="absolute top-24 right-0 z-[1] rotate-180 hidden 2xl:block"
      >
        <g clipPath="url(#clip0_3877_301)">
          <path
            d="M69.9963 196.941C69.9963 360.607 70.0045 750.741 69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433M-69.8022 -0.0624878C-69.8022 -0.0201653 -69.8022 0.0220944 -69.8022 0.0643433M69.9964 707.997C69.9964 544.33 70.0044 154.197 69.9963 96.9968C69.9825 -0.460854 -69.6808 97.3525 -69.8022 0.0643433"
            stroke="#E5E5E5"
          />
        </g>
        <defs>
          <clipPath id="clip0_3877_301">
            <rect
              width="75.0001"
              height="905"
              fill="white"
              transform="translate(75 905) rotate(180)"
            />
          </clipPath>
        </defs>
      </svg>
      <div className=" w-full h-[50px] overflow-hidden flex items-start justify-center bg-neutral-50 border-b">
        <div className="flex h-full items-start gap-[7.99px] ml-[0.2px]">
          {Array(500)
            .fill(0)
            .map((_, i) => (
              <div
                key={`bottom-${i}`}
                className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
              ></div>
            ))}
        </div>
      </div>
      <div className="mx-auto">
        <section
          aria-labelledby="features-heading"
          className="mx-auto w-full h-fit bg-neutral-50/20 backdrop-blur-md border-b border-neutral-200 overflow-hidden"
        >
          <div
            data-cursor-opacity="0.3"
            data-cursor-size="24"
            data-cursor-color="#2A4BCC"
            className="bg-white py-24 sm:py-32"
          >
            <div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8 z-[1000] relative bg-white">
              <p className="text-base/7 font-semibold text-blue-800 relative z-10">Previews</p>
              <h2
                id="features-heading"
                className="mt-2 text-4xl font-semibold tracking-tighter text-gray-950 sm:text-5xl relative z-10 text-balance"
              >
                Building your favorite language tools
              </h2>
              <ul
                role="list"
                data-cursor-opacity="1"
                data-cursor-size="340"
                className="mt-12 grid lg:p-2 z-10 grid-cols-1 lg:grid-cols-3 relative gap-4 bg-white overflow-hidden group"
              >
                <div className="h-1/2 w-1/4 bg-blue-700 rounded-full absolute top-1/5 left-1/4 mix-blend-color blur-2xl animate-[float-left-right_8s_ease-in-out_infinite] group-hover:-translate-y-full transition-transform z-100 pointer-events-none scale-200"></div>
                <div className="h-1/2 w-1/4 bg-sky-700 rounded-full absolute top-1/5 left-4/7 mix-blend-color blur-2xl animate-[float-right-left_8s_ease-in-out_infinite_2s] group-hover:-translate-y-full transition-transform z-100 pointer-events-none scale-200"></div>

                {previews.map(preview => (
                  <a href="/previews" key={preview.title} target="_blank">
                    <li
                      key={preview.title}
                      className="flex flex-col gap-2 border border-neutral-200 rounded-3xl p-2 relative group/item"
                      data-cursor-size="2"
                    >
                      <div className="p-4 pb-2 rounded-2xl bg-white border border-neutral-200">
                        <div className="flex flex-row gap-2 items-center justify-between pb-2">
                          <h3 className="text-lg font-medium tracking-[-0.03em] text-black w-full">
                            {preview.title}
                          </h3>

                          <span className="transition-all inline-flex items-center px-2 py-1.5 border text-sm leading-4 font-medium tracking-tight rounded-xl text-black focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500  sm:w-fit flex-row justify-between hover:shadow-sm group">
                            <div
                              className={`h-2 w-2 rounded-full relative transition-all mr-1`}
                              style={{
                                backgroundColor:
                                  preview.status === 'Available'
                                    ? '#3779B5'
                                    : preview.status === 'In Beta'
                                      ? '#154063'
                                      : 'black',
                              }}
                            ></div>
                            <span className="w-full sm:w-fit text-nowrap">{preview.status}</span>
                          </span>
                        </div>
                      </div>
                      <div
                        className=" rounded-2xl bg-white border border-neutral-200 aspect-square relative overflow-hidden"
                        data-cursor-size="320"
                      >
                        <div className="h-5/6 w-5/6 bg-sky-700 rounded-full absolute top-1/2 left-1/2 transition-transform blur-xl mix-blend-color scale-200 hidden group-hover/item:block z-10"></div>
                        <div className="h-5/6 w-5/6 bg-[#2A4BCC] rounded-full absolute -top-1/4 -left-1/4 transition-transform blur-xl  mix-blend-color scale-200 hidden group-hover/item:block z-10"></div>

                        <img
                          src={preview.image}
                          alt={preview.title}
                          className="w-full h-full object-cover"
                        />
                      </div>
                      <div
                        className="p-4 rounded-2xl bg-white border border-neutral-200 z-100 relative"
                        data-cursor-collision="true"
                      >
                        <p className="text-[0.87rem] text-neutral-600 text-">
                          {preview.description}
                        </p>
                      </div>
                    </li>
                  </a>
                ))}
              </ul>
            </div>
          </div>
        </section>
      </div>
    </div>
  );
}



================================================
FILE: components/sections/research.tsx
================================================
import React from 'react';
import Link from 'next/link';

export default function Research() {
  return (
    <div id="research" className="">
      <svg
        width="75"
        height="905"
        viewBox="0 0 75 905"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
        className="absolute top-4 left-0 z-[1] hidden 2xl:block"
      >
        <g clipPath="url(#clip0_3877_301)">
          <path
            d="M69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433C-69.6808 97.3525 69.9825 -0.460876 69.9963 96.9968C70.0013 132.346 70.0002 294.846 69.9986 452.469C70.0002 610.092 70.0014 772.592 69.9964 807.941Z"
            fill="#ffffff"
          />
          <path
            d="M69.9963 196.941C69.9963 360.607 70.0045 750.741 69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433M-69.8022 -0.0624878C-69.8022 -0.0201653 -69.8022 0.0220944 -69.8022 0.0643433M69.9964 707.997C69.9964 544.33 70.0044 154.197 69.9963 96.9968C69.9825 -0.460854 -69.6808 97.3525 -69.8022 0.0643433"
            stroke="#E5E5E5"
          />
        </g>
        <defs>
          <clipPath id="clip0_3877_301">
            <rect
              width="75.0001"
              height="905"
              fill="white"
              transform="translate(75 905) rotate(180)"
            />
          </clipPath>
        </defs>
      </svg>

      <svg
        width="75"
        height="905"
        viewBox="0 0 75 905"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
        className="absolute top-4 right-0 z-[1] rotate-180 hidden 2xl:block"
      >
        <g clipPath="url(#clip0_3877_301)">
          <path
            d="M69.9963 196.941C69.9963 360.607 70.0045 750.741 69.9964 807.941C69.9826 905.441 -69.8021 807.5 -69.8022 905L-69.8022 0.0643433M-69.8022 -0.0624878C-69.8022 -0.0201653 -69.8022 0.0220944 -69.8022 0.0643433M69.9964 707.997C69.9964 544.33 70.0044 154.197 69.9963 96.9968C69.9825 -0.460854 -69.6808 97.3525 -69.8022 0.0643433"
            stroke="#E5E5E5"
          />
        </g>
        <defs>
          <clipPath id="clip0_3877_301">
            <rect
              width="75.0001"
              height="905"
              fill="white"
              transform="translate(75 905) rotate(180)"
            />
          </clipPath>
        </defs>
      </svg>

      <div className="mx-auto">
        <div className="mx-auto absolute h-full flex justify-between z-[-1]"></div>

        <section
          aria-labelledby="features-heading"
          className="mx-auto w-full h-fit bg-neutral-50/20 backdrop-blur-md border-y border-neutral-200 overflow-hidden"
        >
          <div
            data-cursor-opacity="0.8"
            data-cursor-size="240"
            data-cursor-color="#2A4BCC"
            className="bg-white py-24 sm:py-32"
          >
            <div className="mx-auto max-w-2xl px-6 lg:max-w-7xl lg:px-8 z-[1000] relative">
              <p className="text-base/7 font-semibold text-blue-600 relative z-10">Research</p>
              <h2
                id="features-heading"
                className="mt-2 text-balance text-4xl font-semibold tracking-tighter text-gray-950 sm:text-5xl relative z-10"
              >
                Our newest talks and presentations
              </h2>
              <ul
                role="list"
                className="mt-12 grid grid-cols-1 gap-10 sm:gap-20 lg:grid-cols-6 lg:grid-rows-1 sm:p-2 z-10 relative`"
              >
                <li className="relative lg:col-span-3 group">
                  <Link href="/research">
                    <article className="relative flex h-fit flex-col inset-px ring-1 ring-black/10 rounded-3xl bg-neutral-50 shadow-sm">
                      <div className="relative p-2 rounded-[32px] bg-white border scale-110 shadow-xs">
                        <img
                          alt="Screenshot showing the massive library of content available to practice with"
                          src="/images/interspeech.png"
                          className="w-full aspect-video max-h-[318px] sm:max-h-[650px] object-top rounded-3xl border bg-white border-black/10"
                        />
                      </div>
                      <div className="p-5 pt-9">
                        <div className="flex items-center gap-2">
                          <div className="flex items-center gap-1 bg-white border border-black/10 rounded-xl p-2 pr-3 w-fit pl-3 sm:pl-2">
                            <svg
                              width="86"
                              height="86"
                              viewBox="0 0 86 86"
                              fill="none"
                              className="size-3 text-sky-600 mx-0.5 mr-1 group-hover:rotate-180 transition-transform ease-in-out duration-450 hidden sm:block"
                              xmlns="http://www.w3.org/2000/svg"
                            >
                              <path
                                d="M41.4672 1.19822C41.7127 0.0255133 44.2873 0.0255196 44.5328 1.19822C46.3436 9.84995 50.0055 22.4562 56.7746 29.2254C63.5438 35.9945 76.1501 39.6564 84.8018 41.4672C85.9745 41.7127 85.9745 44.2873 84.8018 44.5328C76.1501 46.3436 63.5438 50.0055 56.7746 56.7746C50.0055 63.5438 46.3436 76.1501 44.5328 84.8018C44.2873 85.9745 41.7127 85.9745 41.4672 84.8018C39.6564 76.1501 35.9945 63.5438 29.2254 56.7746C22.4562 50.0055 9.84994 46.3436 1.19822 44.5328C0.0255133 44.2873 0.0255196 41.7127 1.19822 41.4672C9.84995 39.6564 22.4562 35.9945 29.2254 29.2254C35.9945 22.4562 39.6564 9.84994 41.4672 1.19822Z"
                                fill="oklch(0.588 0.158 241.966)"
                              />
                            </svg>

                            <h3 className="text-sm/4 font-semibold tracking-tight bg-clip-text text-transparent bg-gradient-to-r from-sky-600 to-[#536AD4]">
                              Research Conference
                            </h3>
                          </div>
                          <div className="flex items-center gap-1 bg-white border border-black/10 rounded-xl p-2 pr-3 w-fit group pl-3 sm:pl-2">
                            <svg
                              width="86"
                              height="86"
                              viewBox="0 0 86 86"
                              fill="none"
                              className="size-3 text-emerald-600 mx-0.5 mr-1 rotate-45 group-hover:rotate-270 transition-transform ease-in-out duration-450 hidden sm:block"
                              xmlns="http://www.w3.org/2000/svg"
                            >
                              <path
                                d="M41.4672 1.19822C41.7127 0.0255133 44.2873 0.0255196 44.5328 1.19822C46.3436 9.84995 50.0055 22.4562 56.7746 29.2254C63.5438 35.9945 76.1501 39.6564 84.8018 41.4672C85.9745 41.7127 85.9745 44.2873 84.8018 44.5328C76.1501 46.3436 63.5438 50.0055 56.7746 56.7746C50.0055 63.5438 46.3436 76.1501 44.5328 84.8018C44.2873 85.9745 41.7127 85.9745 41.4672 84.8018C39.6564 76.1501 35.9945 63.5438 29.2254 56.7746C22.4562 50.0055 9.84994 46.3436 1.19822 44.5328C0.0255133 44.2873 0.0255196 41.7127 1.19822 41.4672C9.84995 39.6564 22.4562 35.9945 29.2254 29.2254C35.9945 22.4562 39.6564 9.84994 41.4672 1.19822Z"
                                fill="oklch(0.609 0.126 221.723)"
                              />
                            </svg>

                            <h3 className="text-sm/4 font-semibold tracking-tight bg-clip-text text-transparent bg-gradient-to-r from-cyan-600 to-sky-800">
                              August 2025
                            </h3>
                          </div>
                        </div>
                        <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                          Interspeech Conference Science Slam '25
                        </p>
                        <p className="mt-2 max-w-lg text-sm/6 text-gray-600 text-pretty">
                          We presented our work on making speech pathology more accessible, insights
                          and statistics into our latest phonetic model, and a demo of our
                          work-in-progress pronunciation platform.
                        </p>
                      </div>
                    </article>
                  </Link>
                </li>
                <li className="relative lg:col-span-3 group">
                  <Link href="/research">
                    <article className="relative flex h-fit flex-col inset-px ring-1 ring-black/10 rounded-3xl bg-neutral-50 shadow-sm">
                      <div className="relative p-2 rounded-[32px] bg-white border scale-110 shadow-xs">
                        <img
                          alt="Screenshot showing the massive library of content available to practice with"
                          src="/images/UofW.png"
                          className="w-full aspect-video max-h-[318px] sm:max-h-[650px] object-top rounded-3xl border bg-white border-black/10"
                        />
                      </div>
                      <div className="p-5 pt-9">
                        <div className="flex items-center gap-2">
                          <div className="flex items-center gap-1 bg-white border border-black/10 rounded-xl p-2 pr-3 w-fit pl-3 sm:pl-2">
                            <div className="flex items-center gap-2">
                              <svg
                                width="86"
                                height="86"
                                viewBox="0 0 86 86"
                                fill="none"
                                className="size-3 text-sky-600 mx-0.5 mr-1 group-hover:rotate-180 transition-transform ease-in-out duration-450 hidden sm:block"
                                xmlns="http://www.w3.org/2000/svg"
                              >
                                <path
                                  d="M41.4672 1.19822C41.7127 0.0255133 44.2873 0.0255196 44.5328 1.19822C46.3436 9.84995 50.0055 22.4562 56.7746 29.2254C63.5438 35.9945 76.1501 39.6564 84.8018 41.4672C85.9745 41.7127 85.9745 44.2873 84.8018 44.5328C76.1501 46.3436 63.5438 50.0055 56.7746 56.7746C50.0055 63.5438 46.3436 76.1501 44.5328 84.8018C44.2873 85.9745 41.7127 85.9745 41.4672 84.8018C39.6564 76.1501 35.9945 63.5438 29.2254 56.7746C22.4562 50.0055 9.84994 46.3436 1.19822 44.5328C0.0255133 44.2873 0.0255196 41.7127 1.19822 41.4672C9.84995 39.6564 22.4562 35.9945 29.2254 29.2254C35.9945 22.4562 39.6564 9.84994 41.4672 1.19822Z"
                                  fill="oklch(0.588 0.158 241.966)"
                                />
                              </svg>

                              <h3 className="text-sm/4 font-semibold tracking-tight bg-clip-text text-transparent bg-gradient-to-r from-sky-600 to-[#536AD4]">
                                Research Symposium
                              </h3>
                            </div>
                          </div>
                          <div className="flex items-center gap-1 bg-white border border-black/10 rounded-xl p-2 pr-3 w-fit group pl-3 sm:pl-2">
                            <svg
                              width="86"
                              height="86"
                              viewBox="0 0 86 86"
                              fill="none"
                              className="size-3 text-emerald-600 mx-0.5 mr-1 rotate-45 group-hover:rotate-270 transition-transform ease-in-out duration-450 hidden sm:block"
                              xmlns="http://www.w3.org/2000/svg"
                            >
                              <path
                                d="M41.4672 1.19822C41.7127 0.0255133 44.2873 0.0255196 44.5328 1.19822C46.3436 9.84995 50.0055 22.4562 56.7746 29.2254C63.5438 35.9945 76.1501 39.6564 84.8018 41.4672C85.9745 41.7127 85.9745 44.2873 84.8018 44.5328C76.1501 46.3436 63.5438 50.0055 56.7746 56.7746C50.0055 63.5438 46.3436 76.1501 44.5328 84.8018C44.2873 85.9745 41.7127 85.9745 41.4672 84.8018C39.6564 76.1501 35.9945 63.5438 29.2254 56.7746C22.4562 50.0055 9.84994 46.3436 1.19822 44.5328C0.0255133 44.2873 0.0255196 41.7127 1.19822 41.4672C9.84995 39.6564 22.4562 35.9945 29.2254 29.2254C35.9945 22.4562 39.6564 9.84994 41.4672 1.19822Z"
                                fill="oklch(0.609 0.126 221.723)"
                              />
                            </svg>

                            <h3 className="text-sm/4 font-semibold tracking-tight bg-clip-text text-transparent bg-gradient-to-r from-cyan-600 to-sky-800">
                              May 2025
                            </h3>
                          </div>
                        </div>
                        <p className="mt-2 text-lg font-medium tracking-tight text-gray-950">
                          University of Washington Research Symposium '25
                        </p>
                        <p className="mt-2 max-w-lg text-sm/6 text-gray-600 text-pretty">
                          We presented architectural challenges in building speech tools and models,
                          working with non-lab settings and real-time data, and our mission as a
                          research lab.
                        </p>
                      </div>
                    </article>
                  </Link>
                </li>
              </ul>
            </div>
          </div>
        </section>
      </div>
    </div>
  );
}



================================================
FILE: components/sidebar/app-sidebar.jsx
================================================
'use client';

import {
  ChevronLeft,
  ChevronRight,
  Clapperboard,
  Home,
  LifeBuoy,
  Send,
  Settings,
} from 'lucide-react';
import { motion, AnimatePresence, useReducedMotion } from 'framer-motion';
import { NavMain } from '@/components/sidebar/nav-main';
import { NavVideos } from '@/components/sidebar/nav-videos';
import { NavSecondary } from '@/components/sidebar/nav-secondary';
import { NavUser } from '@/components/sidebar/nav-user';
import { BetaCard } from '@/components/sidebar/beta-card';
import { Button } from '@/components/ui/base/button';
import { MotionConfig } from 'framer-motion';
import {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarHeader,
  SidebarItem,
  SidebarLabel,
  useSidebar,
} from '@/components/ui/sidebar';
import Link from 'next/link';
import { useEffect, useState, useCallback, useMemo, useRef } from 'react';
import { getUser } from '@/lib/auth-client';
import { useUserVideos } from '@/hooks/use-user-videos';
import { Badge } from '../ui/base/badge';

const NAV_MAIN = [
  {
    title: 'Home',
    url: '/dashboard',
    icon: Home,
  },
  {
    title: 'Settings',
    url: '/dashboard/settings',
    icon: Settings,
  },
];

const NAV_SECONDARY = [
  {
    title: 'Support',
    url: '#',
    icon: LifeBuoy,
  },
  {
    title: 'Feedback',
    url: '#',
    icon: Send,
  },
];

export function AppSidebar({ className }) {
  const shouldReduceMotion = useReducedMotion();
  const { open, onOpenChange } = useSidebar();
  const [isLoaded, setIsLoaded] = useState(false);
  const [userData, setUserData] = useState({
    name: 'Loading...',
    email: 'Loading...',
    image: '',
    isLoaded: false,
  });
  const [videosList, setVideosList] = useState([]);
  const { videos, mutate: refreshVideos } = useUserVideos();
  const isInitialLoad = useRef(true);

  const formattedVideos = useMemo(() => {
    return (videos || []).map(video => ({
      name: video.title || 'Untitled Video',
      id: video.id,
      icon: Clapperboard,
    }));
  }, [videos]);

  useEffect(() => {
    if (videos && videos.length > 0) {
      setVideosList(formattedVideos);
    }
  }, [formattedVideos, videos]);

  const loadUserData = useCallback(
    async (forceRefresh = false) => {
      try {
        const { user, error } = await getUser();
        if (error) throw error;

        setUserData(prevUserData => {
          console.log('prevUserData', prevUserData);
          console.log('user', user);
          if (
            !prevUserData.isLoaded ||
            prevUserData.email !== user.email ||
            prevUserData.image !== user.image
          ) {
            return {
              ...user,
              isLoaded: true,
            };
          }
          return prevUserData;
        });

        if (forceRefresh) {
          await refreshVideos();
        }

        setIsLoaded(true);
        return { user, videos: formattedVideos };
      } catch (error) {
        console.error('Error loading sidebar data:', error);
        return { user: userData, videos: [] };
      } finally {
        setIsLoaded(true);
      }
    },
    [refreshVideos],
  );

  useEffect(() => {
    const handleVideoUpdate = event => {
      if (window.sidebarUpdateTimeout) {
        clearTimeout(window.sidebarUpdateTimeout);
      }

      window.sidebarUpdateTimeout = setTimeout(() => {
        const videoId = event.detail?.videoId;
        const action = event.detail?.action;
        const forceRefresh = action === 'add';

        loadUserData(forceRefresh).then(result => {
          if (videoId) {
            setTimeout(() => {
              const videoElement = document.querySelector(`[data-video-id="${videoId}"]`);
              if (videoElement) {
                videoElement.classList.add('highlight-animation');
                setTimeout(() => videoElement.classList.remove('highlight-animation'), 2000);
              }
            }, 300);
          }
        });
      }, 300);
    };

    if (isInitialLoad.current) {
      loadUserData();
      isInitialLoad.current = false;
    }

    const events = ['koellabs:userUpdated'];

    events.forEach(event => {
      window.addEventListener(event, handleVideoUpdate);
    });

    return () => {
      events.forEach(event => {
        window.removeEventListener(event, handleVideoUpdate);
      });

      if (window.sidebarUpdateTimeout) {
        clearTimeout(window.sidebarUpdateTimeout);
      }
    };
  }, [loadUserData]);

  const toggleSidebar = useCallback(() => {
    onOpenChange(!open);
  }, [open, onOpenChange]);

  const LogoSVG = useMemo(
    () => (
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width="1451"
        height="1437"
        fill="none"
        viewBox="0 0 1451 1437"
        className="inline-block h-7 w-7 -mt-0.5"
      >
        <rect
          width="344.708"
          height="691.027"
          x="1126.33"
          y="622.281"
          fill="#154063"
          rx="172.354"
          transform="rotate(90 1126.33 622.281)"
        ></rect>
        <rect
          width="344.708"
          height="691.027"
          x="1096.52"
          y="1040.13"
          fill="#3779B5"
          rx="172.354"
          transform="rotate(135 1096.52 1040.13)"
        ></rect>
        <mask
          id="mask0_3672_386"
          width="692"
          height="345"
          x="435"
          y="622"
          maskUnits="userSpaceOnUse"
          style={{ maskType: 'alpha' }}
        >
          <rect
            width="344.708"
            height="691.027"
            x="1126.33"
            y="622.281"
            fill="#fff"
            rx="172.354"
            transform="rotate(90 1126.33 622.281)"
          ></rect>
        </mask>
        <g mask="url(#mask0_3672_386)">
          <rect
            width="344.708"
            height="691.027"
            x="1096.52"
            y="1040.13"
            fill="#122438"
            rx="172.354"
            transform="rotate(135 1096.52 1040.13)"
          ></rect>
        </g>
        <path
          fill="#000"
          d="M501.589 575.587c-89.244-33.112-171.24-236.2-167.598-246.017 3.642-9.816 198.261-110.275 287.504-77.164s134.749 132.3 101.637 221.544-132.3 134.748-221.543 101.637"
        ></path>
      </svg>
    ),
    [],
  );

  return (
    <Sidebar className={`${className} bg-white/80 backdrop-blur-md dark:bg-black/80`}>
      <MotionConfig reducedMotion="always">
        <SidebarHeader className="py-2.5 pr-3">
          <Link
            href="/"
            className="flex items-center gap-2 -mb-px mt-px font-semibold py-1 h-[38px]"
          >
            {LogoSVG}
            <AnimatePresence>
              {open && (
                <motion.span
                  initial={isLoaded ? { opacity: 0, width: 0 } : false}
                  animate={{ opacity: 1, width: 'auto' }}
                  exit={shouldReduceMotion ? false : { opacity: 0, width: 0 }}
                  transition={
                    shouldReduceMotion ? { duration: 0.0 } : { duration: 0.15, ease: 'easeInOut' }
                  }
                  className="tracking-tighter -ml-1.5 text-xl overflow-hidden whitespace-nowrap"
                >
                  Koel Labs
                  <Badge variant="outline" className="ml-1.5 tracking-tight -translate-y-[3px]">
                    Beta
                  </Badge>
                </motion.span>
              )}
            </AnimatePresence>
          </Link>
          <Button
            variant="outline"
            size="icon"
            onClick={toggleSidebar}
            className="ml-auto h-7 w-7 py-1"
          >
            {open ? <ChevronLeft className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
          </Button>
        </SidebarHeader>
        <SidebarContent>
          <SidebarItem>
            <SidebarLabel>{open && 'Platform'}</SidebarLabel>
            <NavMain items={NAV_MAIN} isCollapsed={!open} className={open ? '' : '-mb-3'} />
          </SidebarItem>
          {!open && <div className="h-[1px] bg-black/10 w-full"></div>}
          <SidebarItem>
            <SidebarLabel className="flex justify-between items-center">
              {open && 'Your Clips'}
            </SidebarLabel>
            <div data-sidebar-videos="true">
              <NavVideos
                videos={videosList}
                isCollapsed={!open}
                className={open ? '' : '-mb-3'}
                isLoading={!isLoaded}
              />
            </div>
          </SidebarItem>
          <SidebarItem className="mt-auto">
            <NavSecondary items={NAV_SECONDARY} isCollapsed={!open} />
          </SidebarItem>
          <AnimatePresence>
            {open && (
              <motion.div
                initial={isLoaded ? { opacity: 0, width: 0 } : false}
                animate={{ opacity: 1 }}
                exit={{ opacity: 0 }}
                transition={{ duration: 0.0, ease: 'easeInOut' }}
                className="flex flex-col gap-3"
              >
                <SidebarItem>
                  <BetaCard />
                </SidebarItem>
              </motion.div>
            )}
          </AnimatePresence>
        </SidebarContent>
        <SidebarFooter>
          <NavUser user={userData} isCollapsed={!open} isLoading={!isLoaded} />
        </SidebarFooter>
      </MotionConfig>
    </Sidebar>
  );
}



================================================
FILE: components/sidebar/beta-card.jsx
================================================
import { Star, Zap } from 'lucide-react';
import { Button } from '@/components/ui/base/button';
import { Card, CardContent, CardFooter } from '@/components/ui/base/card';
import { Badge } from '@/components/ui/base/badge';
// import @radix-ui/react-slider
import * as SliderPrimitive from '@radix-ui/react-slider';

export function BetaCard() {
  return (
    <Card className="rounded-xl text-xs shadow-none min-w-[233px] relative -mb-1">
      <CardContent className="flex flex-col items-start gap-2 p-4 relative">
        <div className="flex items-center tracking-tight w-full relative">
          {/* <svg
            xmlns="http://www.w3.org/2000/svg"
            width="100%"
            height="100%"
            fill="none"
            viewBox="0 0 1 100"
            className="absolute top-0 left-0 rounded-md w-full h-full"
          >
            <g filter="url(#filter0_f_2239_260)">
              <circle cx="30" cy="30" r="44" fill="#317EC5"></circle>
            </g>
            <defs>
              <filter
                id="filter0_f_2239_260"
                width="200"
                height="200"
                x="-0"
                y="-0"
                colorInterpolationFilters="sRGB"
                filterUnits="userSpaceOnUse"
              >
                <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
                <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend>
                <feGaussianBlur
                  result="effect1_foregroundBlur_2239_260"
                  stdDeviation="44.9"
                ></feGaussianBlur>
              </filter>
            </defs>
          </svg> */}
          <h3 className="font-medium text-sm tracking-tight">Welcome to the Beta!</h3>
          <Badge variant="outline" className="ml-auto">
            New
          </Badge>
        </div>
        <p className="text-muted-foreground">
          Please let us know if you have any feedback, questions, or issues.
        </p>
      </CardContent>
    </Card>
  );
}



================================================
FILE: components/sidebar/nav-main.jsx
================================================
import { memo } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { cn } from '@/lib/styles';
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/base/tooltip';

const NavItem = memo(({ item, isCollapsed, isActive }) => (
  <li>
    {isCollapsed ? (
      <TooltipProvider delayDuration={0}>
        <Tooltip>
          <TooltipTrigger asChild>
            <Link
              href={item.url}
              className={cn(
                'flex h-8 items-center gap-2 overflow-hidden rounded-md px-1.5 text-sm font-medium outline-hidden ring-ring transition-all hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 text-foreground',
                isActive ? 'bg-accent text-accent-foreground' : '',
                isCollapsed ? 'justify-center h-10 w-full px-0' : '',
              )}
            >
              <item.icon strokeWidth={2.2} className={`h-4 w-4 shrink-0${isCollapsed ? '' : ''}`} />
              {!isCollapsed && <div className="line-clamp-1">{item.title}</div>}
            </Link>
          </TooltipTrigger>
          {isCollapsed && <TooltipContent side="right">{item.title}</TooltipContent>}
        </Tooltip>
      </TooltipProvider>
    ) : (
      <Link
        href={item.url}
        className={cn(
          'flex h-8 items-center gap-2 overflow-hidden rounded-md px-1.5 text-sm font-medium outline-hidden ring-ring transition-all hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 text-foreground',
          isActive ? 'bg-accent text-accent-foreground' : '',
        )}
      >
        <item.icon strokeWidth={2.2} className={`h-4 w-4 shrink-0${isCollapsed ? '' : ''}`} />
        {!isCollapsed && <div className="line-clamp-1 tracking-[-0.015em]">{item.title}</div>}
      </Link>
    )}
  </li>
));

export const NavMain = memo(({ className, items, isCollapsed }) => {
  const url = usePathname();

  return (
    <ul className={cn('grid gap-0.5', isCollapsed ? '-mt-4' : '', className)}>
      {items.map(item => (
        <NavItem
          key={item.title}
          item={item}
          isCollapsed={isCollapsed}
          isActive={item.url === url}
        />
      ))}
    </ul>
  );
});

NavMain.displayName = 'NavMain';
NavItem.displayName = 'NavItem';



================================================
FILE: components/sidebar/nav-secondary.jsx
================================================
import Link from 'next/link';
import { cn } from '@/lib/styles';
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/base/tooltip';

export function NavSecondary({ className, items, isCollapsed }) {
  if (!items?.length) {
    return null;
  }

  return (
    <ul className={cn('grid gap-0.5', className)}>
      {items.map(item => (
        <li key={item.title}>
          {isCollapsed ? (
            <TooltipProvider delayDuration={0}>
              <Tooltip>
                <TooltipTrigger asChild>
                  <Link
                    href={item.url}
                    className={cn(
                      'flex h-7 items-center gap-2.5 overflow-hidden rounded-md px-1.5 text-xs ring-ring transition-all hover:bg-accent hover:text-accent-foreground focus-visible:outline-hidden focus-visible:ring-2',
                      'justify-center h-10',
                    )}
                  >
                    <item.icon className={cn('h-4 w-4 shrink-0 text-muted-foreground')} />
                  </Link>
                </TooltipTrigger>
                <TooltipContent side="right">{item.title}</TooltipContent>
              </Tooltip>
            </TooltipProvider>
          ) : (
            <Link
              href={item.url}
              className={cn(
                'flex h-7 items-center gap-2.5 overflow-hidden rounded-md px-1.5 text-xs ring-ring transition-all hover:bg-accent hover:text-accent-foreground focus-visible:outline-hidden focus-visible:ring-2',
              )}
            >
              <item.icon className={cn('h-4 w-4 shrink-0 translate-x-0.5 text-muted-foreground')} />
              <div className="line-clamp-1 grow overflow-hidden pr-6 font-medium text-muted-foreground">
                {item.title}
              </div>
            </Link>
          )}
        </li>
      ))}
    </ul>
  );
}



================================================
FILE: components/sidebar/nav-user.jsx
================================================
import {
  Bell,
  ChevronsUpDown,
  CreditCard,
  Laptop,
  LogOut,
  Moon,
  PanelsTopLeft,
  Sun,
  Trash2,
  RefreshCcw,
} from 'lucide-react';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/base/avatar';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuPortal,
  DropdownMenuSeparator,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
} from '@/components/ui/base/dropdown-menu';
import { authClient } from '@/lib/auth-client';
import { resetUserVideos } from '@/lib/videos';
import { useRouter } from 'next/navigation';
import { useTheme } from 'next-themes';
import { Skeleton } from '@/components/ui/base/skeleton';
import { useState } from 'react';
import { useToast } from '@/hooks/use-toast';

export function NavUser({ user = {}, isCollapsed, isLoading }) {
  const router = useRouter();
  const { setTheme } = useTheme();
  const { toast } = useToast();
  const [isResetting, setIsResetting] = useState(false);

  // Extract user properties with default values for safety
  const name = user?.name || 'User';
  const email = user?.email || '';
  const image = user?.image || '';

  const handleSignOut = async () => {
    await authClient.signOut({
      fetchOptions: {
        onSuccess: () => {
          router.push('/sign-in'); // redirect to sign-in page
        },
      },
    });
  };

  // Developer Only [TODO: remove this]
  const resetVideos = async () => {
    if (
      window.confirm(
        'Are you sure you want to reset your video history? This action cannot be undone.',
      )
    ) {
      setIsResetting(true);
      try {
        await resetUserVideos();
        toast({
          title: 'Success',
          description: 'Your video history has been reset.',
          variant: 'default',
        });

        // Dispatch event to update UI components
        window.dispatchEvent(
          new CustomEvent('koellabs:userVideosUpdated', {
            detail: { action: 'reset', timestamp: Date.now() },
            bubbles: true,
          }),
        );

        router.refresh();
      } catch (error) {
        toast({
          title: 'Error',
          description: error.message || 'Failed to reset video history.',
          variant: 'destructive',
        });
      } finally {
        setIsResetting(false);
      }
    }
  };

  if (isLoading) {
    return (
      <div className="flex items-center gap-2 px-2 py-1.5">
        <Skeleton className="h-7 w-7 rounded-md" />
        {!isCollapsed && (
          <div className="flex-1">
            <Skeleton className="h-3.5 w-24 mb-1" />
            <Skeleton className="h-3 w-32" />
          </div>
        )}
      </div>
    );
  }

  return (
    <DropdownMenu>
      <DropdownMenuTrigger className="w-full rounded-md outline-hidden ring-ring hover:bg-accent data-[state=open]:bg-accent">
        <div className="flex items-center gap-2 px-2 py-1.5 text-left text-sm transition-all">
          <Avatar className="h-7 w-7 rounded-md">
            <AvatarImage src={image} alt={name} className="animate-in fade-in-50 zoom-in-90" />
            <AvatarFallback className="rounded-sm border">
              {name.length > 1 ? name[0] + name[1] : 'U'}
            </AvatarFallback>
          </Avatar>
          {!isCollapsed && (
            <>
              <div className="grid flex-1 leading-none">
                <div className="font-medium line-clamp-1">
                  {name.length > 15 ? `${name.substring(0, 18)}...` : name}
                </div>
                <div className="overflow-hidden text-xs text-muted-foreground">
                  <div className="line-clamp-1">{email}</div>
                </div>
              </div>
              <ChevronsUpDown className="ml-auto mr-0.5 h-4 w-4 text-muted-foreground/50" />
            </>
          )}
        </div>
      </DropdownMenuTrigger>
      <DropdownMenuContent className="min-w-56 w-full" align="end" side="right" sideOffset={4}>
        <DropdownMenuLabel className="p-0 font-normal">
          <div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm transition-all">
            <Avatar className="h-7 w-7 rounded-md">
              <AvatarImage src={image} alt={name} />
              <AvatarFallback className="">
                {name.length > 1 ? name[0] + name[1] : 'U'}
              </AvatarFallback>
            </Avatar>
            <div className="grid flex-1">
              <div className="font-medium">{name}</div>
              <div className="overflow-hidden text-xs text-muted-foreground">
                <div className="line-clamp-1">{email}</div>
              </div>
            </div>
          </div>
        </DropdownMenuLabel>
        <DropdownMenuSeparator />
        <DropdownMenuGroup>
          <DropdownMenuSub>
            <DropdownMenuSubTrigger className="gap-2">
              <PanelsTopLeft className="h-4 w-4 text-muted-foreground" />
              Theme
            </DropdownMenuSubTrigger>
            <DropdownMenuPortal>
              <DropdownMenuSubContent>
                <DropdownMenuItem onClick={() => setTheme('system')} className="gap-2">
                  <Laptop className="h-4 w-4 text-muted-foreground" />
                  System
                </DropdownMenuItem>
                <DropdownMenuItem onClick={() => setTheme('light')} className="gap-2">
                  <Sun className="h-4 w-4 text-muted-foreground" />
                  Light
                </DropdownMenuItem>
                <DropdownMenuItem onClick={() => setTheme('dark')} className="gap-2">
                  <Moon className="h-4 w-4 text-muted-foreground" />
                  Dark
                </DropdownMenuItem>
              </DropdownMenuSubContent>
            </DropdownMenuPortal>
          </DropdownMenuSub>

          <DropdownMenuItem className="gap-2">
            <CreditCard className="h-4 w-4 text-muted-foreground" />
            Billing
          </DropdownMenuItem>
          <DropdownMenuItem className="gap-2">
            <Bell className="h-4 w-4 text-muted-foreground" />
            Notifications
          </DropdownMenuItem>
        </DropdownMenuGroup>
        <DropdownMenuSeparator />
        <DropdownMenuItem
          className="gap-2 text-amber-600 focus:text-amber-700"
          onClick={resetVideos}
          disabled={isResetting}
        >
          {isResetting ? (
            <RefreshCcw className="h-4 w-4 text-amber-600 animate-spin" />
          ) : (
            <Trash2 className="h-4 w-4 text-amber-600" />
          )}
          {isResetting ? 'Resetting...' : 'Reset Video History'}
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem className="gap-2 text-red-600 focus:text-red-700" onClick={handleSignOut}>
          <LogOut className="h-4 w-4 text-red-600" />
          Log out
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}



================================================
FILE: components/sidebar/nav-videos.jsx
================================================
import Link from 'next/link';
import { MoreHorizontal, PlusSquare, PencilLine, Trash2, RotateCcw, Clock } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { cn } from '@/lib/styles';
import { Button } from '@/components/ui/base/button';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuLabel,
  DropdownMenuTrigger,
} from '@/components/ui/base/dropdown-menu';
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/base/tooltip';
import { usePathname } from 'next/navigation';
import { Badge } from '../ui/base/badge';
import { Card, CardContent } from '@/components/ui/base/card';

export function NavVideos({ videos, className, isCollapsed, isLoading = false }) {
  const url = usePathname();

  // Render skeleton loaders for the sidebar
  const renderSkeletons = () => {
    return Array(3)
      .fill(0)
      .map((_, index) => (
        <li
          key={`skeleton-${index}`}
          className="has-data-[state=open]:bg-accent has-data-[state=open]:text-accent-foreground group relative rounded-md"
        >
          {isCollapsed ? (
            <div className="flex items-center justify-center h-10">
              <div className="h-4 w-4 rounded-full bg-neutral-100 dark:bg-neutral-800 animate-pulse"></div>
            </div>
          ) : (
            <div className="flex h-6 items-center gap-2.5">
              <div className="h-5 bg-neutral-100 dark:bg-neutral-800 rounded w-full animate-pulse"></div>
            </div>
          )}
        </li>
      ));
  };

  // Render empty state with call to action
  const renderEmptyState = () => {
    if (isCollapsed) {
      // For collapsed sidebar, just show a subtle indicator
      return (
        <li className="text-center py-2 opacity-70">
          <TooltipProvider delayDuration={0}>
            <Tooltip>
              <TooltipTrigger asChild>
                <div className="flex justify-center">
                  <Clock className="h-4 w-4 text-muted-foreground" />
                </div>
              </TooltipTrigger>
              <TooltipContent side="right">No practice history yet</TooltipContent>
            </Tooltip>
          </TooltipProvider>
        </li>
      );
    }

    return (
      <Card className="rounded-xl text-xs min-w-[233px] relative border-dashed border-neutral-200 dark:border-neutral-800 shadow-none">
        <CardContent className="flex flex-col items-start gap-2 p-4 relative">
          <div className="flex items-center tracking-tight w-full relative justify-between">
            <h3 className="font-medium tracking-tight text-sm">No Practice History</h3>
            <Clock className="h-4 w-4" />
          </div>
          <p className="text-muted-foreground">
            Start practicing with any clip from the home page to build history.
          </p>
        </CardContent>
      </Card>
    );
  };

  return (
    <ul
      className={cn('grid gap-0.5', isCollapsed ? '-mt-3' : '', className)}
      data-sidebar-videos-list
    >
      {isLoading
        ? renderSkeletons()
        : videos.length > 0
          ? videos.map(item => (
              <li
                key={item.name}
                className="has-data-[state=open]:bg-accent has-data-[state=open]:text-accent-foreground group relative rounded-md hover:bg-accent hover:text-accent-foreground"
                data-video-id={item.id}
                data-video-item
              >
                {isCollapsed ? (
                  <TooltipProvider delayDuration={0}>
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Link
                          prefetch
                          href={'/dashboard/' + item.id}
                          className={cn(
                            'flex h-7 items-center gap-2.5 overflow-hidden rounded-md px-1.5 text-xs outline-hidden ring-ring transition-all hover:bg-accent hover:text-accent-foreground focus-visible:ring-2',
                            'justify-center h-10',
                            url.includes(item.id) ? 'bg-accent text-accent-foreground' : '',
                          )}
                        >
                          <item.icon className={cn('shrink-0 text-muted-foreground h-4 w-4')} />
                        </Link>
                      </TooltipTrigger>
                      <TooltipContent side="right">{item.name}</TooltipContent>
                    </Tooltip>
                  </TooltipProvider>
                ) : (
                  <>
                    <Link
                      prefetch
                      href={'/dashboard/' + item.id}
                      className={cn(
                        'flex h-7 items-center gap-2.5 overflow-hidden rounded-md px-1.5 text-xs outline-hidden ring-ring transition-all hover:bg-accent hover:text-accent-foreground focus-visible:ring-2',
                        url.includes(item.id) ? 'bg-accent text-accent-foreground' : '',
                      )}
                    >
                      <item.icon
                        className={cn(
                          'shrink-0 text-foreground h-4 w-4',
                          'translate-x-0.5 h-4 w-4',
                        )}
                      />
                      <div className="line-clamp-1 text-foreground tracking-[-0.015em] grow overflow-hidden pr-6 font-medium">
                        {item.name}
                      </div>
                    </Link>
                    <DropdownMenu>
                      <DropdownMenuTrigger asChild>
                        <Button
                          variant="ghost"
                          className="peer absolute right-1 top-0.5 h-6 w-6 shrink-0 rounded-md bg-accent p-0 text-accent-foreground opacity-0 ring-ring transition-all focus-visible:ring-2 group-focus-within:opacity-100 group-hover:opacity-100 data-[state=open]:bg-accent data-[state=open]:opacity-100"
                        >
                          <MoreHorizontal className="h-4 w-4 text-muted-foreground" />
                          <span className="sr-only">Toggle</span>
                        </Button>
                      </DropdownMenuTrigger>
                      <DropdownMenuContent side="right" className=" rounded-lg w-44">
                        <DropdownMenuItem>
                          <div className="flex items-center justify-center mr-2" aria-hidden="true">
                            <PencilLine size={16} strokeWidth={2} className="opacity-60" />
                          </div>
                          <div className="mr-1">
                            <div className="text-sm font-normal text-foreground/90">
                              Change Icon
                            </div>
                          </div>
                        </DropdownMenuItem>
                        <DropdownMenuSeparator />
                        <DropdownMenuItem>
                          <div
                            className="flex items-center justify-center mr-2 group"
                            aria-hidden="true"
                          >
                            <RotateCcw size={16} strokeWidth={2.2} className="text-red-500" />
                          </div>
                          <div>
                            <div className="text-sm font-normal text-red-500">Reset Progress</div>
                          </div>
                        </DropdownMenuItem>
                        <DropdownMenuItem>
                          <div className="flex items-center justify-center mr-2" aria-hidden="true">
                            <Trash2 size={16} strokeWidth={2} className=" text-red-500" />
                          </div>
                          <div>
                            <div className="text-sm font-normal text-red-500">Delete Clip</div>
                          </div>
                        </DropdownMenuItem>
                      </DropdownMenuContent>
                    </DropdownMenu>
                  </>
                )}
              </li>
            ))
          : renderEmptyState()}
    </ul>
  );
}



================================================
FILE: components/sidebar/streak-card.jsx
================================================
import { Card, CardContent } from '@/components/ui/base/card';
import { Badge } from '@/components/ui/base/badge';
import { Database, Flame } from 'lucide-react';
import { Progress } from '@radix-ui/react-progress';

// dummy user data for streak card

const user = {
  name: 'John Doe',
  streak: 3,
};

export function StreakCard() {
  return (
    <Card className="rounded-md text-xs shadow-xs">
      <CardContent className="flex items-start gap-2.5 p-2.5">
        <div className="grid flex-1 gap-1">
          <p className="font-medium">Streak</p>
        </div>
        <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-orange-100 relative overflow-hidden">
          <p className="text-black absolute z-10 text-bold text-3xl">{user.streak}</p>
          <Flame
            className="absolute w-full h-full text-orange-600 scale-125 translate-y-2 "
            fill="#ea580c"
          />
        </div>
      </CardContent>
    </Card>
  );
}



================================================
FILE: components/ui/audio-playback.tsx
================================================
'use client';

import React, { useState, useRef, useEffect, useCallback } from 'react';
import { Button } from '@/components/ui/base/button';
import { Play, Pause } from 'lucide-react';
import WaveSurfer from '@wavesurfer/react';

interface AudioPlaybackProps {
  audioBlob?: Blob;
  onPlay?: () => void;
  className?: string;
}

export function AudioPlayback({ audioBlob, onPlay, className = '' }: AudioPlaybackProps) {
  const [isPlaying, setIsPlaying] = useState(false);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [wavesurfer, setWavesurfer] = useState<any>(null);
  const containerRef = useRef<HTMLDivElement>(null);

  const onReady = useCallback((ws: any) => {
    setWavesurfer(ws);
    setIsPlaying(false);
    setDuration(ws.getDuration());
  }, []);

  const handlePlay = useCallback(() => setIsPlaying(true), []);
  const handlePause = useCallback(() => setIsPlaying(false), []);

  const handleTimeUpdate = useCallback((currentTime: number) => {
    setCurrentTime(currentTime);
  }, []);

  useEffect(() => {
    if (audioBlob && wavesurfer) {
      const audioUrl = URL.createObjectURL(audioBlob);
      wavesurfer.load(audioUrl);

      return () => {
        URL.revokeObjectURL(audioUrl);
      };
    }
  }, [audioBlob, wavesurfer]);

  const handlePlayPause = async () => {
    if (wavesurfer) {
      wavesurfer.playPause();
    } else if (onPlay) {
      // Fallback to external play function if no wavesurfer instance
      onPlay();
    }
  };

  const formatTime = (time: number) => {
    if (isNaN(time)) return '0:00';
    const minutes = Math.floor(time / 60);
    const seconds = Math.floor(time % 60);
    return `${minutes}:${seconds.toString().padStart(2, '0')}`;
  };

  return (
    <div className={`flex items-center gap-3 p-3 border border-dashed rounded-2xl ${className}`}>
      <Button
        size="sm"
        disabled={!audioBlob}
        className="h-7 w-7 rounded-full text-white p-0 disabled:opacity-50 disabled:cursor-not-allowed"
        onClick={handlePlayPause}
      >
        {isPlaying ? (
          <Pause className="h-3 w-3" fill="currentColor" />
        ) : (
          <Play className="h-3 w-3" fill="currentColor" />
        )}
      </Button>

      {/* Waveform visualization */}
      <div className="flex-1 flex items-center h-8" ref={containerRef}>
        {audioBlob ? (
          <WaveSurfer
            height={32}
            waveColor="rgb(163, 163, 163)"
            progressColor="rgb(115, 115, 115)"
            cursorColor="rgb(59, 130, 246)"
            barWidth={2}
            barGap={1}
            barRadius={2}
            onReady={onReady}
            onPlay={handlePlay}
            onPause={handlePause}
            // onTimeupdate={handleTimeUpdate}
            normalize={true}
            backend="WebAudio"
            mediaControls={false}
          />
        ) : (
          // Fallback static visualization
          <div className="flex items-center gap-0.5 h-8 w-full">
            <span className="text-sm text-neutral-500 dark:text-neutral-400 open-runde-medium tracking-tight">
              {audioBlob === undefined ? 'No audio blob provided' : 'Loading audio...'}
            </span>
          </div>
        )}
      </div>

      <div className="text-sm font-mono text-neutral-600 dark:text-neutral-400 open-runde-medium tracking-tight">
        {formatTime(currentTime)} / {formatTime(duration)}
      </div>
    </div>
  );
}



================================================
FILE: components/ui/calendar-rac.tsx
================================================
'use client';

import { ComponentProps } from 'react';
import { getLocalTimeZone, today } from '@internationalized/date';
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
import {
  Button,
  CalendarCell as CalendarCellRac,
  CalendarGridBody as CalendarGridBodyRac,
  CalendarGridHeader as CalendarGridHeaderRac,
  CalendarGrid as CalendarGridRac,
  CalendarHeaderCell as CalendarHeaderCellRac,
  Calendar as CalendarRac,
  composeRenderProps,
  Heading as HeadingRac,
  RangeCalendar as RangeCalendarRac,
} from 'react-aria-components';

import { cn } from '@/lib/styles';

interface BaseCalendarProps {
  className?: string;
}

type CalendarProps = ComponentProps<typeof CalendarRac> & BaseCalendarProps;
type RangeCalendarProps = ComponentProps<typeof RangeCalendarRac> & BaseCalendarProps;

function CalendarHeader() {
  return (
    <header className="flex w-full items-center gap-1 pb-1">
      <Button
        slot="previous"
        className="text-muted-foreground/80 hover:bg-accent hover:text-foreground focus-visible:ring-ring/50 flex size-9 items-center justify-center rounded-md transition-[color,box-shadow] outline-none focus-visible:ring-[3px]"
      >
        <ChevronLeftIcon size={16} />
      </Button>
      <HeadingRac className="grow text-center text-sm font-medium" />
      <Button
        slot="next"
        className="text-muted-foreground/80 hover:bg-accent hover:text-foreground focus-visible:ring-ring/50 flex size-9 items-center justify-center rounded-md transition-[color,box-shadow] outline-none focus-visible:ring-[3px]"
      >
        <ChevronRightIcon size={16} />
      </Button>
    </header>
  );
}

function CalendarGridComponent({ isRange = false }: { isRange?: boolean }) {
  const now = today(getLocalTimeZone());

  return (
    <CalendarGridRac>
      <CalendarGridHeaderRac>
        {day => (
          <CalendarHeaderCellRac className="text-muted-foreground/80 size-9 rounded-md p-0 text-xs font-medium">
            {day}
          </CalendarHeaderCellRac>
        )}
      </CalendarGridHeaderRac>
      <CalendarGridBodyRac className="[&_td]:px-0 [&_td]:py-px">
        {date => (
          <CalendarCellRac
            date={date}
            className={cn(
              'text-foreground data-hovered:bg-accent data-selected:bg-primary data-hovered:text-foreground data-selected:text-primary-foreground data-focus-visible:ring-ring/50 relative flex size-9 items-center justify-center rounded-md p-0 text-sm font-normal whitespace-nowrap [transition-property:color,background-color,border-radius,box-shadow] duration-150 outline-none data-disabled:pointer-events-none data-disabled:opacity-30 data-focus-visible:z-10 data-focus-visible:ring-[3px] data-unavailable:pointer-events-none data-unavailable:line-through data-unavailable:opacity-30',
              // Range-specific styles
              isRange &&
                'data-selected:bg-accent data-selected:text-foreground data-invalid:data-selection-end:bg-destructive data-invalid:data-selection-start:bg-destructive data-selection-end:bg-primary data-selection-start:bg-primary data-selection-end:text-primary-foreground data-selection-start:text-primary-foreground data-invalid:bg-red-100 data-selected:rounded-none data-selection-end:rounded-e-md data-invalid:data-selection-end:text-white data-selection-start:rounded-s-md data-invalid:data-selection-start:text-white',
              // Today indicator styles
              date.compare(now) === 0 &&
                cn(
                  'after:bg-primary after:pointer-events-none after:absolute after:start-1/2 after:bottom-1 after:z-10 after:size-[3px] after:-translate-x-1/2 after:rounded-full',
                  isRange
                    ? 'data-selection-end:after:bg-background data-selection-start:after:bg-background'
                    : 'data-selected:after:bg-background',
                ),
            )}
          />
        )}
      </CalendarGridBodyRac>
    </CalendarGridRac>
  );
}

function Calendar({ className, ...props }: CalendarProps) {
  return (
    <CalendarRac
      {...props}
      className={composeRenderProps(className, className => cn('w-fit', className))}
    >
      <CalendarHeader />
      <CalendarGridComponent />
    </CalendarRac>
  );
}

function RangeCalendar({ className, ...props }: RangeCalendarProps) {
  return (
    <RangeCalendarRac
      {...props}
      className={composeRenderProps(className, className => cn('w-fit', className))}
    >
      <CalendarHeader />
      <CalendarGridComponent isRange />
    </RangeCalendarRac>
  );
}

export { Calendar, RangeCalendar };



================================================
FILE: components/ui/code-block.tsx
================================================
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism';
import { cn } from '@/lib/styles';

interface CodeBlockProps {
  code: string;
  className?: string;
}

export function CodeBlock({ code, className }: CodeBlockProps) {
  return (
    <div className={cn('overflow-hidden rounded-lg border bg-neutral-50', className)}>
      <SyntaxHighlighter
        language="python"
        style={oneLight}
        customStyle={{
          margin: 0,
          background: 'transparent',
          padding: '1rem',
          fontSize: '0.875rem', // text-sm
        }}
        codeTagProps={{
          style: {
            fontSize: 'inherit',
            background: 'transparent',
          },
        }}
      >
        {code}
      </SyntaxHighlighter>
    </div>
  );
}



================================================
FILE: components/ui/dashboard-stat-chart.jsx
================================================
'use client';

import { Area, AreaChart, XAxis, YAxis } from 'recharts';

import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from '@/components/ui/base/card';
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/base/chart';

export default function Chart() {
  return (
    <Card className="max-w-xs">
      <CardHeader className="space-y-0 pb-0">
        <CardDescription>Time in Bed</CardDescription>
        <CardTitle className="flex items-baseline gap-1 text-4xl tabular-nums">
          8
          <span className="font-sans text-sm font-normal tracking-normal text-muted-foreground">
            hr
          </span>
          35
          <span className="font-sans text-sm font-normal tracking-normal text-muted-foreground">
            min
          </span>
        </CardTitle>
      </CardHeader>
      <CardContent className="p-0">
        <ChartContainer
          config={{
            time: {
              label: 'Time',
              color: 'hsl(var(--chart-2))',
            },
          }}
        >
          <AreaChart
            accessibilityLayer
            data={[
              {
                date: '2024-01-01',
                time: 8.5,
              },
              {
                date: '2024-01-02',
                time: 7.2,
              },
              {
                date: '2024-01-03',
                time: 8.1,
              },
              {
                date: '2024-01-04',
                time: 6.2,
              },
              {
                date: '2024-01-05',
                time: 5.2,
              },
              {
                date: '2024-01-06',
                time: 8.1,
              },
              {
                date: '2024-01-07',
                time: 7.0,
              },
            ]}
            margin={{
              left: 0,
              right: 0,
              top: 0,
              bottom: 0,
            }}
          >
            <XAxis dataKey="date" hide />
            <YAxis domain={['dataMin - 5', 'dataMax + 2']} hide />
            <defs>
              <linearGradient id="fillTime" x1="0" y1="0" x2="0" y2="1">
                <stop offset="5%" stopColor="var(--color-time)" stopOpacity={0.8} />
                <stop offset="95%" stopColor="var(--color-time)" stopOpacity={0.1} />
              </linearGradient>
            </defs>
            <Area
              dataKey="time"
              type="natural"
              fill="url(#fillTime)"
              fillOpacity={0.4}
              stroke="var(--color-time)"
            />
            <ChartTooltip
              cursor={false}
              content={<ChartTooltipContent hideLabel />}
              formatter={value => (
                <div className="flex min-w-[120px] items-center text-xs text-muted-foreground">
                  Time in bed
                  <div className="ml-auto flex items-baseline gap-0.5 font-mono font-medium tabular-nums text-foreground">
                    {value}
                    <span className="font-normal text-muted-foreground">hr</span>
                  </div>
                </div>
              )}
            />
          </AreaChart>
        </ChartContainer>
      </CardContent>
    </Card>
  );
}



================================================
FILE: components/ui/dashboard.jsx
================================================
import React from 'react';
import Link from 'next/link';
import {
  Bell,
  CircleUser,
  Home,
  LineChart,
  Menu,
  Package,
  Package2,
  Search,
  ShoppingCart,
  Users,
} from 'lucide-react';
import { Badge } from '@/components/ui/base/badge';
import { Button } from '@/components/ui/base/button';
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from '@/components/ui/base/card';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '@/components/ui/base/dropdown-menu';
import { Input } from '@/components/ui/base/input';
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/base/sheet';
export const description =
  'A products dashboard with a sidebar navigation and a main content area. The dashboard has a header with a search input and a user menu. The sidebar has a logo, navigation links, and a card with a call to action. The main content area shows an empty state with a call to action.';
export function Dashboard() {
  return (
    <div className="grid min-h-screen w-full md:grid-cols-[220px_1fr] lg:grid-cols-[280px_1fr] bg-muted/10">
      <div className="hidden bg-muted/10 md:block">
        <div className="flex h-full max-h-screen flex-col gap-2">
          <div className="flex h-14 items-center justify-between px-4 lg:h-[60px] lg:px-6">
            <Link href="/" className="flex items-center gap-2 font-semibold mt-1">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                width="870"
                height="870"
                fill="none"
                viewBox="0 0 870 870"
                className="inline-block h-8 w-8 -mt-0.5"
              >
                <rect
                  width="214"
                  height="429"
                  x="671.179"
                  y="403"
                  fill="url(#paint0_linear_1691_806)"
                  fillOpacity="0.6"
                  rx="107"
                  transform="rotate(90 671.179 403)"
                ></rect>
                <rect
                  width="214"
                  height="429"
                  x="652.67"
                  y="662.406"
                  fill="url(#paint1_linear_1691_806)"
                  fillOpacity="0.6"
                  rx="107"
                  transform="rotate(135 652.67 662.406)"
                ></rect>
                <rect
                  width="214"
                  height="429"
                  x="671.179"
                  y="403"
                  fill="url(#paint2_linear_1691_806)"
                  fillOpacity="0.6"
                  rx="107"
                  transform="rotate(90 671.179 403)"
                ></rect>
                <rect
                  width="214"
                  height="429"
                  x="652.67"
                  y="662.406"
                  fill="url(#paint3_linear_1691_806)"
                  fillOpacity="0.6"
                  rx="107"
                  transform="rotate(135 652.67 662.406)"
                ></rect>
                <rect
                  width="214"
                  height="429"
                  x="671.179"
                  y="403"
                  fill="url(#paint4_linear_1691_806)"
                  fillOpacity="0.6"
                  rx="107"
                  transform="rotate(90 671.179 403)"
                ></rect>
                <rect
                  width="214"
                  height="429"
                  x="652.67"
                  y="662.406"
                  fill="url(#paint5_linear_1691_806)"
                  fillOpacity="0.6"
                  rx="107"
                  transform="rotate(135 652.67 662.406)"
                ></rect>
                <path
                  fill="#000"
                  d="M283.332 374.002c-55.404-20.556-106.308-146.637-104.047-152.731 2.261-6.094 123.083-68.461 178.487-47.905 55.404 20.556 83.654 82.134 63.098 137.538-20.556 55.404-82.134 83.654-137.538 63.098z"
                ></path>
                <defs>
                  <linearGradient
                    id="paint0_linear_1691_806"
                    x1="778.179"
                    x2="778.179"
                    y1="403"
                    y2="832"
                    gradientUnits="userSpaceOnUse"
                  >
                    <stop stopColor="#317EC5"></stop>
                    <stop offset="1"></stop>
                  </linearGradient>
                  <linearGradient
                    id="paint1_linear_1691_806"
                    x1="759.67"
                    x2="759.67"
                    y1="662.406"
                    y2="1091.41"
                    gradientUnits="userSpaceOnUse"
                  >
                    <stop stopColor="#317EC5"></stop>
                    <stop offset="1"></stop>
                  </linearGradient>
                  <linearGradient
                    id="paint2_linear_1691_806"
                    x1="778.179"
                    x2="778.179"
                    y1="403"
                    y2="832"
                    gradientUnits="userSpaceOnUse"
                  >
                    <stop stopColor="#317EC5"></stop>
                    <stop offset="1"></stop>
                  </linearGradient>
                  <linearGradient
                    id="paint3_linear_1691_806"
                    x1="759.67"
                    x2="759.67"
                    y1="662.406"
                    y2="1091.41"
                    gradientUnits="userSpaceOnUse"
                  >
                    <stop stopColor="#317EC5"></stop>
                    <stop offset="1"></stop>
                  </linearGradient>
                  <linearGradient
                    id="paint4_linear_1691_806"
                    x1="778.179"
                    x2="778.179"
                    y1="403"
                    y2="832"
                    gradientUnits="userSpaceOnUse"
                  >
                    <stop stopColor="#317EC5"></stop>
                    <stop offset="1"></stop>
                  </linearGradient>
                  <linearGradient
                    id="paint5_linear_1691_806"
                    x1="759.67"
                    x2="759.67"
                    y1="662.406"
                    y2="1091.41"
                    gradientUnits="userSpaceOnUse"
                  >
                    <stop stopColor="#317EC5"></stop>
                    <stop offset="1"></stop>
                  </linearGradient>
                </defs>
              </svg>
              <span className="tracking-tighter -ml-1 text-2xl">Koel Labs</span>
            </Link>
            {/* <Button variant="outline" size="icon" className="ml-auto h-8 w-8">
              <Bell className="h-4 w-4" />
              <span className="sr-only">Toggle notifications</span>
            </Button> */}
          </div>
          <div className="flex-1">
            <nav className="grid items-start px-2 text-sm font-medium lg:px-4">
              <Link
                href="#"
                className="flex items-center gap-3 rounded-lg px-3 py-2 text-primary bg-muted transition-all hover:text-primary"
              >
                <Home className="h-4 w-4" />
                Home
              </Link>
              <Link
                href="#"
                className="flex items-center gap-3 rounded-lg px-3 py-2 text-muted-foreground transition-all hover:text-primary"
              ></Link>
              <Link
                href="#"
                className="flex items-center gap-3 rounded-lg text-muted-foreground px-3 py-2 transition-all hover:text-primary"
              >
                <Package className="h-4 w-4" />
                Products{' '}
              </Link>
              <Link
                href="#"
                className="flex items-center gap-3 rounded-lg px-3 py-2 text-muted-foreground transition-all hover:text-primary"
              >
                <Users className="h-4 w-4" />
                Customers
              </Link>
              <Link
                href="#"
                className="flex items-center gap-3 rounded-lg px-3 py-2 text-muted-foreground transition-all hover:text-primary"
              >
                <LineChart className="h-4 w-4" />
                Analytics
              </Link>
            </nav>
          </div>
          <div className="mt-auto p-4">
            <Card x-chunk="dashboard-02-chunk-0">
              <CardHeader className="p-2 pt-0 md:p-4">
                <CardTitle>
                  Unlock{' '}
                  <span className="text-transparent bg-clip-text bg-linear-to-br from-black to-sky-600">
                    Premium
                  </span>
                </CardTitle>
                <CardDescription>
                  Get access to all features and high limits with our plan designed for growth.
                </CardDescription>
              </CardHeader>
              <CardContent className="p-2 pt-0 md:p-4 md:pt-0">
                <Button
                  size="sm"
                  className="w-full border bg-linear-to-br border-double outline-white/50 outline outline-[0.1px] outline-offset-[-2px] border-black from-sky-800 to-blue-950 dark:outline-black/50 dark:from-sky-600 dark:to-blue-800 text-white"
                >
                  Upgrade
                </Button>
              </CardContent>
            </Card>
          </div>
        </div>
      </div>
      <div className="flex flex-col">
        <header className="flex h-16 items-center gap-4 bg-muted/10 px-4 md:h-4 lg:px-6">
          <Sheet>
            <SheetTrigger asChild>
              <Button variant="outline" size="icon" className="shrink-0 md:hidden">
                <Menu className="h-5 w-5" />
                <span className="sr-only">Toggle navigation menu</span>
              </Button>
            </SheetTrigger>
            <SheetContent side="left" className="flex flex-col">
              <nav className="grid gap-2 text-lg font-medium">
                <Link href="#" className="flex items-center gap-2 text-lg font-semibold">
                  <Package2 className="h-6 w-6" />
                  <span className="sr-only">Acme Inc</span>
                </Link>
                <Link
                  href="#"
                  className="mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 text-muted-foreground hover:text-foreground"
                >
                  <Home className="h-5 w-5" />
                  Dashboard
                </Link>
                <Link
                  href="#"
                  className="mx-[-0.65rem] flex items-center gap-4 rounded-xl bg-muted px-3 py-2 text-foreground hover:text-foreground"
                >
                  <ShoppingCart className="h-5 w-5" />
                  Orders
                  <Badge className="ml-auto flex h-6 w-6 shrink-0 items-center justify-center rounded-full">
                    6
                  </Badge>
                </Link>
                <Link
                  href="#"
                  className="mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 text-muted-foreground hover:text-foreground"
                >
                  <Package className="h-5 w-5" />
                  Products
                </Link>
                <Link
                  href="#"
                  className="mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 text-muted-foreground hover:text-foreground"
                >
                  <Users className="h-5 w-5" />
                  Customers
                </Link>
                <Link
                  href="#"
                  className="mx-[-0.65rem] flex items-center gap-4 rounded-xl px-3 py-2 text-muted-foreground hover:text-foreground"
                >
                  <LineChart className="h-5 w-5" />
                  Analytics
                </Link>
              </nav>
              <div className="mt-auto">
                <Card>
                  <CardHeader>
                    <CardTitle>Upgrade to Pro</CardTitle>
                    <CardDescription>
                      Unlock all features and get unlimited access to our support team.
                    </CardDescription>
                  </CardHeader>
                  <CardContent>
                    <Button size="sm" className="w-full">
                      Upgrade
                    </Button>
                  </CardContent>
                </Card>
              </div>
            </SheetContent>
          </Sheet>
        </header>
        <main className="flex flex-1 flex-col gap-4 p-4 lg:gap-6 lg:p-6 border md:rounded-tl-2xl  bg-white">
          <div className="flex items-center">
            <h1 className="text-lg font-semibold md:text-2xl tracking-tight ">Dashboard</h1>
          </div>
          <div
            className="flex flex-1 items-center justify-center rounded-lg border border-dashed shadow-xs"
            x-chunk="dashboard-02-chunk-1"
          >
            <div className="flex flex-col items-center gap-1 text-center">
              <h3 className="text-2xl font-bold tracking-tight">You have no products</h3>
              <p className="text-sm text-muted-foreground">
                You can start selling as soon as you add a product.
              </p>
              <Button className="mt-4">Add Product</Button>
            </div>
          </div>
        </main>
      </div>
    </div>
  );
}



================================================
FILE: components/ui/datefield-rac.tsx
================================================
'use client';

import {
  composeRenderProps,
  DateFieldProps,
  DateField as DateFieldRac,
  DateInputProps as DateInputPropsRac,
  DateInput as DateInputRac,
  DateSegmentProps,
  DateSegment as DateSegmentRac,
  DateValue as DateValueRac,
  TimeFieldProps,
  TimeField as TimeFieldRac,
  TimeValue as TimeValueRac,
} from 'react-aria-components';

import { cn } from '@/lib/styles';

function DateField<T extends DateValueRac>({ className, children, ...props }: DateFieldProps<T>) {
  return (
    <DateFieldRac className={composeRenderProps(className, className => cn(className))} {...props}>
      {children}
    </DateFieldRac>
  );
}

function TimeField<T extends TimeValueRac>({ className, children, ...props }: TimeFieldProps<T>) {
  return (
    <TimeFieldRac className={composeRenderProps(className, className => cn(className))} {...props}>
      {children}
    </TimeFieldRac>
  );
}

function DateSegment({ className, ...props }: DateSegmentProps) {
  return (
    <DateSegmentRac
      className={composeRenderProps(className, className =>
        cn(
          'text-foreground data-focused:bg-accent data-invalid:data-focused:bg-destructive data-focused:data-placeholder:text-foreground data-focused:text-foreground data-invalid:data-placeholder:text-destructive data-invalid:text-destructive data-placeholder:text-muted-foreground/70 data-[type=literal]:text-muted-foreground/70 inline rounded p-0.5 caret-transparent outline-hidden data-disabled:cursor-not-allowed data-disabled:opacity-50 data-invalid:data-focused:text-white data-invalid:data-focused:data-placeholder:text-white data-[type=literal]:px-0 ',
          className,
        ),
      )}
      {...props}
      data-invalid
    />
  );
}

const dateInputStyle =
  'relative inline-flex h-10 w-full items-center overflow-hidden whitespace-nowrap rounded-xl border border-input bg-background px-3 py-2 text-sm transition-[color,box-shadow] outline-none  ';

interface DateInputProps extends DateInputPropsRac {
  className?: string;
  unstyled?: boolean;
}

function DateInput({ className, unstyled = false, ...props }: Omit<DateInputProps, 'children'>) {
  return (
    <DateInputRac
      className={composeRenderProps(className, className =>
        cn(!unstyled && dateInputStyle, className),
      )}
      {...props}
    >
      {segment => <DateSegment segment={segment} />}
    </DateInputRac>
  );
}

export { DateField, DateInput, DateSegment, TimeField, dateInputStyle };
export type { DateInputProps };



================================================
FILE: components/ui/header.jsx
================================================
'use client';

import React, { createContext, useId, useState } from 'react';
import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu';
import { LayoutGroup, motion } from 'framer-motion';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { Menu, SquareChevronRight, SquareLibrary, SquareUserRound, X } from 'lucide-react';
import { Dialog, DialogPanel } from '@headlessui/react';
import { cn } from '@/lib/styles';
import { useScroll } from '@/lib/hooks/use-scroll';
import { Button } from '@/components/ui/base/button';

export const NavContext = createContext({ theme: 'light' });

function AboutContent() {
  return (
    <div className="w-[400px] transform-gpu bg-neutral-100 ring-1">
      <div className="-space-y-0.5 p-2 bg-white rounded-xl border-b">
        <Link
          href="/about"
          prefetch={true}
          className="group rounded-xl transition-colors p-2 hover:bg-neutral-50 flex items-center gap-2"
        >
          <div className="flex items-center gap-2 border p-3 rounded-lg text-neutral-600 justify-center size-12 bg-white">
            <SquareUserRound className="size-8" />
          </div>
          <div className="flex flex-col ml-1.5">
            <div className="font-medium text-sm text-neutral-900">Team</div>
            <div className="text-sm text-neutral-500 mt-0.5">Our mission, team, and values</div>
          </div>
        </Link>
        <Link
          href="/blog"
          prefetch={true}
          className="group rounded-xl transition-colors p-2 hover:bg-neutral-50 flex items-center gap-2"
        >
          <div className="flex items-center gap-2 border p-3 rounded-lg text-neutral-600 size-12 bg-white">
            <SquareLibrary className="size-8" />
          </div>
          <div className="flex flex-col ml-1.5">
            <div className="font-medium text-sm text-neutral-900">Blog</div>
            <div className="text-sm text-neutral-500 mt-0.5">Latest insights and updates</div>
          </div>
        </Link>
        <Link
          href="/contact"
          prefetch={true}
          className="group rounded-xl transition-colors p-2 hover:bg-neutral-50 flex items-center gap-2"
        >
          <div className="flex items-center gap-2 border p-3 rounded-lg text-neutral-600 size-12 bg-white">
            <SquareChevronRight className="size-8" />
          </div>
          <div className="flex flex-col ml-1.5">
            <div className="font-medium text-sm text-neutral-900">Contact</div>
            <div className="text-sm text-neutral-500 mt-0.5">Get in touch with our team</div>
          </div>
        </Link>
      </div>
      {/* <div className="h-fit w-full bg-neutral-100">
        <Link
          href="/blog"
          className="group rounded-xl transition-colors p-2 hover:bg-neutral-50 flex items-center gap-2"
        >
          <div className="flex items-center gap-2 border p-3 rounded-2xl text-neutral-600 w-full h-12 mb-0.5 bg-white">
            <p className="text-xs font-medium">We are building a pronunciation platform</p>
          </div>
        </Link>
      </div> */}
    </div>
  );
}

function AnimatedChevron(props) {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="9"
      height="9"
      fill="none"
      viewBox="0 0 9 9"
      {...props}
    >
      <path
        stroke="currentColor"
        strokeLinecap="round"
        strokeLinejoin="round"
        strokeWidth="1.5"
        d="M7.278 3.389 4.5 6.167 1.722 3.389"
        className="transition-transform duration-150 [transform-box:view-box] [transform-origin:center] [vector-effect:non-scaling-stroke] group-data-[state=open]/item:-scale-y-100"
      />
    </svg>
  );
}

function WithTrigger({ trigger, children }) {
  return trigger ? (
    <NavigationMenuPrimitive.Trigger asChild>{children}</NavigationMenuPrimitive.Trigger>
  ) : (
    children
  );
}

const navItems = [
  {
    name: 'Home',
    href: '/',
    segments: ['/'],
  },
  {
    name: 'Previews',
    href: '/previews',
    segments: ['/previews'],
  },
  {
    name: 'Research',
    href: '/research',
    segments: ['/research'],
  },
  {
    name: 'About',
    content: AboutContent,
    segments: ['/about', '/blog', '/contact'],
  },
];

function LogoComponent() {
  return (
    <Link href="/" className="text-2xl font-semibold tracking-[-0.04em] flex justify-center">
      <svg
        width="770"
        height="859"
        viewBox="0 0 770 859"
        fill="none"
        xmlns="http://www.w3.org/2000/svg"
        className="h-8 w-8 mr-1 -mt-px inline-block"
      >
        <rect
          x="686.844"
          y="353.266"
          width="263.361"
          height="527.953"
          rx="131.681"
          transform="rotate(90 686.844 353.266)"
          fill="#154063"
        />
        <rect
          x="664.07"
          y="672.516"
          width="263.361"
          height="527.953"
          rx="131.681"
          transform="rotate(135 664.07 672.516)"
          fill="#3779B5"
        />
        <mask
          id="mask0_3106_273"
          style={{ maskType: 'alpha' }}
          maskUnits="userSpaceOnUse"
          x="158"
          y="353"
          width="529"
          height="264"
        >
          <rect
            x="686.844"
            y="353.266"
            width="263.361"
            height="527.953"
            rx="131.681"
            transform="rotate(90 686.844 353.266)"
            fill="white"
          />
        </mask>
        <g mask="url(#mask0_3106_273)">
          <rect
            x="664.07"
            y="672.516"
            width="263.361"
            height="527.953"
            rx="131.681"
            transform="rotate(135 664.07 672.516)"
            fill="#122438"
          />
        </g>
        <path
          d="M209.534 317.593C141.351 292.296 78.7053 137.133 81.4879 129.634C84.2704 122.134 232.961 45.3817 301.145 70.6792C369.328 95.9767 404.094 171.758 378.796 239.941C353.499 308.125 277.718 342.891 209.534 317.593Z"
          fill="black"
        />
      </svg>
      Koel Labs
    </Link>
  );
}

export default function Header({ theme = 'light' }) {
  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
  const [hoveredItem, setHoveredItem] = useState(null);
  const [previousHoveredItem, setPreviousHoveredItem] = useState(null);
  const layoutGroupId = useId();
  const scrolled = useScroll(20);
  const pathname = usePathname();
  const currentPath = pathname === '/' ? '/' : `/${pathname?.split('/')?.[1] || ''}`;

  const activeItem = navItems.find(({ segments }) =>
    segments.some(segment => currentPath === segment),
  );

  const handleItemHover = itemName => {
    setPreviousHoveredItem(hoveredItem || activeItem?.name);
    setHoveredItem(itemName);
  };

  const handleItemLeave = () => {
    setPreviousHoveredItem(hoveredItem);
    setHoveredItem(null);
  };

  const backgroundItem = hoveredItem || activeItem?.name;

  return (
    <NavContext.Provider value={{ theme }}>
      <LayoutGroup id={layoutGroupId}>
        <div
          className={cn(
            'sticky inset-x-0 top-0 z-[60] w-full transition-all',
            theme === 'dark' && 'dark',
          )}
        >
          <div
            className={cn(
              'absolute inset-0 block border-b border-transparent transition-all duration-300 z-[50]',
              (scrolled || pathname === '/contact') &&
                'border-neutral-200 bg-white/80 backdrop-blur-xl transform-gpu translate-y-0 dark:border-white/10 dark:bg-black/80',
            )}
          />
          <div className="mx-auto w-full max-w-6xl px-6 lg:px-8 relative z-[50]">
            <div className="flex h-20 items-center justify-between z-[50] relative">
              <div className="grow basis-0">
                <div className="block w-fit py-2 pr-2">
                  <LogoComponent />
                </div>
              </div>

              <NavigationMenuPrimitive.Root
                delayDuration={150}
                className="relative hidden lg:block"
              >
                <NavigationMenuPrimitive.List className="group relative z-0 flex">
                  {navItems.map(({ name, href, segments, content: Content }, index) => {
                    const isActive = segments.some(segment => currentPath === segment);
                    const isHovered = hoveredItem === name;
                    const hasBackground = backgroundItem === name;
                    const currentIndex = index;
                    const previousIndex = previousHoveredItem
                      ? navItems.findIndex(item => item.name === previousHoveredItem)
                      : activeItem
                        ? navItems.findIndex(item => item.name === activeItem.name)
                        : currentIndex;

                    return (
                      <NavigationMenuPrimitive.Item
                        key={name}
                        className="relative active:scale-[97%]"
                      >
                        {hasBackground && (
                          <motion.div
                            layoutId="nav-bg"
                            className={cn(
                              'absolute inset-0 rounded-xl bg-neutral-200/30 opacity-50 ',
                            )}
                            initial={{
                              opacity: 1,
                              scale: 1,
                              x:
                                previousIndex !== currentIndex
                                  ? previousIndex > currentIndex
                                    ? 16
                                    : -16
                                  : 0,
                              y: isHovered ? -2 : 0,
                            }}
                            animate={{
                              opacity: 1,
                              scale: 1,
                              x: 0,
                              y: 0,
                            }}
                            exit={{
                              x:
                                previousIndex !== currentIndex
                                  ? previousIndex < currentIndex
                                    ? 16
                                    : -16
                                  : 0,
                              y: 2,
                            }}
                            transition={{
                              type: 'spring',
                              bounce: 0.15,
                              duration: 0.5,
                            }}
                          />
                        )}

                        <WithTrigger trigger={!!Content}>
                          {href !== undefined ? (
                            <Link
                              href={href}
                              className="relative z-10 group/item flex items-center px-4 py-2 text-sm rounded-xl font-base"
                              onMouseEnter={() => handleItemHover(name)}
                              onMouseLeave={handleItemLeave}
                            >
                              {name}
                            </Link>
                          ) : (
                            <button
                              className="relative z-10 group/item flex items-center px-4 py-2 text-sm rounded-xl font-base"
                              onMouseEnter={() => handleItemHover(name)}
                              onMouseLeave={handleItemLeave}
                            >
                              {name}
                              <AnimatedChevron className="ml-1.5 size-2.5 text-neutral-700" />
                            </button>
                          )}
                        </WithTrigger>

                        {Content && (
                          <NavigationMenuPrimitive.Content className="data-[motion=from-start]:animate-enter-from-left data-[motion=from-end]:animate-enter-from-right data-[motion=to-start]:animate-exit-to-left data-[motion=to-end]:animate-exit-to-right absolute left-0 top-0">
                            <Content />
                          </NavigationMenuPrimitive.Content>
                        )}
                      </NavigationMenuPrimitive.Item>
                    );
                  })}
                </NavigationMenuPrimitive.List>

                <div className="absolute left-1/2 top-full mt-3 -translate-x-1/2">
                  <NavigationMenuPrimitive.Viewport
                    className={cn(
                      'nav-viewport relative flex justify-start overflow-hidden rounded-[20px] border border-neutral-200 bg-white shadow-lg dark:border-white/[0.15] dark:bg-black',
                      'transform-gpu will-change-[transform,width,height]',
                      'data-[state=closed]:animate-scale-out-content data-[state=open]:animate-scale-in-content',
                      'transition-[width,height] duration-300',
                      'h-[var(--radix-navigation-menu-viewport-height)] w-[var(--radix-navigation-menu-viewport-width)]',
                    )}
                  />
                </div>
              </NavigationMenuPrimitive.Root>

              <div className="flex lg:hidden">
                <button
                  type="button"
                  onClick={() => setMobileMenuOpen(true)}
                  className="-m-2.5 inline-flex items-center justify-center rounded-md p-2.5 text-gray-700"
                >
                  <span className="sr-only">Open main menu</span>
                  <Menu aria-hidden="true" className="size-6" />
                </button>
              </div>
            </div>
          </div>
        </div>
      </LayoutGroup>

      <Dialog open={mobileMenuOpen} onClose={setMobileMenuOpen} className="lg:hidden">
        <div className="fixed inset-0" />
        <DialogPanel className="fixed inset-y-0 right-0 z-[100000] w-full overflow-y-auto bg-white px-6 py-6 sm:max-w-sm sm:ring-1 sm:ring-gray-900/10">
          <div className="flex items-center justify-between">
            <span className="text-2xl font-semibold tracking-[-0.04em] flex justify-center items-center gap-2">
              <LogoComponent />
              <span className="md:block hidden">Koel Labs</span>
            </span>
            <button
              type="button"
              onClick={() => setMobileMenuOpen(false)}
              className="-m-2.5 rounded-md p-2.5 text-gray-700"
            >
              <span className="sr-only">Close menu</span>
              <X aria-hidden="true" className="size-6" />
            </button>
          </div>
          <div className="mt-6 flow-root">
            <div className="-my-6 divide-y divide-gray-500/10">
              <div className="space-y-2 py-6">
                <ul className="flex flex-col gap-y-2">
                  {navItems.map(({ href, name, content, segments }) => {
                    if (content) {
                      return (
                        <div key={name}>
                          <Link
                            className={
                              currentPath === '/about'
                                ? 'text-black'
                                : 'text-neutral-500 hover:text-neutral-700'
                            }
                            href="/about"
                            onClick={() => setMobileMenuOpen(false)}
                          >
                            <li className="w-full p-2 px-3 text-sm rounded-2xl tracking-tight hover:bg-neutral-100 border flex items-center justify-between">
                              About Us
                              {currentPath === '/about' ? (
                                <div
                                  className={`h-2 w-2 bg-[#154063] rounded-full relative transition-all mr-1`}
                                ></div>
                              ) : (
                                <div
                                  className={`h-2 w-2 bg-[#3779B5] rounded-full relative transition-all mr-1 opacity-50`}
                                ></div>
                              )}
                            </li>
                          </Link>
                          <Link
                            className={
                              currentPath === '/blog'
                                ? 'text-black'
                                : 'text-neutral-500 hover:text-neutral-700'
                            }
                            href="/blog"
                            onClick={() => setMobileMenuOpen(false)}
                          >
                            <li className="w-full p-2 px-3 text-sm rounded-2xl tracking-tight hover:bg-neutral-100 border flex items-center justify-between mt-2">
                              Blog
                              {currentPath === '/blog' ? (
                                <div
                                  className={`h-2 w-2 bg-[#154063] rounded-full relative transition-all mr-1`}
                                ></div>
                              ) : (
                                <div
                                  className={`h-2 w-2 bg-[#3779B5] rounded-full relative transition-all mr-1 opacity-50`}
                                ></div>
                              )}
                            </li>
                          </Link>
                          <Link
                            className={
                              currentPath === '/contact'
                                ? 'text-black'
                                : 'text-neutral-500 hover:text-neutral-700'
                            }
                            href="/contact"
                            onClick={() => setMobileMenuOpen(false)}
                          >
                            <li className="w-full p-2 px-3 text-sm rounded-2xl tracking-tight hover:bg-neutral-100 border flex items-center justify-between mt-2">
                              Contact
                              {currentPath === '/contact' ? (
                                <div
                                  className={`h-2 w-2 bg-[#154063] rounded-full relative transition-all mr-1`}
                                ></div>
                              ) : (
                                <div
                                  className={`h-2 w-2 bg-[#3779B5] rounded-full relative transition-all mr-1 opacity-50`}
                                ></div>
                              )}
                            </li>
                          </Link>
                        </div>
                      );
                    }

                    return (
                      <Link
                        className={
                          currentPath === href
                            ? 'text-black'
                            : 'text-neutral-500 hover:text-neutral-700'
                        }
                        href={href}
                        key={`${href}${name}`}
                        onClick={() => setMobileMenuOpen(false)}
                      >
                        <li className="w-full p-2 px-3 text-sm rounded-2xl tracking-tight hover:bg-neutral-100 border flex items-center justify-between">
                          {name}

                          {currentPath === href ? (
                            <div
                              className={`h-2 w-2 bg-[#154063] rounded-full relative transition-all mr-1`}
                            ></div>
                          ) : (
                            <div
                              className={`h-2 w-2 bg-[#3779B5] rounded-full relative transition-all mr-1 opacity-50`}
                            ></div>
                          )}
                        </li>
                      </Link>
                    );
                  })}
                </ul>
              </div>
              <div className="py-6">
                <Link href="#join-the-waitlist" onClick={() => setMobileMenuOpen(false)}>
                  <Button className="w-full">Join the Waitlist</Button>
                </Link>
              </div>
            </div>
          </div>
        </DialogPanel>
      </Dialog>
    </NavContext.Provider>
  );
}



================================================
FILE: components/ui/koellabs-onboarding.tsx
================================================
'use client';

import { useState, useEffect } from 'react';
import { Button } from '@/components/ui/base/button';
import {
  Card,
  CardContent,
  CardHeader,
  CardTitle,
  CardDescription,
  CardFooter,
} from '@/components/ui/base/card';
import { Label } from '@/components/ui/base/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/base/select';
import { Checkbox } from '@/components/ui/base/checkbox';
import { cn } from '@/lib/styles';
import { ChevronLeft, ChevronRight, Verified } from 'lucide-react';
import KoelBird from '@/components/ui/base/koel-labs-bird';

export default function OnboardingFlow({ user }: { user: string }) {
  const [step, setStep] = useState(1);
  const [targetLanguage, setTargetLanguage] = useState('');
  const [targetDialect, setTargetDialect] = useState('');
  const [nativeLanguage, setNativeLanguage] = useState('');
  const [nativeDialect, setNativeDialect] = useState('');
  const [consent, setConsent] = useState(false);
  const [privacyPolicy, setPrivacyPolicy] = useState(false);
  const [termsOfService, setTermsOfService] = useState(false);
  const [isNextDisabled, setIsNextDisabled] = useState(true);

  useEffect(() => {
    switch (step) {
      case 1:
        setIsNextDisabled(false);
        break;
      case 2:
        setIsNextDisabled(!targetLanguage);
        break;
      case 3:
        setIsNextDisabled(!nativeLanguage);
        break;
      case 4:
        setIsNextDisabled(!(consent && privacyPolicy && termsOfService));
        break;
      default:
        setIsNextDisabled(false);
    }
  }, [step, targetLanguage, nativeLanguage, consent, privacyPolicy, termsOfService]);

  const handleNext = () => {
    if (step < 4) setStep(step + 1);
  };

  const handleBack = () => {
    if (step > 1) setStep(step - 1);
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    console.log('Onboarding data:', {
      targetLanguage,
      targetDialect,
      nativeLanguage,
      nativeDialect,
      consent,
      privacyPolicy,
      termsOfService,
    });
    // Here you would typically send this data to your backend
  };

  const MandatoryStar = () => (
    <span className="text-[#317EC5]" aria-hidden="true">
      *
    </span>
  );

  const getDialects = (language: string) => {
    switch (language) {
      case 'english':
        return ['American', 'British', 'Australian', 'Canadian', 'Irish', 'Scottish', 'Other'];
      case 'spanish':
        return ['Castilian', 'Latin American', 'Other'];
      case 'french':
        return ['Metropolitan French', 'Canadian French', 'Other'];
      case 'german':
        return ['Standard German', 'Swiss German', 'Austrian German', 'Other'];
      default:
        return [];
    }
  };

  return (
    <div className="flex justify-center items-center h-full bg-muted relative rounded-xl m-4 overflow-hidden dark:bg-neutral-900/[0.25] border border-neutral-200">
      <div className="mx-auto absolute top-0 left-0 right-0 bottom-0 h-full flex justify-between z-0 rotate-45 scale-[1.95]">
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 "></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 "></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 "></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 "></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 "></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops3"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 "></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops2"></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 "></div>
        <div className="w-[1px] h-full bg-neutral-200 dark:bg-neutral-900 drops4"></div>
      </div>

      <Card className="w-[600px] p-0 rounded-2xl bg-white border border-neutral-200 z-11 relative">
        <CardHeader className="text-center bg-neutral-50 rounded-t-2xl py-9">
          <KoelBird className="w-16 h-16 mx-auto" />
          <CardTitle className="text-2xl tracking-tighter font-semibold">
            Welcome to Koel{' '}
            <span className="text-transparent bg-clip-text bg-linear-to-br from-black via-sky-950 to-sky-600 dark:from-white dark:via-white dark:to-white">
              Labs!
            </span>
          </CardTitle>
          <CardDescription>Step {step} of 4</CardDescription>
        </CardHeader>
        <div className="border-t border-neutral-200 mb-4"></div>
        <CardContent className="">
          <form onSubmit={handleSubmit}>
            {step === 1 && (
              <div className="space-y-6 px-2">
                <div className="space-y-3 pb-2 pt-4">
                  <h3 className="text-md font-semibold tracking-tight">Dear {user.normalize()},</h3>
                  <p className="text-sm text-muted-foreground leading-relaxed">
                    We're thrilled to have you join our community of pronunciation learners!
                  </p>
                  <p className="text-sm text-muted-foreground leading-relaxed">
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
                    incididunt ut labore et dolore magna aliqua. Ut imperdiet erat platea ultricies
                    consectetur natoque posuere ornare habitasse parturient lobortis.
                  </p>
                  <p className="text-sm text-muted-foreground leading-relaxed">
                    Nulla nulla id vel etiam; maximus id ipsum feugiat netus. Metus ultricies in
                    nisi praesent montes nam orci praesent sed. Elit adipiscing tellus dapibus fames
                    dapibus; ridiculus suspendisse semper. Consectetur commodo lacinia.
                  </p>

                  <p className="text-xs text-muted-foreground pt-1 mx-auto">
                    <img
                      src="/images/koelLabsSig.png"
                      alt="koel labs signature"
                      className="h-10 mt-2 mb-2 ml-0"
                    />
                    - Koel Labs Team
                  </p>
                </div>
              </div>
            )}
            {step === 2 && (
              <div className="space-y-4">
                <div className="space-y-2">
                  <Label htmlFor="targetLanguage">
                    Target Language <MandatoryStar />
                  </Label>
                  <Select
                    onValueChange={value => {
                      setTargetLanguage(value);
                      setTargetDialect('');
                    }}
                    value={targetLanguage}
                  >
                    <SelectTrigger id="targetLanguage">
                      <SelectValue placeholder="Select target language" />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="english">English</SelectItem>
                      <SelectItem value="spanish" disabled className="text-neutral-400">
                        Spanish (Coming Soon)
                      </SelectItem>
                      <SelectItem value="french" disabled className="text-neutral-400">
                        French (Coming Soon)
                      </SelectItem>
                      <SelectItem value="german" disabled className="text-neutral-400">
                        German (Coming Soon)
                      </SelectItem>
                    </SelectContent>
                  </Select>
                </div>
                {targetLanguage && (
                  <div className="space-y-2">
                    <Label htmlFor="targetDialect">Target Dialect (Optional)</Label>
                    <Select onValueChange={setTargetDialect} value={targetDialect}>
                      <SelectTrigger id="targetDialect">
                        <SelectValue placeholder="Select target dialect" />
                      </SelectTrigger>
                      <SelectContent>
                        {getDialects(targetLanguage).map(dialect => (
                          <SelectItem key={dialect} value={dialect.toLowerCase()}>
                            {dialect}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                )}
              </div>
            )}
            {step === 3 && (
              <div className="space-y-4">
                <div className="space-y-2">
                  <Label htmlFor="nativeLanguage">
                    Native Language <MandatoryStar />
                  </Label>
                  <Select
                    onValueChange={value => {
                      setNativeLanguage(value);
                      setNativeDialect('');
                    }}
                    value={nativeLanguage}
                  >
                    <SelectTrigger id="nativeLanguage">
                      <SelectValue placeholder="Select native language" />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="english">English</SelectItem>
                      <SelectItem value="spanish">Spanish</SelectItem>
                      <SelectItem value="french">French</SelectItem>
                      <SelectItem value="german">German</SelectItem>
                    </SelectContent>
                  </Select>
                </div>
                {nativeLanguage && (
                  <div className="space-y-2">
                    <Label htmlFor="nativeDialect">Native Dialect (Optional)</Label>
                    <Select onValueChange={setNativeDialect} value={nativeDialect}>
                      <SelectTrigger id="nativeDialect">
                        <SelectValue placeholder="Select native dialect" />
                      </SelectTrigger>
                      <SelectContent>
                        {getDialects(nativeLanguage).map(dialect => (
                          <SelectItem key={dialect} value={dialect.toLowerCase()}>
                            {dialect}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  </div>
                )}
              </div>
            )}
            {step === 4 && (
              <div className="space-y-4">
                <div className="flex flex-col gap-4">
                  <div className="relative flex w-full items-start mt-3 gap-2 rounded-lg border border-input p-4 shadow-xs shadow-black/5 has-data-[state=checked]:border-ring">
                    <Checkbox
                      id="consent"
                      checked={consent}
                      onCheckedChange={checked => setConsent(checked as boolean)}
                      className="order-1 after:absolute after:inset-0"
                      aria-describedby="checkbox-consent-description"
                    />
                    <div className="flex grow items-start gap-3">
                      <div className="grid gap-2">
                        <Label htmlFor="consent">
                          User Research Consent{' '}
                          <span className="text-xs font-normal leading-[inherit] text-muted-foreground">
                            <MandatoryStar />
                          </span>
                        </Label>
                        <p
                          id="checkbox-consent-description"
                          className="text-xs text-muted-foreground"
                        >
                          I consent to have recordings of my voice stored and analyzed for improving
                          my language learning experience.
                        </p>
                      </div>
                    </div>
                  </div>

                  <div className="relative flex w-full items-start gap-2 rounded-lg border border-input p-4 shadow-xs shadow-black/5 has-data-[state=checked]:border-ring">
                    <Checkbox
                      id="privacy"
                      checked={privacyPolicy}
                      onCheckedChange={checked => setPrivacyPolicy(checked as boolean)}
                      className="order-1 after:absolute after:inset-0"
                      aria-describedby="checkbox-privacy-description"
                    />
                    <div className="flex grow items-start gap-3">
                      <div className="grid gap-2">
                        <Label htmlFor="privacy">
                          Privacy Policy{' '}
                          <span className="text-xs font-normal leading-[inherit] text-muted-foreground">
                            <MandatoryStar />
                          </span>
                        </Label>
                        <p
                          id="checkbox-privacy-description"
                          className="text-xs text-muted-foreground"
                        >
                          I have read and agree to the{' '}
                          <a
                            href="/privacy"
                            className="text-[#317EC5] hover:underline"
                            target="_blank"
                            rel="noopener noreferrer"
                          >
                            Privacy Policy
                          </a>
                        </p>
                      </div>
                    </div>
                  </div>

                  <div className="relative flex w-full items-start gap-2 rounded-lg border border-input p-4 shadow-xs shadow-black/5 has-data-[state=checked]:border-ring">
                    <Checkbox
                      id="terms"
                      checked={termsOfService}
                      onCheckedChange={checked => setTermsOfService(checked as boolean)}
                      className="order-1 after:absolute after:inset-0"
                      aria-describedby="checkbox-terms-description"
                    />
                    <div className="flex grow items-start gap-3">
                      <div className="grid gap-2">
                        <Label htmlFor="terms">
                          Terms of Service{' '}
                          <span className="text-xs font-normal leading-[inherit] text-muted-foreground">
                            <MandatoryStar />
                          </span>
                        </Label>
                        <p
                          id="checkbox-terms-description"
                          className="text-xs text-muted-foreground"
                        >
                          I have read and agree to the{' '}
                          <a
                            href="/terms"
                            className="text-[#317EC5] hover:underline"
                            target="_blank"
                            rel="noopener noreferrer"
                          >
                            Terms of Service
                          </a>
                        </p>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            )}
          </form>
        </CardContent>
        <div className="border-t border-neutral-200"></div>
        <CardFooter className="flex justify-between p-4 bg-neutral-50 rounded-b-2xl transition-none">
          {step > 1 ? (
            <>
              <Button
                className="rounded-lg outline outline-1 h-9 outline-offset-[-2px] outline-neutral-100 tracking-[-0.02em] pr-4"
                variant="outline"
                onClick={handleBack}
              >
                <ChevronLeft className="w-4 h-4 inline-block -ml-2 mr-1" strokeWidth={2.5} />
                Back
              </Button>
              {step < 4 ? (
                <Button
                  className="rounded-lg outline outline-1 h-9 outline-offset-[-2px] outline-neutral-700 tracking-[-0.02em]"
                  onClick={handleNext}
                  disabled={isNextDisabled}
                >
                  Next
                  <ChevronRight
                    className="w-4 h-4 inline-block ml-1 -mr-1.5 mt-px"
                    strokeWidth={2.5}
                  />
                </Button>
              ) : (
                <Button
                  className="rounded-lg outline outline-1 h-9 outline-offset-[-2px] outline-neutral-700 tracking-[-0.02em]"
                  type="submit"
                  onClick={handleSubmit}
                  disabled={isNextDisabled}
                >
                  Submit
                </Button>
              )}
            </>
          ) : (
            <Button
              onClick={handleNext}
              disabled={isNextDisabled}
              className="w-full rounded-lg outline outline-1 outline-offset-[-2px] outline-neutral-700 tracking-[-0.02em]"
            >
              Start Your Journey{' '}
              <ChevronRight className="w-4 h-4 inline-block ml-1 mt-px" strokeWidth={3} />
            </Button>
          )}
        </CardFooter>
      </Card>
    </div>
  );
}



================================================
FILE: components/ui/sidebar.jsx
================================================
'use client';
import * as React from 'react';
import { PanelLeft } from 'lucide-react';

import { useIsMobile } from '@/hooks/use-mobile';
import { cn } from '@/lib/styles';
import { Button } from '@/components/ui/base/button';
import { Sheet, SheetContent } from '@/components/ui/base/sheet';
import { useReducedMotion } from 'framer-motion';

export const SIDEBAR_STATE_COOKIE = 'sidebar:state';

const SidebarContext = React.createContext({
  state: 'open',
  open: true,
  onOpenChange: () => {},
});

function useSidebar() {
  return React.useContext(SidebarContext);
}

const SidebarLayout = React.forwardRef(({ defaultOpen, className, ...props }, ref) => {
  const [open, setOpen] = React.useState(defaultOpen !== false);

  const onOpenChange = React.useCallback(open => {
    setOpen(open);
    document.cookie = `${SIDEBAR_STATE_COOKIE}=${open}; path=/; max-age=${60 * 60 * 24 * 7}`;
  }, []);

  const state = open ? 'open' : 'closed';

  return (
    <SidebarContext.Provider value={{ state, open, onOpenChange }}>
      <div
        ref={ref}
        data-sidebar={state}
        style={{
          '--sidebar-width': open ? '16rem' : '4rem',
        }}
        className={cn(
          'flex min-h-screen bg-accent/50 pl-0 transition-all duration-150 ease-in-out  special:pl-(--sidebar-width)',
          className,
        )}
        {...props}
      />
    </SidebarContext.Provider>
  );
});
SidebarLayout.displayName = 'SidebarLayout';

const SidebarTrigger = React.forwardRef(({ className, ...props }, ref) => {
  const { open, onOpenChange } = useSidebar();

  return (
    <Button
      ref={ref}
      variant="ghost"
      size="icon"
      className={cn('h-8 w-8', className, { 'fixed bottom-2 left-2': !open })}
      onClick={() => onOpenChange(!open)}
      {...props}
    >
      <PanelLeft className="h-4 w-4" />
      <span className="sr-only">Toggle Sidebar</span>
    </Button>
  );
});
SidebarTrigger.displayName = 'SidebarTrigger';

const Sidebar = React.forwardRef(({ className, children }, ref) => {
  const isMobile = useIsMobile();
  const prefersReducedMotion = useReducedMotion();
  const { open, onOpenChange } = useSidebar();

  const sidebar = (
    <div
      ref={ref}
      className={cn(
        'flex h-full flex-col border-r bg-background',
        prefersReducedMotion ? '' : 'transition-all duration-150 ease-in-out',
        open ? 'w-64' : 'w-16',

        className,
      )}
    >
      {children}
    </div>
  );

  if (isMobile) {
    return (
      <Sheet open={open} onOpenChange={onOpenChange}>
        <SheetContent
          className="w-[260px] p-0 md:w-(--sidebar-width) [&>button]:hidden"
          side="left"
        >
          {sidebar}
        </SheetContent>
      </Sheet>
    );
  }

  return (
    <aside
      className={cn(
        'fixed inset-y-0 left-0 z-10 hidden md:block',
        prefersReducedMotion ? '' : 'transition-all duration-150 ease-in-out',
        open ? 'w-64' : 'w-16',
      )}
    >
      {sidebar}
    </aside>
  );
});
Sidebar.displayName = 'Sidebar';

const SidebarHeader = React.forwardRef(({ className, ...props }, ref) => {
  return (
    <div ref={ref} className={cn('flex items-center border-b px-2.5 py-2', className)} {...props} />
  );
});
SidebarHeader.displayName = 'SidebarHeader';

const SidebarFooter = React.forwardRef(({ className, ...props }, ref) => {
  return (
    <div ref={ref} className={cn('flex items-center border-t px-2.5 py-2', className)} {...props} />
  );
});
SidebarFooter.displayName = 'SidebarFooter';

const SidebarContent = React.forwardRef(({ className, ...props }, ref) => {
  return (
    <div
      ref={ref}
      className={cn('flex flex-1 flex-col gap-5 overflow-auto py-4', className)}
      {...props}
    />
  );
});
SidebarContent.displayName = 'SidebarContent';

const SidebarItem = React.forwardRef(({ className, ...props }, ref) => {
  return <div ref={ref} className={cn('grid gap-2 px-2.5', className)} {...props} />;
});
SidebarItem.displayName = 'SidebarItem';

const SidebarLabel = React.forwardRef(({ className, ...props }, ref) => {
  return (
    <div
      ref={ref}
      className={cn('px-1.5 text-xs font-medium text-muted-foreground', className)}
      {...props}
    />
  );
});
SidebarLabel.displayName = 'SidebarLabel';

export {
  Sidebar,
  SidebarContent,
  SidebarFooter,
  SidebarHeader,
  SidebarItem,
  SidebarLabel,
  SidebarLayout,
  SidebarTrigger,
  useSidebar,
};



================================================
FILE: components/ui/toast.jsx
================================================
'use client';
import * as React from 'react';
import * as ToastPrimitives from '@radix-ui/react-toast';
import { cva } from 'class-variance-authority';
import { X } from 'lucide-react';

import { cn } from '@/lib/styles';

const ToastProvider = ToastPrimitives.Provider;

const ToastViewport = React.forwardRef(({ className, ...props }, ref) => (
  <ToastPrimitives.Viewport
    ref={ref}
    className={cn(
      'fixed top-0 z-100 flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]',
      className,
    )}
    {...props}
  />
));
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;

const toastVariants = cva(
  'group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full sm:data-[state=open]:slide-in-from-bottom-full',
  {
    variants: {
      variant: {
        default: 'border bg-background text-foreground',
        destructive:
          'destructive group border-destructive bg-destructive text-destructive-foreground',
      },
    },
    defaultVariants: {
      variant: 'default',
    },
  },
);

const Toast = React.forwardRef(({ className, variant, ...props }, ref) => {
  return (
    <ToastPrimitives.Root
      ref={ref}
      className={cn(toastVariants({ variant }), className)}
      {...props}
    />
  );
});
Toast.displayName = ToastPrimitives.Root.displayName;

const ToastAction = React.forwardRef(({ className, ...props }, ref) => (
  <ToastPrimitives.Action
    ref={ref}
    className={cn(
      'inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 hover:group-[.destructive]:border-destructive/30 hover:group-[.destructive]:bg-destructive hover:group-[.destructive]:text-destructive-foreground focus:group-[.destructive]:ring-destructive',
      className,
    )}
    {...props}
  />
));
ToastAction.displayName = ToastPrimitives.Action.displayName;

const ToastClose = React.forwardRef(({ className, ...props }, ref) => (
  <ToastPrimitives.Close
    ref={ref}
    className={cn(
      'absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-hidden focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 hover:group-[.destructive]:text-red-50 focus:group-[.destructive]:ring-red-400 focus:group-[.destructive]:ring-offset-red-600',
      className,
    )}
    toast-close=""
    {...props}
  >
    <X className="h-4 w-4" />
  </ToastPrimitives.Close>
));
ToastClose.displayName = ToastPrimitives.Close.displayName;

const ToastTitle = React.forwardRef(({ className, ...props }, ref) => (
  <ToastPrimitives.Title ref={ref} className={cn('text-sm font-semibold', className)} {...props} />
));
ToastTitle.displayName = ToastPrimitives.Title.displayName;

const ToastDescription = React.forwardRef(({ className, ...props }, ref) => (
  <ToastPrimitives.Description
    ref={ref}
    className={cn('text-sm opacity-90', className)}
    {...props}
  />
));
ToastDescription.displayName = ToastPrimitives.Description.displayName;

export {
  ToastProvider,
  ToastViewport,
  Toast,
  ToastTitle,
  ToastDescription,
  ToastClose,
  ToastAction,
};



================================================
FILE: components/ui/toaster.jsx
================================================
'use client';

import { useToast } from '@/hooks/use-toast';
import {
  Toast,
  ToastClose,
  ToastDescription,
  ToastProvider,
  ToastTitle,
  ToastViewport,
} from '@/components/ui/toast';

export function Toaster() {
  const { toasts } = useToast();

  return (
    <ToastProvider>
      {toasts.map(function ({ id, title, description, action, ...props }) {
        return (
          <Toast key={id} {...props}>
            <div className="grid gap-1">
              {title && <ToastTitle>{title}</ToastTitle>}
              {description && <ToastDescription>{description}</ToastDescription>}
            </div>
            {action}
            <ToastClose />
          </Toast>
        );
      })}
      <ToastViewport />
    </ToastProvider>
  );
}



================================================
FILE: components/ui/base/avatar.jsx
================================================
'use client';

import * as React from 'react';
import * as AvatarPrimitive from '@radix-ui/react-avatar';

import { cn } from '@/lib/styles';

const Avatar = React.forwardRef(({ className, ...props }, ref) => (
  <AvatarPrimitive.Root
    ref={ref}
    className={cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', className)}
    {...props}
  />
));
Avatar.displayName = AvatarPrimitive.Root.displayName;

const AvatarImage = React.forwardRef(({ className, ...props }, ref) => (
  <AvatarPrimitive.Image
    ref={ref}
    className={cn('aspect-square h-full w-full', className)}
    {...props}
  />
));
AvatarImage.displayName = AvatarPrimitive.Image.displayName;

const AvatarFallback = React.forwardRef(({ className, ...props }, ref) => (
  <AvatarPrimitive.Fallback
    ref={ref}
    className={cn(
      'flex h-full w-full items-center justify-center rounded-full bg-muted',
      className,
    )}
    {...props}
  />
));
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;

export { Avatar, AvatarImage, AvatarFallback };



================================================
FILE: components/ui/base/badge.jsx
================================================
import * as React from 'react';
import { cva } from 'class-variance-authority';

import { cn } from '@/lib/styles';

const badgeVariants = cva(
  'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2',
  {
    variants: {
      variant: {
        default: 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
        secondary:
          'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
        destructive:
          'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
        outline: 'text-foreground',
      },
    },
    defaultVariants: {
      variant: 'default',
    },
  },
);

function Badge({ className, variant, ...props }) {
  return <div className={cn(badgeVariants({ variant }), className)} {...props} />;
}

export { Badge, badgeVariants };



================================================
FILE: components/ui/base/button.tsx
================================================
import * as React from 'react';
import { Slot } from '@radix-ui/react-slot';
import { cva } from 'class-variance-authority';

import { cn } from '@/lib/styles';

const buttonVariants = cva(
  'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 cursor-pointer',
  {
    variants: {
      variant: {
        default: 'bg-primary text-primary-foreground hover:bg-primary/90',
        destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
        outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
        secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
        ghost: 'hover:bg-accent hover:text-accent-foreground',
        link: 'text-primary underline-offset-4 hover:underline',
      },
      size: {
        default: 'h-9 rounded-xl px-4 py-2',
        settings: 'h-9 rounded-lg px-4 py-2',
        sm: 'h-8 rounded-xl px-3',
        lg: 'h-10 rounded-xl px-5',
        icon: 'h-10 w-10',
        badge: 'h-8 rounded-full px-3',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  },
);

type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
  className?: string;
  variant?: any;
  size?: any;
  asChild?: boolean;
};

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, children, ...props }, ref) => {
    const Comp = asChild ? Slot : 'button';
    return (
      <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props}>
        {children}
      </Comp>
    );
  },
);
Button.displayName = 'Button';

export { Button, buttonVariants };



================================================
FILE: components/ui/base/card.tsx
================================================
import * as React from 'react';

import { cn } from '@/lib/styles';

type CardProps = React.HTMLAttributes<HTMLDivElement> & {
  className?: string;
};

const Card = React.forwardRef<HTMLDivElement, CardProps>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn('rounded-lg border bg-card text-card-foreground shadow-xs', className)}
    {...props}
  />
));
Card.displayName = 'Card';

type CardHeaderProps = React.HTMLAttributes<HTMLDivElement> & {
  className?: string;
};

const CardHeader = React.forwardRef<HTMLDivElement, CardHeaderProps>(
  ({ className, ...props }, ref) => (
    <div ref={ref} className={cn('flex flex-col space-y-1.5 p-6', className)} {...props} />
  ),
);
CardHeader.displayName = 'CardHeader';

type CardTitleProps = React.HTMLAttributes<HTMLHeadingElement> & {
  className?: string;
};

const CardTitle = React.forwardRef<HTMLHeadingElement, CardTitleProps>(
  ({ className, ...props }, ref) => (
    <h3
      ref={ref}
      className={cn('text-2xl font-semibold leading-none tracking-tight', className)}
      {...props}
    />
  ),
);
CardTitle.displayName = 'CardTitle';

type CardDescriptionProps = React.HTMLAttributes<HTMLParagraphElement> & {
  className?: string;
};

const CardDescription = React.forwardRef<HTMLParagraphElement, CardDescriptionProps>(
  ({ className, ...props }, ref) => (
    <p ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />
  ),
);
CardDescription.displayName = 'CardDescription';

type CardContentProps = React.HTMLAttributes<HTMLDivElement> & {
  className?: string;
};

const CardContent = React.forwardRef<HTMLDivElement, CardContentProps>(
  ({ className, ...props }, ref) => (
    <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
  ),
);
CardContent.displayName = 'CardContent';

type CardFooterProps = React.HTMLAttributes<HTMLDivElement> & {
  className?: string;
};

const CardFooter = React.forwardRef<HTMLDivElement, CardFooterProps>(
  ({ className, ...props }, ref) => (
    <div ref={ref} className={cn('flex items-center p-6 pt-0', className)} {...props} />
  ),
);
CardFooter.displayName = 'CardFooter';

export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };



================================================
FILE: components/ui/base/carousel.tsx
================================================
'use client';
import * as React from 'react';
import useEmblaCarousel, { EmblaViewportRefType } from 'embla-carousel-react';
import { ArrowLeft, ArrowRight } from 'lucide-react';

import { cn } from '@/lib/styles';
import { Button } from '@/components/ui/base/button';

const CarouselContext = React.createContext<{
  carouselRef: EmblaViewportRefType;
  api: any;
  opts: any;
  orientation: 'horizontal' | 'vertical';
  scrollPrev: () => void;
  scrollNext: () => void;
  canScrollPrev: boolean;
  canScrollNext: boolean;
} | null>(null);

function useCarousel() {
  const context = React.useContext(CarouselContext);

  if (!context) {
    throw new Error('useCarousel must be used within a <Carousel />');
  }

  return context;
}

type CarouselProps = React.HTMLAttributes<HTMLDivElement> & {
  orientation?: 'horizontal' | 'vertical';
  opts?: any;
  setApi?: (api: any) => void;
  plugins?: any;
};

const Carousel = React.forwardRef<HTMLDivElement, CarouselProps>(
  ({ orientation = 'horizontal', opts, setApi, plugins, className, children, ...props }, ref) => {
    const [carouselRef, api] = useEmblaCarousel(
      {
        ...opts,
        axis: orientation === 'horizontal' ? 'x' : 'y',
      },
      plugins,
    );
    const [canScrollPrev, setCanScrollPrev] = React.useState(false);
    const [canScrollNext, setCanScrollNext] = React.useState(false);

    const onSelect = React.useCallback(api => {
      if (!api) {
        return;
      }

      setCanScrollPrev(api.canScrollPrev());
      setCanScrollNext(api.canScrollNext());
    }, []);

    const scrollPrev = React.useCallback(() => {
      api?.scrollPrev();
    }, [api]);

    const scrollNext = React.useCallback(() => {
      api?.scrollNext();
    }, [api]);

    const handleKeyDown = React.useCallback(
      event => {
        if (event.key === 'ArrowLeft') {
          event.preventDefault();
          scrollPrev();
        } else if (event.key === 'ArrowRight') {
          event.preventDefault();
          scrollNext();
        }
      },
      [scrollPrev, scrollNext],
    );

    React.useEffect(() => {
      if (!api || !setApi) {
        return;
      }

      setApi(api);
    }, [api, setApi]);

    React.useEffect(() => {
      if (!api) {
        return;
      }

      onSelect(api);
      api.on('reInit', onSelect);
      api.on('select', onSelect);

      return () => {
        api?.off('select', onSelect);
      };
    }, [api, onSelect]);

    return (
      <CarouselContext.Provider
        value={{
          carouselRef,
          api: api,
          opts,
          orientation: orientation || (opts?.axis === 'y' ? 'vertical' : 'horizontal'),
          scrollPrev,
          scrollNext,
          canScrollPrev,
          canScrollNext,
        }}
      >
        <div
          ref={ref}
          onKeyDownCapture={handleKeyDown}
          className={cn('relative', className)}
          role="region"
          aria-roledescription="carousel"
          {...props}
        >
          {children}
        </div>
      </CarouselContext.Provider>
    );
  },
);
Carousel.displayName = 'Carousel';

type CarouselContentProps = React.HTMLAttributes<HTMLDivElement> & {
  overflowVisible?: boolean;
};

const CarouselContent = React.forwardRef<HTMLDivElement, CarouselContentProps>(
  ({ className, overflowVisible, ...props }, ref) => {
    const { carouselRef, orientation } = useCarousel();

    return (
      <div
        ref={carouselRef}
        className={cn('overflow-hidden', overflowVisible && 'overflow-visible')}
      >
        <div
          ref={ref}
          className={cn(
            'flex',
            orientation === 'horizontal' ? '-ml-4' : '-mt-4 flex-col',
            className,
          )}
          {...props}
        />
      </div>
    );
  },
);
CarouselContent.displayName = 'CarouselContent';

type CarouselItemProps = React.HTMLAttributes<HTMLDivElement>;

const CarouselItem = React.forwardRef<HTMLDivElement, CarouselItemProps>(
  ({ className, ...props }, ref) => {
    const { orientation } = useCarousel();

    return (
      <div
        ref={ref}
        role="group"
        aria-roledescription="slide"
        className={cn(
          'min-w-0 shrink-0 grow-0 basis-full',
          orientation === 'horizontal' ? 'pl-4' : 'pt-4',
          className,
        )}
        {...props}
      />
    );
  },
);
CarouselItem.displayName = 'CarouselItem';

type CarouselPreviousProps = React.HTMLAttributes<HTMLButtonElement> & {
  variant?: any;
  size?: any;
};

const CarouselPrevious = React.forwardRef<HTMLButtonElement, CarouselPreviousProps>(
  ({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
    const { orientation, scrollPrev, canScrollPrev } = useCarousel();

    return (
      <Button
        ref={ref}
        variant={variant}
        size={size}
        className={cn(
          'absolute  h-8 w-8 rounded-full',
          orientation === 'horizontal'
            ? '-left-12 top-1/2 -translate-y-1/2'
            : '-top-12 left-1/2 -translate-x-1/2 rotate-90',
          className,
        )}
        disabled={!canScrollPrev}
        onClick={scrollPrev}
        {...props}
      >
        <ArrowLeft className="h-4 w-4" />
        <span className="sr-only">Previous slide</span>
      </Button>
    );
  },
);
CarouselPrevious.displayName = 'CarouselPrevious';

type CarouselNextProps = React.HTMLAttributes<HTMLButtonElement> & {
  variant?: any;
  size?: any;
};

const CarouselNext = React.forwardRef<HTMLButtonElement, CarouselNextProps>(
  ({ className, variant = 'outline', size = 'icon', ...props }, ref) => {
    const { orientation, scrollNext, canScrollNext } = useCarousel();

    return (
      <Button
        ref={ref}
        variant={variant}
        size={size}
        className={cn(
          'absolute h-8 w-8 rounded-full',
          orientation === 'horizontal'
            ? '-right-12 top-1/2 -translate-y-1/2'
            : '-bottom-12 left-1/2 -translate-x-1/2 rotate-90',
          className,
        )}
        disabled={!canScrollNext}
        onClick={scrollNext}
        {...props}
      >
        <ArrowRight className="h-4 w-4" />
        <span className="sr-only">Next slide</span>
      </Button>
    );
  },
);
CarouselNext.displayName = 'CarouselNext';

export { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext };



================================================
FILE: components/ui/base/chart.tsx
================================================
'use client';

import * as React from 'react';
import * as RechartsPrimitive from 'recharts';

import { cn } from '@/lib/styles';

// Format: { THEME_NAME: CSS_SELECTOR }
const THEMES = { light: '', dark: '.dark' } as const;

export type ChartConfig = {
  [k in string]: {
    label?: React.ReactNode;
    icon?: React.ComponentType;
  } & (
    | { color?: string; theme?: never }
    | { color?: never; theme: Record<keyof typeof THEMES, string> }
  );
};

type ChartContextProps = {
  config: ChartConfig;
};

const ChartContext = React.createContext<ChartContextProps | null>(null);

function useChart() {
  const context = React.useContext(ChartContext);

  if (!context) {
    throw new Error('useChart must be used within a <ChartContainer />');
  }

  return context;
}

const ChartContainer = React.forwardRef<
  HTMLDivElement,
  React.ComponentProps<'div'> & {
    config: ChartConfig;
    children: React.ComponentProps<typeof RechartsPrimitive.ResponsiveContainer>['children'];
  }
>(({ id, className, children, config, ...props }, ref) => {
  const uniqueId = React.useId();
  const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`;

  return (
    <ChartContext.Provider value={{ config }}>
      <div
        data-chart={chartId}
        ref={ref}
        className={cn(
          "flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
          className,
        )}
        {...props}
      >
        <ChartStyle id={chartId} config={config} />
        <RechartsPrimitive.ResponsiveContainer>{children}</RechartsPrimitive.ResponsiveContainer>
      </div>
    </ChartContext.Provider>
  );
});
ChartContainer.displayName = 'Chart';

const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
  const colorConfig = Object.entries(config).filter(([, config]) => config.theme || config.color);

  if (!colorConfig.length) {
    return null;
  }

  return (
    <style
      dangerouslySetInnerHTML={{
        __html: Object.entries(THEMES)
          .map(
            ([theme, prefix]) => `
${prefix} [data-chart=${id}] {
${colorConfig
  .map(([key, itemConfig]) => {
    const color = itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || itemConfig.color;
    return color ? `  --color-${key}: ${color};` : null;
  })
  .join('\n')}
}
`,
          )
          .join('\n'),
      }}
    />
  );
};

const ChartTooltip = RechartsPrimitive.Tooltip;

const ChartTooltipContent = React.forwardRef<
  HTMLDivElement,
  React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
    React.ComponentProps<'div'> & {
      hideLabel?: boolean;
      hideIndicator?: boolean;
      indicator?: 'line' | 'dot' | 'dashed';
      nameKey?: string;
      labelKey?: string;
    }
>(
  (
    {
      active,
      payload,
      className,
      indicator = 'dot',
      hideLabel = false,
      hideIndicator = false,
      label,
      labelFormatter,
      labelClassName,
      formatter,
      color,
      nameKey,
      labelKey,
    },
    ref,
  ) => {
    const { config } = useChart();

    const tooltipLabel = React.useMemo(() => {
      if (hideLabel || !payload?.length) {
        return null;
      }

      const [item] = payload;
      const key = `${labelKey || item?.dataKey || item?.name || 'value'}`;
      const itemConfig = getPayloadConfigFromPayload(config, item, key);
      const value =
        !labelKey && typeof label === 'string'
          ? config[label as keyof typeof config]?.label || label
          : itemConfig?.label;

      if (labelFormatter) {
        return (
          <div className={cn('font-medium', labelClassName)}>{labelFormatter(value, payload)}</div>
        );
      }

      if (!value) {
        return null;
      }

      return <div className={cn('font-medium', labelClassName)}>{value}</div>;
    }, [label, labelFormatter, payload, hideLabel, labelClassName, config, labelKey]);

    if (!active || !payload?.length) {
      return null;
    }

    const nestLabel = payload.length === 1 && indicator !== 'dot';

    return (
      <div
        ref={ref}
        className={cn(
          'grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl',
          className,
        )}
      >
        {!nestLabel ? tooltipLabel : null}
        <div className="grid gap-1.5">
          {payload.map((item, index) => {
            const key = `${nameKey || item.name || item.dataKey || 'value'}`;
            const itemConfig = getPayloadConfigFromPayload(config, item, key);
            const indicatorColor = color || item.payload.fill || item.color;

            return (
              <div
                key={item.dataKey}
                className={cn(
                  'flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground',
                  indicator === 'dot' && 'items-center',
                )}
              >
                {formatter && item?.value !== undefined && item.name ? (
                  formatter(item.value, item.name, item, index, item.payload)
                ) : (
                  <>
                    {itemConfig?.icon ? (
                      <itemConfig.icon />
                    ) : (
                      !hideIndicator && (
                        <div
                          className={cn(
                            'shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]',
                            {
                              'h-2.5 w-2.5': indicator === 'dot',
                              'w-1': indicator === 'line',
                              'w-0 border-[1.5px] border-dashed bg-transparent':
                                indicator === 'dashed',
                              'my-0.5': nestLabel && indicator === 'dashed',
                            },
                          )}
                          style={
                            {
                              '--color-bg': indicatorColor,
                              '--color-border': indicatorColor,
                            } as React.CSSProperties
                          }
                        />
                      )
                    )}
                    <div
                      className={cn(
                        'flex flex-1 justify-between leading-none',
                        nestLabel ? 'items-end' : 'items-center',
                      )}
                    >
                      <div className="grid gap-1.5">
                        {nestLabel ? tooltipLabel : null}
                        <span className="text-muted-foreground">
                          {itemConfig?.label || item.name}
                        </span>
                      </div>
                      {item.value && (
                        <span className="font-mono font-medium tabular-nums text-foreground">
                          {item.value.toLocaleString()}
                        </span>
                      )}
                    </div>
                  </>
                )}
              </div>
            );
          })}
        </div>
      </div>
    );
  },
);
ChartTooltipContent.displayName = 'ChartTooltip';

const ChartLegend = RechartsPrimitive.Legend;

const ChartLegendContent = React.forwardRef<
  HTMLDivElement,
  React.ComponentProps<'div'> &
    Pick<RechartsPrimitive.LegendProps, 'payload' | 'verticalAlign'> & {
      hideIcon?: boolean;
      nameKey?: string;
    }
>(({ className, hideIcon = false, payload, verticalAlign = 'bottom', nameKey }, ref) => {
  const { config } = useChart();

  if (!payload?.length) {
    return null;
  }

  return (
    <div
      ref={ref}
      className={cn(
        'flex items-center justify-center gap-4',
        verticalAlign === 'top' ? 'pb-3' : 'pt-3',
        className,
      )}
    >
      {payload.map(item => {
        const key = `${nameKey || item.dataKey || 'value'}`;
        const itemConfig = getPayloadConfigFromPayload(config, item, key);

        return (
          <div
            key={item.value}
            className={cn(
              'flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground',
            )}
          >
            {itemConfig?.icon && !hideIcon ? (
              <itemConfig.icon />
            ) : (
              <div
                className="h-2 w-2 shrink-0 rounded-[2px]"
                style={{
                  backgroundColor: item.color,
                }}
              />
            )}
            {itemConfig?.label}
          </div>
        );
      })}
    </div>
  );
});
ChartLegendContent.displayName = 'ChartLegend';

// Helper to extract item config from a payload.
function getPayloadConfigFromPayload(config: ChartConfig, payload: unknown, key: string) {
  if (typeof payload !== 'object' || payload === null) {
    return undefined;
  }

  const payloadPayload =
    'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null
      ? payload.payload
      : undefined;

  let configLabelKey: string = key;

  if (key in payload && typeof payload[key as keyof typeof payload] === 'string') {
    configLabelKey = payload[key as keyof typeof payload] as string;
  } else if (
    payloadPayload &&
    key in payloadPayload &&
    typeof payloadPayload[key as keyof typeof payloadPayload] === 'string'
  ) {
    configLabelKey = payloadPayload[key as keyof typeof payloadPayload] as string;
  }

  return configLabelKey in config ? config[configLabelKey] : config[key as keyof typeof config];
}

export {
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  ChartLegend,
  ChartLegendContent,
  ChartStyle,
};



================================================
FILE: components/ui/base/checkbox.tsx
================================================
'use client';

import * as React from 'react';
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
import { Check } from 'lucide-react';

import { cn } from '@/lib/styles';

type CheckboxProps = React.ComponentProps<typeof CheckboxPrimitive.Root>;

const Checkbox = React.forwardRef<HTMLButtonElement, CheckboxProps>(
  ({ className, ...props }, ref) => (
    <CheckboxPrimitive.Root
      ref={ref}
      className={cn(
        'peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
        className,
      )}
      {...props}
    >
      <CheckboxPrimitive.Indicator className={cn('flex items-center justify-center text-current')}>
        <Check className="h-4 w-4" />
      </CheckboxPrimitive.Indicator>
    </CheckboxPrimitive.Root>
  ),
);
Checkbox.displayName = CheckboxPrimitive.Root.displayName;

export { Checkbox };



================================================
FILE: components/ui/base/collapsible.jsx
================================================
'use client';

import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';

const Collapsible = CollapsiblePrimitive.Root;

const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;

const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent;

export { Collapsible, CollapsibleTrigger, CollapsibleContent };



================================================
FILE: components/ui/base/command.tsx
================================================
'use client';

import * as React from 'react';
import { Command as CommandPrimitive } from 'cmdk';
import { SearchIcon } from 'lucide-react';

import { cn } from '@/lib/styles';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/base/dialog';

function Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {
  return (
    <CommandPrimitive
      data-slot="command"
      className={cn(
        'bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md',
        className,
      )}
      {...props}
    />
  );
}

function CommandDialog({
  title = 'Command Palette',
  description = 'Search for a command to run...',
  children,
  className,
  showCloseButton = true,
  ...props
}: React.ComponentProps<typeof Dialog> & {
  title?: string;
  description?: string;
  className?: string;
  showCloseButton?: boolean;
}) {
  return (
    <Dialog {...props}>
      <DialogHeader className="sr-only">
        <DialogTitle className={className}>{title}</DialogTitle>
        <DialogDescription className={className}>{description}</DialogDescription>
      </DialogHeader>
      <DialogContent
        className={cn('overflow-hidden p-0', className)}
        showCloseButton={showCloseButton}
      >
        <Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
          {children}
        </Command>
      </DialogContent>
    </Dialog>
  );
}

function CommandInput({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Input>) {
  return (
    <div data-slot="command-input-wrapper" className="flex h-9 items-center gap-2 border-b px-3">
      <SearchIcon className="size-4 shrink-0 opacity-50" />
      <CommandPrimitive.Input
        data-slot="command-input"
        className={cn(
          'placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
          className,
        )}
        {...props}
      />
    </div>
  );
}

function CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {
  return (
    <CommandPrimitive.List
      data-slot="command-list"
      className={cn('max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto', className)}
      {...props}
    />
  );
}

function CommandEmpty({ ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
  return (
    <CommandPrimitive.Empty
      data-slot="command-empty"
      className="py-6 text-center text-sm"
      {...props}
    />
  );
}

function CommandGroup({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Group>) {
  return (
    <CommandPrimitive.Group
      data-slot="command-group"
      className={cn(
        'text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium',
        className,
      )}
      {...props}
    />
  );
}

function CommandSeparator({
  className,
  ...props
}: React.ComponentProps<typeof CommandPrimitive.Separator>) {
  return (
    <CommandPrimitive.Separator
      data-slot="command-separator"
      className={cn('bg-border -mx-1 h-px', className)}
      {...props}
    />
  );
}

function CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>) {
  return (
    <CommandPrimitive.Item
      data-slot="command-item"
      className={cn(
        "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
        className,
      )}
      {...props}
    />
  );
}

function CommandShortcut({ className, ...props }: React.ComponentProps<'span'>) {
  return (
    <span
      data-slot="command-shortcut"
      className={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)}
      {...props}
    />
  );
}

export {
  Command,
  CommandDialog,
  CommandInput,
  CommandList,
  CommandEmpty,
  CommandGroup,
  CommandItem,
  CommandShortcut,
  CommandSeparator,
};



================================================
FILE: components/ui/base/context-menu.jsx
================================================
'use client';

import * as React from 'react';
import * as ContextMenuPrimitive from '@radix-ui/react-context-menu';
import { Check, ChevronRight, Circle } from 'lucide-react';

import { cn } from '@/lib/styles';

const ContextMenu = ContextMenuPrimitive.Root;

const ContextMenuTrigger = ContextMenuPrimitive.Trigger;

const ContextMenuGroup = ContextMenuPrimitive.Group;

const ContextMenuPortal = ContextMenuPrimitive.Portal;

const ContextMenuSub = ContextMenuPrimitive.Sub;

const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;

const ContextMenuSubTrigger = React.forwardRef(({ className, inset, children, ...props }, ref) => (
  <ContextMenuPrimitive.SubTrigger
    ref={ref}
    className={cn(
      'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground',
      inset && 'pl-8',
      className,
    )}
    {...props}
  >
    {children}
    <ChevronRight className="ml-auto h-4 w-4" />
  </ContextMenuPrimitive.SubTrigger>
));
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;

const ContextMenuSubContent = React.forwardRef(({ className, ...props }, ref) => (
  <ContextMenuPrimitive.SubContent
    ref={ref}
    className={cn(
      'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
      className,
    )}
    {...props}
  />
));
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;

const ContextMenuContent = React.forwardRef(({ className, ...props }, ref) => (
  <ContextMenuPrimitive.Portal>
    <ContextMenuPrimitive.Content
      ref={ref}
      className={cn(
        'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
        className,
      )}
      {...props}
    />
  </ContextMenuPrimitive.Portal>
));
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;

const ContextMenuItem = React.forwardRef(({ className, inset, ...props }, ref) => (
  <ContextMenuPrimitive.Item
    ref={ref}
    className={cn(
      'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
      inset && 'pl-8',
      className,
    )}
    {...props}
  />
));
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;

const ContextMenuCheckboxItem = React.forwardRef(
  ({ className, children, checked, ...props }, ref) => (
    <ContextMenuPrimitive.CheckboxItem
      ref={ref}
      className={cn(
        'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
        className,
      )}
      checked={checked}
      {...props}
    >
      <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
        <ContextMenuPrimitive.ItemIndicator>
          <Check className="h-4 w-4" />
        </ContextMenuPrimitive.ItemIndicator>
      </span>
      {children}
    </ContextMenuPrimitive.CheckboxItem>
  ),
);
ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName;

const ContextMenuRadioItem = React.forwardRef(({ className, children, ...props }, ref) => (
  <ContextMenuPrimitive.RadioItem
    ref={ref}
    className={cn(
      'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
      className,
    )}
    {...props}
  >
    <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
      <ContextMenuPrimitive.ItemIndicator>
        <Circle className="h-2 w-2 fill-current" />
      </ContextMenuPrimitive.ItemIndicator>
    </span>
    {children}
  </ContextMenuPrimitive.RadioItem>
));
ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;

const ContextMenuLabel = React.forwardRef(({ className, inset, ...props }, ref) => (
  <ContextMenuPrimitive.Label
    ref={ref}
    className={cn('px-2 py-1.5 text-sm font-semibold text-foreground', inset && 'pl-8', className)}
    {...props}
  />
));
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;

const ContextMenuSeparator = React.forwardRef(({ className, ...props }, ref) => (
  <ContextMenuPrimitive.Separator
    ref={ref}
    className={cn('-mx-1 my-1 h-px bg-border', className)}
    {...props}
  />
));
ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;

const ContextMenuShortcut = ({ className, ...props }) => {
  return (
    <span
      className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}
      {...props}
    />
  );
};
ContextMenuShortcut.displayName = 'ContextMenuShortcut';

export {
  ContextMenu,
  ContextMenuTrigger,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuCheckboxItem,
  ContextMenuRadioItem,
  ContextMenuLabel,
  ContextMenuSeparator,
  ContextMenuShortcut,
  ContextMenuGroup,
  ContextMenuPortal,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuRadioGroup,
};



================================================
FILE: components/ui/base/date.tsx
================================================
import { Button, DatePicker, Dialog, Group, Label, Popover } from 'react-aria-components';

import { Calendar } from '@/components/ui/calendar-rac';
import { DateInput } from '@/components/ui/datefield-rac';
import { CalendarIcon } from 'lucide-react';
import { DateValue } from '@internationalized/date';

export default function DatePickerComponent({
  label,
  value,
  onChange,
}: {
  label: string;
  value: DateValue | null;
  onChange: (value: DateValue | null) => void;
}) {
  return (
    <DatePicker className="*:not-first:mt-2 text-left" value={value} onChange={onChange}>
      <Label className="text-foreground text-sm font-medium">{label}</Label>
      <div className="flex mt-1!">
        <Group className="w-full">
          <DateInput className="pe-9" />
        </Group>
        <Button className="text-muted-foreground/80 hover:text-foreground data-focus-visible:border-ring data-focus-visible:ring-ring/50 z-10 -ms-9 -me-px flex w-9 items-center justify-center rounded-e-md transition-[color,box-shadow] outline-none data-focus-visible:ring-[3px]">
          <CalendarIcon size={16} />
        </Button>
      </div>
      <Popover
        className="bg-background text-popover-foreground data-entering:animate-in data-exiting:animate-out data-[entering]:fade-in-0 data-[exiting]:fade-out-0 data-[entering]:zoom-in-95 data-[exiting]:zoom-out-95 data-[placement=bottom]:slide-in-from-top-2 data-[placement=left]:slide-in-from-right-2 data-[placement=right]:slide-in-from-left-2 data-[placement=top]:slide-in-from-bottom-2 z-50 rounded-lg border shadow-lg outline-hidden"
        offset={4}
      >
        <Dialog className="max-h-[inherit] overflow-auto p-2">
          <Calendar />
        </Dialog>
      </Popover>
    </DatePicker>
  );
}



================================================
FILE: components/ui/base/dialog.tsx
================================================
'use client';

import * as React from 'react';
import * as DialogPrimitive from '@radix-ui/react-dialog';
import { XIcon } from 'lucide-react';

import { cn } from '@/lib/styles';

function Dialog({ ...props }) {
  return <DialogPrimitive.Root data-slot="dialog" {...props} />;
}

function DialogTrigger({ ...props }) {
  return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
}

function DialogPortal({ ...props }) {
  return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
}

function DialogClose({ ...props }) {
  return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
}

function DialogOverlay({ className, ...props }) {
  return (
    <DialogPrimitive.Overlay
      data-slot="dialog-overlay"
      className={cn(
        'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50',
        className,
      )}
      {...props}
    />
  );
}

function DialogContent({ className, children, ...props }) {
  return (
    <DialogPortal data-slot="dialog-portal">
      <DialogOverlay className="" />
      <DialogPrimitive.Content
        data-slot="dialog-content"
        className={cn(
          'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
          className,
        )}
        {...props}
      >
        {children}
        <DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4">
          <XIcon />
          <span className="sr-only">Close</span>
        </DialogPrimitive.Close>
      </DialogPrimitive.Content>
    </DialogPortal>
  );
}

function DialogHeader({ className, ...props }) {
  return (
    <div
      data-slot="dialog-header"
      className={cn('flex flex-col gap-2 text-center sm:text-left', className)}
      {...props}
    />
  );
}

function DialogFooter({ className, ...props }) {
  return (
    <div
      data-slot="dialog-footer"
      className={cn('flex flex-col-reverse gap-2 sm:flex-row sm:justify-end', className)}
      {...props}
    />
  );
}

function DialogTitle({ className, ...props }) {
  return (
    <DialogPrimitive.Title
      data-slot="dialog-title"
      className={cn('text-lg leading-none font-semibold', className)}
      {...props}
    />
  );
}

function DialogDescription({ className, ...props }) {
  return (
    <DialogPrimitive.Description
      data-slot="dialog-description"
      className={cn('text-muted-foreground text-sm', className)}
      {...props}
    />
  );
}

export {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogOverlay,
  DialogPortal,
  DialogTitle,
  DialogTrigger,
};



================================================
FILE: components/ui/base/drawer.tsx
================================================
'use client';

import * as React from 'react';
import { Drawer as DrawerPrimitive } from 'vaul';

import { cn } from '@/lib/styles';

const Drawer = ({ shouldScaleBackground = true, ...props }) => (
  <DrawerPrimitive.Root shouldScaleBackground={shouldScaleBackground} {...props} />
);
Drawer.displayName = 'Drawer';

const DrawerTrigger = DrawerPrimitive.Trigger;

const DrawerPortal = DrawerPrimitive.Portal;

const DrawerClose = DrawerPrimitive.Close;

type DrawerOverlayProps = React.HTMLAttributes<HTMLDivElement> & {
  className?: string;
};

const DrawerOverlay = React.forwardRef<HTMLDivElement, DrawerOverlayProps>(
  ({ className, ...props }, ref) => (
    <DrawerPrimitive.Overlay
      ref={ref}
      className={cn('fixed inset-0 z-50 bg-black/80', className)}
      {...props}
    />
  ),
);
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;

type DrawerContentProps = React.HTMLAttributes<HTMLDivElement> & {
  className?: string;
};

const DrawerContent = React.forwardRef<HTMLDivElement, DrawerContentProps>(
  ({ className, children, ...props }, ref) => (
    <DrawerPortal>
      <DrawerOverlay />
      <DrawerPrimitive.Content
        ref={ref}
        className={cn(
          'fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background',
          className,
        )}
        {...props}
      >
        <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
        {children}
      </DrawerPrimitive.Content>
    </DrawerPortal>
  ),
);
DrawerContent.displayName = 'DrawerContent';

const DrawerHeader = ({ className, ...props }) => (
  <div className={cn('grid gap-1.5 p-4 text-center sm:text-left', className)} {...props} />
);
DrawerHeader.displayName = 'DrawerHeader';

const DrawerFooter = ({ className, ...props }) => (
  <div className={cn('mt-auto flex flex-col gap-2 p-4', className)} {...props} />
);
DrawerFooter.displayName = 'DrawerFooter';

type DrawerTitleProps = React.HTMLAttributes<HTMLHeadingElement> & {
  className?: string;
};

const DrawerTitle = React.forwardRef<HTMLHeadingElement, DrawerTitleProps>(
  ({ className, ...props }, ref) => (
    <DrawerPrimitive.Title
      ref={ref}
      className={cn('text-lg font-semibold leading-none tracking-tight', className)}
      {...props}
    />
  ),
);
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;

type DrawerDescriptionProps = React.HTMLAttributes<HTMLParagraphElement> & {
  className?: string;
};

const DrawerDescription = React.forwardRef<HTMLParagraphElement, DrawerDescriptionProps>(
  ({ className, ...props }, ref) => (
    <DrawerPrimitive.Description
      ref={ref}
      className={cn('text-sm text-muted-foreground', className)}
      {...props}
    />
  ),
);
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;

export {
  Drawer,
  DrawerPortal,
  DrawerOverlay,
  DrawerTrigger,
  DrawerClose,
  DrawerContent,
  DrawerHeader,
  DrawerFooter,
  DrawerTitle,
  DrawerDescription,
};



================================================
FILE: components/ui/base/dropdown-menu.jsx
================================================
'use client';

import * as React from 'react';
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
import { Check, ChevronRight, Circle } from 'lucide-react';

import { cn } from '@/lib/styles';

const DropdownMenu = DropdownMenuPrimitive.Root;

const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;

const DropdownMenuGroup = DropdownMenuPrimitive.Group;

const DropdownMenuPortal = DropdownMenuPrimitive.Portal;

const DropdownMenuSub = DropdownMenuPrimitive.Sub;

const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;

const DropdownMenuSubTrigger = React.forwardRef(({ className, inset, children, ...props }, ref) => (
  <DropdownMenuPrimitive.SubTrigger
    ref={ref}
    className={cn(
      'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent data-[state=open]:bg-accent',
      inset && 'pl-8',
      className,
    )}
    {...props}
  >
    {children}
    <ChevronRight className="ml-auto h-4 w-4" />
  </DropdownMenuPrimitive.SubTrigger>
));
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;

const DropdownMenuSubContent = React.forwardRef(({ className, ...props }, ref) => (
  <DropdownMenuPrimitive.SubContent
    ref={ref}
    className={cn(
      'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
      className,
    )}
    {...props}
  />
));
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;

const DropdownMenuContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => (
  <DropdownMenuPrimitive.Portal>
    <DropdownMenuPrimitive.Content
      ref={ref}
      sideOffset={sideOffset}
      className={cn(
        'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
        className,
      )}
      {...props}
    />
  </DropdownMenuPrimitive.Portal>
));
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;

const DropdownMenuItem = React.forwardRef(({ className, inset, ...props }, ref) => (
  <DropdownMenuPrimitive.Item
    ref={ref}
    className={cn(
      'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
      inset && 'pl-8',
      className,
    )}
    {...props}
  />
));
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;

const DropdownMenuCheckboxItem = React.forwardRef(
  ({ className, children, checked, ...props }, ref) => (
    <DropdownMenuPrimitive.CheckboxItem
      ref={ref}
      className={cn(
        'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
        className,
      )}
      checked={checked}
      {...props}
    >
      <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
        <DropdownMenuPrimitive.ItemIndicator>
          <Check className="h-4 w-4" />
        </DropdownMenuPrimitive.ItemIndicator>
      </span>
      {children}
    </DropdownMenuPrimitive.CheckboxItem>
  ),
);
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;

const DropdownMenuRadioItem = React.forwardRef(({ className, children, ...props }, ref) => (
  <DropdownMenuPrimitive.RadioItem
    ref={ref}
    className={cn(
      'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50',
      className,
    )}
    {...props}
  >
    <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
      <DropdownMenuPrimitive.ItemIndicator>
        <Circle className="h-2 w-2 fill-current" />
      </DropdownMenuPrimitive.ItemIndicator>
    </span>
    {children}
  </DropdownMenuPrimitive.RadioItem>
));
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;

const DropdownMenuLabel = React.forwardRef(({ className, inset, ...props }, ref) => (
  <DropdownMenuPrimitive.Label
    ref={ref}
    className={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)}
    {...props}
  />
));
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;

const DropdownMenuSeparator = React.forwardRef(({ className, ...props }, ref) => (
  <DropdownMenuPrimitive.Separator
    ref={ref}
    className={cn('-mx-1 my-1 h-px bg-muted', className)}
    {...props}
  />
));
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;

const DropdownMenuShortcut = ({ className, ...props }) => {
  return (
    <span className={cn('ml-auto text-xs tracking-widest opacity-60', className)} {...props} />
  );
};
DropdownMenuShortcut.displayName = 'DropdownMenuShortcut';

export {
  DropdownMenu,
  DropdownMenuTrigger,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuCheckboxItem,
  DropdownMenuRadioItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuShortcut,
  DropdownMenuGroup,
  DropdownMenuPortal,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuRadioGroup,
};



================================================
FILE: components/ui/base/info-card.jsx
================================================
'use client';
import {
  useState,
  useRef,
  useEffect,
  createContext,
  useContext,
  useMemo,
  useCallback,
} from 'react';
import { motion, AnimatePresence } from 'motion/react';
import { cn } from '@/lib/styles';
import React from 'react';

const InfoCardTitle = React.memo(({ children, className, ...props }) => {
  return (
    <div className={cn('font-medium mb-1', className)} {...props}>
      {children}
    </div>
  );
});
InfoCardTitle.displayName = 'InfoCardTitle';

const InfoCardDescription = React.memo(({ children, className, ...props }) => {
  return (
    <div className={cn('text-muted-foreground leading-4', className)} {...props}>
      {children}
    </div>
  );
});
InfoCardDescription.displayName = 'InfoCardDescription';

const InfoCardContent = React.memo(({ children, className, ...props }) => {
  return (
    <div className={cn('flex flex-col gap-1 text-xs', className)} {...props}>
      {children}
    </div>
  );
});
InfoCardContent.displayName = 'InfoCardContent';

const InfoCardImageContext = createContext({
  handleMediaLoad: () => {},
  setAllImagesLoaded: () => {},
});

const InfoCardContext = createContext({
  isHovered: false,
  onDismiss: () => {},
});

function InfoCard({ children, className, storageKey, dismissType = 'once' }) {
  if (dismissType === 'forever' && !storageKey) {
    throw new Error('A storageKey must be provided when using dismissType="forever"');
  }

  const [isHovered, setIsHovered] = useState(false);
  const [allImagesLoaded, setAllImagesLoaded] = useState(true);
  const [isDismissed, setIsDismissed] = useState(() => {
    if (typeof window === 'undefined' || dismissType === 'once') return false;
    return dismissType === 'forever' ? localStorage.getItem(storageKey) === 'dismissed' : false;
  });

  const handleDismiss = useCallback(() => {
    setIsDismissed(true);
    if (dismissType === 'forever') {
      localStorage.setItem(storageKey, 'dismissed');
    }
  }, [storageKey, dismissType]);

  const imageContextValue = useMemo(
    () => ({
      handleMediaLoad: () => {},
      setAllImagesLoaded,
    }),
    [setAllImagesLoaded],
  );

  const cardContextValue = useMemo(
    () => ({
      isHovered,
      onDismiss: handleDismiss,
    }),
    [isHovered, handleDismiss],
  );

  return (
    <InfoCardContext.Provider value={cardContextValue}>
      <InfoCardImageContext.Provider value={imageContextValue}>
        <AnimatePresence>
          {!isDismissed && (
            <motion.div
              initial={{ opacity: 0, y: 10 }}
              animate={{
                opacity: allImagesLoaded ? 1 : 0,
                y: allImagesLoaded ? 0 : 10,
              }}
              exit={{
                opacity: 0,
                y: 10,
                transition: { duration: 0.2 },
              }}
              transition={{ duration: 0.3, delay: 0 }}
              className={cn(
                'group rounded-lg border p-3',
                'bg-white',
                'dark:bg-gradient-to-br dark:from-zinc-800 dark:to-zinc-900',
                'dark:border-zinc-700',
                className,
              )}
              onMouseEnter={() => setIsHovered(true)}
              onMouseLeave={() => setIsHovered(false)}
            >
              {children}
            </motion.div>
          )}
        </AnimatePresence>
      </InfoCardImageContext.Provider>
    </InfoCardContext.Provider>
  );
}

const InfoCardFooter = ({ children, className }) => {
  const { isHovered } = useContext(InfoCardContext);

  return (
    <motion.div
      className={cn('flex justify-between text-xs text-muted-foreground', className)}
      initial={{ opacity: 0, height: '0px' }}
      animate={{
        opacity: isHovered ? 1 : 0,
        height: isHovered ? 'auto' : '0px',
      }}
      transition={{
        type: 'spring',
        stiffness: 300,
        damping: 30,
        duration: 0.3,
      }}
    >
      {children}
    </motion.div>
  );
};

const InfoCardDismiss = React.memo(({ children, className, onDismiss, ...props }) => {
  const { onDismiss: contextDismiss } = useContext(InfoCardContext);

  const handleClick = e => {
    e.preventDefault();
    onDismiss?.();
    contextDismiss();
  };

  return (
    <div className={cn('cursor-pointer', className)} onClick={handleClick} {...props}>
      {children}
    </div>
  );
});
InfoCardDismiss.displayName = 'InfoCardDismiss';

const InfoCardAction = React.memo(({ children, className, ...props }) => {
  return (
    <div className={cn('', className)} {...props}>
      {children}
    </div>
  );
});
InfoCardAction.displayName = 'InfoCardAction';

// Memoized InfoCardMedia component to prevent unnecessary re-renders
const InfoCardMedia = React.memo(
  ({ media = [], className, loading = undefined, shrinkHeight = 75, expandHeight = 150 }) => {
    const { isHovered } = useContext(InfoCardContext);
    const { setAllImagesLoaded } = useContext(InfoCardImageContext);
    const [isOverflowVisible, setIsOverflowVisible] = useState(false);
    const loadedMedia = useRef(new Set());

    const handleMediaLoad = useCallback(
      mediaSrc => {
        loadedMedia.current.add(mediaSrc);
        if (loadedMedia.current.size === Math.min(3, media.slice(0, 3).length)) {
          setAllImagesLoaded(true);
        }
      },
      [media, setAllImagesLoaded],
    );

    const processedMedia = useMemo(
      () =>
        media.map(item => ({
          ...item,
          type: item.type || 'image',
        })),
      [media],
    );

    const displayMedia = useMemo(() => processedMedia.slice(0, 3), [processedMedia]);
    const mediaCount = useMemo(() => displayMedia.length, [displayMedia]);

    useEffect(() => {
      if (media.length > 0) {
        setAllImagesLoaded(false);
        loadedMedia.current.clear();
      } else {
        setAllImagesLoaded(true); // No media to load
      }
    }, [media.length, setAllImagesLoaded]);

    useEffect(() => {
      let timeoutId;
      if (isHovered) {
        timeoutId = setTimeout(() => {
          setIsOverflowVisible(true);
        }, 100);
      } else {
        setIsOverflowVisible(false);
      }
      return () => clearTimeout(timeoutId);
    }, [isHovered]);

    const getRotation = useCallback(
      index => {
        if (!isHovered || mediaCount === 1) return 0;
        return (index - (mediaCount === 2 ? 0.5 : 1)) * 5;
      },
      [isHovered, mediaCount],
    );

    const getTranslateX = useCallback(
      index => {
        if (!isHovered || mediaCount === 1) return 0;
        return (index - (mediaCount === 2 ? 0.5 : 1)) * 20;
      },
      [isHovered, mediaCount],
    );

    const getTranslateY = useCallback(
      index => {
        if (!isHovered) return 0;
        if (mediaCount === 1) return -5;
        return index === 0 ? -10 : index === 1 ? -5 : 0;
      },
      [isHovered, mediaCount],
    );

    const getScale = useCallback(
      index => {
        if (!isHovered) return 1;
        return mediaCount === 1 ? 1 : 0.95 + index * 0.02;
      },
      [isHovered, mediaCount],
    );

    const contextValue = useMemo(
      () => ({
        handleMediaLoad,
        setAllImagesLoaded,
      }),
      [handleMediaLoad, setAllImagesLoaded],
    );

    // Don't render anything if no media
    if (media.length === 0) {
      return null;
    }

    return (
      <InfoCardImageContext.Provider value={contextValue}>
        <motion.div
          className={cn('relative mt-2 rounded-md', className)}
          animate={{
            height: isHovered ? expandHeight : shrinkHeight,
          }}
          style={{
            overflow: isOverflowVisible ? 'visible' : 'hidden',
          }}
          transition={{
            type: 'spring',
            stiffness: 300,
            damping: 30,
            duration: 0.3,
          }}
        >
          <div className={cn('relative', { height: shrinkHeight })}>
            {displayMedia.map((item, index) => {
              const { type, src, alt, className: itemClassName, ...mediaProps } = item;

              return (
                <motion.div
                  key={src}
                  className="absolute w-full"
                  animate={{
                    rotateZ: getRotation(index),
                    x: getTranslateX(index),
                    y: getTranslateY(index),
                    scale: getScale(index),
                  }}
                  transition={{
                    type: 'spring',
                    stiffness: 300,
                    damping: 30,
                  }}
                >
                  {type === 'video' ? (
                    <video
                      src={src}
                      className={cn(
                        'w-full rounded-md border border-gray-200 dark:border-zinc-700/10 object-cover shadow-lg',
                        itemClassName,
                      )}
                      onLoadedData={() => handleMediaLoad(src)}
                      preload="metadata"
                      muted
                      playsInline
                      {...mediaProps}
                    />
                  ) : (
                    <img
                      src={src}
                      alt={alt}
                      className={cn(
                        'w-full rounded-md border border-gray-200 dark:border-zinc-700/10 object-cover shadow-lg',
                        itemClassName,
                      )}
                      onLoad={() => handleMediaLoad(src)}
                      loading={loading}
                      {...mediaProps}
                    />
                  )}
                </motion.div>
              );
            })}
          </div>
        </motion.div>
      </InfoCardImageContext.Provider>
    );
  },
);
InfoCardMedia.displayName = 'InfoCardMedia';

export {
  InfoCard,
  InfoCardTitle,
  InfoCardDescription,
  InfoCardContent,
  InfoCardMedia,
  InfoCardFooter,
  InfoCardDismiss,
  InfoCardAction,
};



================================================
FILE: components/ui/base/input.tsx
================================================
import * as React from 'react';

import { cn } from '@/lib/styles';

type InputProps = React.InputHTMLAttributes<HTMLInputElement> & {
  className?: string;
};

const Input = React.forwardRef<HTMLInputElement, InputProps>(
  ({ className, type, ...props }, ref) => {
    return (
      <input
        type={type}
        className={cn(
          'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 ring-0',
          className,
        )}
        ref={ref}
        {...props}
      />
    );
  },
);
Input.displayName = 'Input';

export { Input };



================================================
FILE: components/ui/base/koel-bird-rounded.jsx
================================================
import * as React from 'react';

const KoelBirdRounded = ({ className, ...props }) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    width="1451"
    height="1437"
    fill="none"
    viewBox="0 0 1451 1437"
    className={className}
    {...props}
  >
    <rect
      width="344.708"
      height="691.027"
      x="1126.33"
      y="622.273"
      fill="#154063"
      rx="172.354"
      transform="rotate(90 1126.33 622.273)"
    ></rect>
    <rect
      width="344.708"
      height="691.027"
      x="1096.52"
      y="1040.12"
      fill="#3779B5"
      rx="172.354"
      transform="rotate(135 1096.52 1040.12)"
    ></rect>
    <mask
      id="mask0_3666_266"
      width="692"
      height="345"
      x="435"
      y="622"
      maskUnits="userSpaceOnUse"
      style={{ maskType: 'alpha' }}
    >
      <rect
        width="344.708"
        height="691.027"
        x="1126.33"
        y="622.273"
        fill="#fff"
        rx="172.354"
        transform="rotate(90 1126.33 622.273)"
      ></rect>
    </mask>
    <g mask="url(#mask0_3666_266)">
      <rect
        width="344.708"
        height="691.027"
        x="1096.52"
        y="1040.12"
        fill="#122438"
        rx="172.354"
        transform="rotate(135 1096.52 1040.12)"
      ></rect>
    </g>
    <path
      fill="#000"
      d="M501.589 575.579c-89.244-33.111-171.24-236.2-167.598-246.017 3.642-9.816 198.261-110.275 287.504-77.164s134.749 132.3 101.637 221.544-132.3 134.748-221.543 101.637"
    ></path>
  </svg>
);

export default KoelBirdRounded;



================================================
FILE: components/ui/base/koel-labs-bird.jsx
================================================
import React from 'react';
import { cn } from '@/lib/styles';

export default function KoelBird({ className }) {
  return (
    <div>
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width="870"
        height="870"
        fill="none"
        viewBox="0 0 870 870"
        className={'hidden h-0 w-0 dark:inline-block ' + cn(className)}
      >
        <rect
          width="214"
          height="429"
          x="671.178"
          y="403"
          fill="url(#paint0_linear_1675_354)"
          fillOpacity="0.6"
          rx="107"
          transform="rotate(90 671.178 403)"
        ></rect>
        <rect
          width="214"
          height="429"
          x="671.18"
          y="403"
          fill="url(#paint1_linear_1675_354)"
          fillOpacity="0.6"
          rx="107"
          transform="rotate(90 671.18 403)"
        ></rect>
        <rect
          width="214"
          height="429"
          x="652.67"
          y="662.406"
          fill="url(#paint2_linear_1675_354)"
          fillOpacity="0.6"
          rx="107"
          transform="rotate(135 652.67 662.406)"
        ></rect>
        <rect
          width="214"
          height="429"
          x="652.67"
          y="662.406"
          fill="url(#paint3_linear_1675_354)"
          fillOpacity="0.6"
          rx="107"
          transform="rotate(135 652.67 662.406)"
        ></rect>
        <path
          fill="#fff"
          d="M349.176 383c-59.095 0-150.677-100.5-150.677-107s91.582-107 150.677-107c59.094 0 107 47.906 107 107s-47.906 107-107 107z"
        ></path>
        <defs>
          <linearGradient
            id="paint0_linear_1675_354"
            x1="778.178"
            x2="778.178"
            y1="403"
            y2="832"
            gradientUnits="userSpaceOnUse"
          >
            <stop></stop>
            <stop offset="1" stopColor="#fff"></stop>
          </linearGradient>
          <linearGradient
            id="paint1_linear_1675_354"
            x1="778.18"
            x2="778.18"
            y1="403"
            y2="832"
            gradientUnits="userSpaceOnUse"
          >
            <stop></stop>
            <stop offset="1" stopColor="#fff"></stop>
          </linearGradient>
          <linearGradient
            id="paint2_linear_1675_354"
            x1="759.67"
            x2="759.67"
            y1="662.406"
            y2="1091.41"
            gradientUnits="userSpaceOnUse"
          >
            <stop></stop>
            <stop offset="1" stopColor="#fff"></stop>
          </linearGradient>
          <linearGradient
            id="paint3_linear_1675_354"
            x1="759.67"
            x2="759.67"
            y1="662.406"
            y2="1091.41"
            gradientUnits="userSpaceOnUse"
          >
            <stop></stop>
            <stop offset="1" stopColor="#fff"></stop>
          </linearGradient>
        </defs>
      </svg>
      <svg
        xmlns="http://www.w3.org/2000/svg"
        width="870"
        height="870"
        fill="none"
        viewBox="0 0 870 870"
        className={'inline-block dark:hidden dark:h-0 dark:w-0 ' + cn(className)}
      >
        <rect
          width="214"
          height="429"
          x="671.179"
          y="403"
          fill="url(#paint0_linear_1691_806)"
          fillOpacity="0.6"
          rx="107"
          transform="rotate(90 671.179 403)"
        ></rect>
        <rect
          width="214"
          height="429"
          x="652.67"
          y="662.406"
          fill="url(#paint1_linear_1691_806)"
          fillOpacity="0.6"
          rx="107"
          transform="rotate(135 652.67 662.406)"
        ></rect>
        <rect
          width="214"
          height="429"
          x="671.179"
          y="403"
          fill="url(#paint2_linear_1691_806)"
          fillOpacity="0.6"
          rx="107"
          transform="rotate(90 671.179 403)"
        ></rect>
        <rect
          width="214"
          height="429"
          x="652.67"
          y="662.406"
          fill="url(#paint3_linear_1691_806)"
          fillOpacity="0.6"
          rx="107"
          transform="rotate(135 652.67 662.406)"
        ></rect>
        <rect
          width="214"
          height="429"
          x="671.179"
          y="403"
          fill="url(#paint4_linear_1691_806)"
          fillOpacity="0.6"
          rx="107"
          transform="rotate(90 671.179 403)"
        ></rect>
        <rect
          width="214"
          height="429"
          x="652.67"
          y="662.406"
          fill="url(#paint5_linear_1691_806)"
          fillOpacity="0.6"
          rx="107"
          transform="rotate(135 652.67 662.406)"
        ></rect>
        <path
          fill="#000"
          d="M283.332 374.002c-55.404-20.556-106.308-146.637-104.047-152.731 2.261-6.094 123.083-68.461 178.487-47.905 55.404 20.556 83.654 82.134 63.098 137.538-20.556 55.404-82.134 83.654-137.538 63.098z"
        ></path>
        <defs>
          <linearGradient
            id="paint0_linear_1691_806"
            x1="778.179"
            x2="778.179"
            y1="403"
            y2="832"
            gradientUnits="userSpaceOnUse"
          >
            <stop stopColor="#317EC5"></stop>
            <stop offset="1"></stop>
          </linearGradient>
          <linearGradient
            id="paint1_linear_1691_806"
            x1="759.67"
            x2="759.67"
            y1="662.406"
            y2="1091.41"
            gradientUnits="userSpaceOnUse"
          >
            <stop stopColor="#317EC5"></stop>
            <stop offset="1"></stop>
          </linearGradient>
          <linearGradient
            id="paint2_linear_1691_806"
            x1="778.179"
            x2="778.179"
            y1="403"
            y2="832"
            gradientUnits="userSpaceOnUse"
          >
            <stop stopColor="#317EC5"></stop>
            <stop offset="1"></stop>
          </linearGradient>
          <linearGradient
            id="paint3_linear_1691_806"
            x1="759.67"
            x2="759.67"
            y1="662.406"
            y2="1091.41"
            gradientUnits="userSpaceOnUse"
          >
            <stop stopColor="#317EC5"></stop>
            <stop offset="1"></stop>
          </linearGradient>
          <linearGradient
            id="paint4_linear_1691_806"
            x1="778.179"
            x2="778.179"
            y1="403"
            y2="832"
            gradientUnits="userSpaceOnUse"
          >
            <stop stopColor="#317EC5"></stop>
            <stop offset="1"></stop>
          </linearGradient>
          <linearGradient
            id="paint5_linear_1691_806"
            x1="759.67"
            x2="759.67"
            y1="662.406"
            y2="1091.41"
            gradientUnits="userSpaceOnUse"
          >
            <stop stopColor="#317EC5"></stop>
            <stop offset="1"></stop>
          </linearGradient>
        </defs>
      </svg>
    </div>
  );
}



================================================
FILE: components/ui/base/label.tsx
================================================
'use client';

import * as React from 'react';
import type { ComponentPropsWithoutRef } from 'react';

import * as LabelPrimitive from '@radix-ui/react-label';
import { cva } from 'class-variance-authority';

import { cn } from '@/lib/styles';

const labelVariants = cva(
  'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
);

type LabelProps = ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & {
  className?: string;
};

const Label = React.forwardRef<HTMLLabelElement, LabelProps>(({ className, ...props }, ref) => (
  <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
));
Label.displayName = LabelPrimitive.Root.displayName;

export { Label };



================================================
FILE: components/ui/base/model-svg.tsx
================================================
import React from 'react';

export default function ModelSvg() {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      width="580"
      height="579"
      fill="none"
      viewBox="0 0 580 579"
    >
      <g clipPath="url(#clip0_3893_337)">
        <rect width="580" height="579" fill="#fff" rx="22"></rect>
        <g filter="url(#filter0_d_3893_337)">
          <rect
            width="284.951"
            height="284.951"
            fill="#F7F7F7"
            rx="49.747"
            transform="scale(1.22477 .70706)rotate(-45 541.78 178.225)"
          ></rect>
          <rect
            width="283.707"
            height="283.707"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="49.125"
            transform="scale(1.22477 .70706)rotate(-45 542.758 178.464)"
          ></rect>
        </g>
        <g filter="url(#filter1_d_3893_337)">
          <rect
            width="251.286"
            height="251.286"
            fill="#fff"
            rx="32.335"
            transform="scale(1.22477 .70706)rotate(-45 496.761 125.903)"
          ></rect>
          <rect
            width="250.042"
            height="250.042"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="31.714"
            transform="scale(1.22477 .70706)rotate(-45 497.739 126.142)"
          ></rect>
        </g>
        <path
          fill="#A6A6A6"
          d="M239.844 295.939c-4.142 2.391-9.421 2.267-13.734-.222-4.241-2.449-4.563-5.6-.626-7.872 3.382-1.953 8.401-2.402 13.224.382l.009.005c.635.367.635.77 0 1.137l-8.59 4.958c2.38 1.343 5.145 1.338 7.239.129 1.073-.62 1.601-1.338 1.449-2.055-.107-.465-.018-.786.6-1.07l1.216-.558c.77-.351 1.504-.34 1.79.083 1.065 1.586.233 3.461-2.577 5.083m-11.891-2.877 6.46-3.73c-1.888-1.069-4.5-1.131-6.361-.056-1.933 1.115-1.754 2.716-.099 3.786m21.217-3.953c.635.366.635.769 0 1.136l-1.271.734a1.9 1.9 0 0 1-1.968 0l-11.775-6.798c-.635-.367-.635-.77 0-1.136l1.128-.651a1.9 1.9 0 0 1 1.968 0l1.351.78.161-.093c-.904-1.245-.474-2.629 1.584-3.817 2.836-1.638 6.594-1.638 9.878.268l7.766 4.484c.635.367.635.769 0 1.136l-1.271.734a1.9 1.9 0 0 1-1.968 0l-7.265-4.195c-1.834-1.058-3.937-1.115-5.61-.149-1.709.986-1.763 2.339.223 3.486zm23.004-5.863c-2.881 1.663-5.78 2.128-8.124 1.808-.931-.134-1.119-.594-.618-1.069l.796-.749c.421-.398.958-.481 1.763-.45 1.074.031 2.389-.181 3.785-.986 1.843-1.064 2.353-2.32.331-3.487l-2.604-1.503-.161.093c.51.873.671 2.237-1.682 3.595-3.167 1.829-7.9 1.978-12.383-.609-4.518-2.609-4.509-5.486-1.333-7.32 2.425-1.399 4.912-1.152 6.397-.862l.179-.104-1.288-.743c-.636-.367-.636-.77 0-1.137l1.225-.707a1.9 1.9 0 0 1 1.969 0l12.982 7.494c3.517 2.03 2.479 4.592-1.234 6.736m-15.613-5.274c2.532 1.462 5.323 1.772 7.462.537 2.066-1.193 1.655-2.773-.967-4.287-2.603-1.503-5.475-1.839-7.56-.635-2.156 1.245-1.432 2.944 1.065 4.385m20.686-5.072c.635.366.635.769 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.969 0l-16.355-9.443c-.636-.366-.636-.769 0-1.136l1.27-.733a1.9 1.9 0 0 1 1.968 0zm-11.262-10.482c-1.038.599-2.666.63-3.633.072-.975-.563-.921-1.503.117-2.102 1.029-.594 2.657-.625 3.632-.062.967.558.913 1.498-.116 2.092m13.081 9.432-11.775-6.798c-.635-.367-.635-.769 0-1.136l1.271-.734a1.9 1.9 0 0 1 1.968 0l11.775 6.798c.635.367.635.769 0 1.136l-1.271.734a1.9 1.9 0 0 1-1.968 0m4.915-13.106c-.501.361-1.056.392-1.861.31a5.37 5.37 0 0 0-3.141.697c-1.351.78-1.736 1.746-.796 2.278.787.465 1.825.424 3.534-.201l2.845-1.065c3.159-1.172 5.619-1.208 7.588-.082 2.594 1.508 1.95 3.936-1.486 5.919-2.881 1.663-5.941 2.17-8.598 1.514-.895-.217-.957-.687-.349-1.111l1.109-.775c.519-.361 1.074-.382 1.888-.273 1.181.155 2.371-.109 3.499-.76 1.539-.888 1.852-1.885.912-2.427-.778-.45-1.879-.403-3.417.165l-2.837 1.069c-3.185 1.209-5.744 1.157-7.739-.005-2.55-1.462-1.924-3.704 1.387-5.615 2.711-1.565 5.52-1.968 7.99-1.41.903.212.993.677.384 1.111zm15.698 1.206c.635.366.635.769 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.969 0l-16.356-9.443c-.635-.366-.635-.769 0-1.136l1.199-.692a1.9 1.9 0 0 1 1.969 0l5.932 3.425.161-.093c-.922-1.266-.537-2.593 1.575-3.812 2.854-1.648 6.585-1.664 9.904.253l7.767 4.483c.635.367.635.77 0 1.137l-1.271.733a1.9 1.9 0 0 1-1.968 0l-7.266-4.194c-1.852-1.069-3.936-1.116-5.636-.135-1.736 1.003-1.826 2.377.161 3.523zm12.732-14.623c.636.366.636.769 0 1.136l-6.281 3.626a1.9 1.9 0 0 1-1.968 0l-.698-.403c-.635-.367-.635-.769 0-1.136l6.281-3.626a1.9 1.9 0 0 1 1.969 0zm16.265-.578c-4.42 2.552-10.549 2.061-16.553-1.405-5.977-3.46-6.773-6.978-2.371-9.519s10.513-2.082 16.49 1.368c6.013 3.472 6.863 7.01 2.434 9.556m-13.198-3.342c4.394 2.547 8.116 3.043 10.397 1.726 2.291-1.323 1.423-3.466-2.979-6.008-4.375-2.515-8.098-3.021-10.379-1.704-2.273 1.312-1.396 3.46 2.961 5.986m27.838-6.649c.635.367.635.77 0 1.136l-1.351.78a1.9 1.9 0 0 1-1.968 0l-14.11-8.145-.108.062-1.118 2.928c-.242.636-1.047.77-1.843.31l-.859-.495c-.528-.305-.698-.62-.537-1.054l1.199-3.182c.143-.382.385-.635.859-.909l1.512-.873a1.9 1.9 0 0 1 1.968 0z"
        ></path>
        <g filter="url(#filter2_f_3893_337)" style={{ mixBlendMode: 'color' }}>
          <path
            fill="#0086FF"
            d="M-75 442.508c0-265.373 229.678-480.5 513-480.5s513 215.127 513 480.5-229.678 480.5-513 480.5c-136.279 0-215.453-80.473-307.319-161.669C31.559 673.729-75 580.235-75 442.508"
          ></path>
        </g>
        <g filter="url(#filter3_f_3893_337)" style={{ mixBlendMode: 'color' }}>
          <path
            fill="#0086FF"
            d="M522 714.008c0-265.649 229.902-481 513.5-481 283.6 0 513.5 215.351 513.5 481s-229.9 481.002-513.5 481.002c-136.412 0-215.663-80.56-307.618-161.84C628.663 945.47 522 851.879 522 714.008"
          ></path>
        </g>
        <g filter="url(#filter4_f_3893_337)" style={{ mixBlendMode: 'color' }}>
          <path
            fill="#0086FF"
            d="M-647-127.992c0-265.649 229.902-481 513.5-481s513.5 215.351 513.5 481-229.902 481-513.5 481c-136.412 0-215.663-80.557-307.618-161.837C-540.337 103.47-647 9.879-647-127.992"
          ></path>
        </g>
        <g filter="url(#filter5_f_3893_337)" style={{ mixBlendMode: 'color' }}>
          <path
            fill="#2A4BCC"
            d="M25.912 139.936C271.44 272.717 355.564 566.796 213.807 796.78c-141.756 229.98-455.712 308.78-701.24 176.001C-732.96 840-817.084 545.921-675.328 315.937c68.185-110.623 182.253-134.627 303.341-168.571 130.653-36.626 270.47-76.344 397.899-7.43"
          ></path>
        </g>
        <g filter="url(#filter6_f_3893_337)" style={{ mixBlendMode: 'color' }}>
          <path
            fill="#2A4BCC"
            d="M1389.43-386.752c245.53 132.781 329.66 426.86 187.9 656.845-141.75 229.984-455.71 308.782-701.238 176.001C630.563 313.312 546.439 19.233 688.195-210.751c68.185-110.623 182.254-134.627 303.342-168.571 130.653-36.625 270.473-76.343 397.893-7.43"
          ></path>
        </g>
        <g filter="url(#filter7_f_3893_337)" style={{ mixBlendMode: 'color' }}>
          <path
            fill="#002E72"
            d="M143.61 473.356c221.637-165.6 544.628-131.548 721.421 76.057 176.789 207.606 140.439 510.147-81.198 675.747s-544.629 131.55-721.421-76.06c-85.038-99.85-67.233-208.087-56.743-326.071C16.988 695.726 28.581 559.302 143.61 473.356"
          ></path>
        </g>
        <g filter="url(#filter8_f_3893_337)" style={{ mixBlendMode: 'color' }}>
          <path
            fill="#002E72"
            d="M118.172-648.152c221.637-165.6 544.629-131.548 721.422 76.057 176.796 207.606 140.439 510.15-81.198 675.749-221.638 165.6-544.629 131.548-721.422-76.057-85.038-99.859-67.232-208.091-56.742-326.075C-8.45-425.782 3.143-562.206 118.172-648.152"
          ></path>
        </g>
        <g filter="url(#filter9_d_3893_337)">
          <rect
            width="284.951"
            height="284.951"
            fill="#F7F7F7"
            rx="49.747"
            transform="matrix(.86604 -.49997 .86604 .49997 340 107.656)"
          ></rect>
          <rect
            width="283.707"
            height="283.707"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="49.125"
            transform="scale(1.22477 .70706)rotate(-45 323.573 -258.728)"
          ></rect>
        </g>
        <g filter="url(#filter10_d_3893_337)">
          <rect
            width="251.286"
            height="251.286"
            fill="#fff"
            rx="32.335"
            transform="scale(1.22477 .70706)rotate(-45 277.948 -311.135)"
          ></rect>
          <rect
            width="250.042"
            height="250.042"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="31.714"
            transform="scale(1.22477 .70706)rotate(-45 278.927 -310.896)"
          ></rect>
        </g>
        <path
          fill="#A6A6A6"
          d="M516.152 89.137c-.636-.366-.636-.77 0-1.136l1.27-.733a1.9 1.9 0 0 1 1.969 0l9.117 5.263.224-.13-.528-5.448c-.045-.419.161-.713.671-1.008l1.431-.826c.859-.496 1.682-.32 1.754.382l.483 5.176 11.381 1.064c1.136.108 1.405.573.591 1.043l-1.647.95c-.528.305-1.073.403-1.807.331l-9.028-.862.081 1.41 3.632 2.097c.636.366.636.77 0 1.136l-1.27.733a1.9 1.9 0 0 1-1.969 0zm35.87-.377c-4.027 2.325-9.422 2.164-13.672-.29-4.259-2.458-4.545-5.578-.519-7.902 4.027-2.324 9.431-2.159 13.69.3 4.25 2.453 4.527 5.568.501 7.892m-10.397-2.19c2.514 1.452 5.592 1.968 7.82.682 2.192-1.266 1.297-3.042-1.217-4.494s-5.619-1.983-7.811-.718c-2.228 1.286-1.306 3.079 1.208 4.53m24.303-5.838c-4.142 2.391-9.421 2.267-13.734-.222-4.241-2.449-4.563-5.6-.626-7.872 3.382-1.953 8.402-2.402 13.224.382l.009.005c.635.367.635.77 0 1.137l-8.589 4.958c2.38 1.343 5.144 1.338 7.238.13 1.074-.62 1.602-1.338 1.45-2.056-.108-.465-.018-.785.599-1.07l1.217-.557c.769-.352 1.503-.341 1.789.082 1.065 1.586.233 3.46-2.577 5.083m-11.891-2.877 6.46-3.73c-1.887-1.069-4.5-1.13-6.361-.056-1.933 1.115-1.754 2.717-.099 3.786m21.217-3.953c.635.367.635.77 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.969 0L555.66 66.33c-.636-.367-.636-.77 0-1.137l1.27-.733a1.9 1.9 0 0 1 1.968 0zm5.058-2.92c.635.367.635.77 0 1.136l-1.271.734a1.9 1.9 0 0 1-1.968 0l-16.356-9.442c-.635-.367-.635-.77 0-1.137l1.271-.733a1.9 1.9 0 0 1 1.968 0zm7.035-2.605c-2.621 1.514-6.03 1.829-8.732.269-3.096-1.787-1.343-3.72 1.037-5.424 2.166-1.55 3.096-2.138 2.166-2.675l-.054-.031c-1.351-.78-2.944-.75-4.447.118-1.154.667-1.521 1.374-1.405 1.99.108.464.027.779-.617 1.058l-1.235.537c-.787.341-1.592.258-1.888-.294-.85-1.617.188-3.29 2.649-4.711 2.621-1.513 6.675-2.593 10.307-.496l8.214 4.742c.635.367.635.77 0 1.136l-1.145.661c-.636.367-1.325.372-1.933.021l-.94-.542-.107.062c.564 1.007.286 2.334-1.87 3.58m-5.664-1.565c1.19.687 2.774.486 4.125-.294 1.951-1.126 1.888-2.588.358-3.471l-1.619-.935c-.081.439-1.566 1.544-2.3 2.102-1.244.956-1.807 1.88-.564 2.598m-2.809-13.884c-.635-.367-.635-.77 0-1.137l1.271-.733a1.9 1.9 0 0 1 1.968 0l5.87 3.388.134-.077c-.501-.858-.948-2.283 1.476-3.683 3.177-1.834 8.16-1.839 12.741.806 4.527 2.613 4.671 5.496 1.432 7.365-2.362 1.364-4.832 1.168-6.344.884l-.188.108 1.181.682c.636.367.636.77 0 1.136l-1.217.703a1.9 1.9 0 0 1-1.968 0zm13.645 4.21c2.666 1.539 5.619 1.9 7.686.707 2.138-1.234 1.387-2.97-1.19-4.458-2.559-1.477-5.503-1.895-7.659-.65-2.085 1.203-1.503 2.861 1.163 4.4m16.783-13.16c-.501.36-1.056.392-1.861.31a5.36 5.36 0 0 0-3.14.697c-1.351.78-1.736 1.745-.797 2.277.788.465 1.826.424 3.535-.201l2.845-1.064c3.158-1.173 5.619-1.209 7.587-.083 2.595 1.508 1.951 3.936-1.485 5.92-2.881 1.663-5.941 2.17-8.598 1.513-.895-.217-.958-.687-.349-1.11l1.109-.775c.519-.362 1.074-.382 1.888-.274 1.181.155 2.371-.108 3.498-.76 1.539-.888 1.852-1.885.913-2.427-.778-.45-1.879-.403-3.418.165l-2.836 1.07c-3.185 1.208-5.744 1.157-7.74-.006-2.55-1.461-1.923-3.703 1.387-5.614 2.711-1.565 5.521-1.968 7.99-1.41.904.211.993.676.385 1.11z"
        ></path>
        <g filter="url(#filter11_d_3893_337)">
          <rect
            width="284.951"
            height="284.951"
            fill="#F7F7F7"
            rx="49.747"
            transform="scale(1.22477 .70706)rotate(-45 760.552 615.246)"
          ></rect>
          <rect
            width="283.707"
            height="283.707"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="49.125"
            transform="scale(1.22477 .70706)rotate(-45 761.53 615.486)"
          ></rect>
        </g>
        <g filter="url(#filter12_d_3893_337)">
          <rect
            width="251.286"
            height="251.286"
            fill="#fff"
            rx="32.335"
            transform="scale(1.22477 .70706)rotate(-45 715.892 563.073)"
          ></rect>
          <rect
            width="250.042"
            height="250.042"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="31.714"
            transform="scale(1.22477 .70706)rotate(-45 716.871 563.312)"
          ></rect>
        </g>
        <path
          fill="#A6A6A6"
          d="M-70.086 500.361c-4.142 2.391-9.421 2.267-13.734-.222-4.24-2.449-4.563-5.6-.626-7.872 3.382-1.953 8.402-2.402 13.224.382l.01.005c.634.367.634.77 0 1.136l-8.59 4.959c2.38 1.343 5.144 1.338 7.238.129 1.074-.62 1.602-1.338 1.45-2.056-.108-.464-.018-.785.599-1.069l1.217-.558c.77-.351 1.503-.341 1.79.083 1.064 1.586.232 3.461-2.578 5.083m-11.89-2.877 6.46-3.73c-1.888-1.069-4.501-1.131-6.362-.057-1.933 1.116-1.754 2.717-.099 3.787m21.216-3.953c.635.366.635.769 0 1.136l-1.27.733a1.9 1.9 0 0 1-1.969 0l-11.774-6.797c-.636-.367-.636-.77 0-1.136l1.127-.651a1.9 1.9 0 0 1 1.968 0l1.351.78.161-.093c-.903-1.245-.474-2.629 1.584-3.817 2.836-1.638 6.594-1.638 9.878.268l7.766 4.484c.635.366.635.769 0 1.136l-1.27.733a1.9 1.9 0 0 1-1.969 0l-7.265-4.194c-1.834-1.059-3.937-1.115-5.61-.15-1.709.987-1.762 2.34.224 3.487zm23.004-5.863c-2.881 1.663-5.78 2.128-8.124 1.808-.93-.135-1.119-.594-.617-1.07l.796-.748c.42-.398.957-.481 1.762-.45 1.074.031 2.39-.181 3.785-.986 1.843-1.064 2.353-2.32.331-3.487l-2.603-1.503-.162.093c.51.873.672 2.236-1.682 3.595-3.167 1.828-7.9 1.978-12.383-.61-4.518-2.608-4.51-5.485-1.333-7.319 2.425-1.4 4.912-1.152 6.397-.862l.18-.104-1.289-.743c-.635-.367-.635-.77 0-1.137l1.226-.707a1.9 1.9 0 0 1 1.968 0l12.983 7.494c3.516 2.03 2.478 4.592-1.235 6.736m-15.613-5.274c2.532 1.462 5.324 1.772 7.462.537 2.067-1.193 1.655-2.773-.966-4.287-2.604-1.503-5.476-1.839-7.56-.635-2.157 1.245-1.432 2.944 1.064 4.385m20.686-5.072c.636.366.636.769 0 1.136l-1.27.733a1.9 1.9 0 0 1-1.968 0l-16.356-9.442c-.635-.366-.635-.769 0-1.136l1.27-.734a1.9 1.9 0 0 1 1.969 0zm-11.262-10.482c-1.038.599-2.666.63-3.632.072-.976-.563-.922-1.503.116-2.102 1.029-.594 2.657-.625 3.633-.062.966.558.912 1.498-.117 2.092m13.081 9.432-11.774-6.798c-.636-.367-.636-.77 0-1.136l1.27-.734a1.9 1.9 0 0 1 1.969 0l11.774 6.798c.636.366.636.769 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.969 0m4.915-13.106c-.501.361-1.056.392-1.861.31a5.36 5.36 0 0 0-3.14.697c-1.352.78-1.736 1.746-.797 2.278.788.465 1.825.423 3.534-.202l2.846-1.064c3.158-1.172 5.619-1.208 7.587-.082 2.595 1.508 1.95 3.936-1.485 5.919-2.881 1.663-5.941 2.17-8.599 1.514-.895-.217-.957-.687-.349-1.111l1.11-.775c.519-.361 1.074-.382 1.888-.274 1.18.155 2.37-.108 3.498-.759 1.539-.888 1.852-1.885.913-2.428-.779-.449-1.88-.402-3.418.166l-2.836 1.069c-3.186 1.209-5.745 1.157-7.74-.005-2.55-1.462-1.924-3.704 1.387-5.615 2.711-1.565 5.52-1.968 7.99-1.41.904.212.993.677.385 1.111zm15.698 1.206c.636.366.636.769 0 1.136l-1.27.733a1.9 1.9 0 0 1-1.969 0l-16.355-9.442c-.636-.366-.636-.769 0-1.136l1.199-.692a1.9 1.9 0 0 1 1.968 0l5.932 3.424.161-.093c-.921-1.265-.537-2.593 1.575-3.812 2.854-1.647 6.585-1.663 9.905.254l7.766 4.483c.635.367.635.77 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.97 0l-7.264-4.194c-1.852-1.07-3.937-1.116-5.637-.135-1.736 1.002-1.825 2.376.161 3.523zm12.733-14.623c.635.366.635.769 0 1.136l-6.281 3.626a1.9 1.9 0 0 1-1.969 0l-.698-.403c-.635-.367-.635-.77 0-1.136l6.281-3.626a1.9 1.9 0 0 1 1.969 0zm-8.019-6.983c-.635-.367-.635-.769 0-1.136l6.03-3.482c3.973-2.293 7.964-2.262 10.693-.687 2.227 1.287 2.066 2.826.697 4.102l.18.103c2.048-1.069 5.645-1.266 8.419.336 2.854 1.647 2.935 4.07-1.262 6.492l-6.433 3.714a1.9 1.9 0 0 1-1.968 0zm17.886 6.493 3.57-2.061c2.407-1.389 2.389-2.557.93-3.399-1.637-.945-4.16-.935-6.21.248L6.98 446.16zm-7.758-4.478 3.284-1.896c1.727-.997 2.031-2.33.42-3.259-1.413-.816-3.453-.827-5.404.299l-3.355 1.937zm29.203-4.297c-4.42 2.552-10.55 2.061-16.553-1.405-5.977-3.46-6.773-6.978-2.371-9.519s10.513-2.082 16.49 1.368c6.012 3.472 6.862 7.01 2.434 9.556m-13.198-3.342c4.393 2.547 8.115 3.043 10.397 1.725 2.29-1.322 1.423-3.465-2.98-6.007-4.375-2.515-8.097-3.021-10.378-1.704-2.273 1.312-1.396 3.46 2.961 5.986"
        ></path>
        <g filter="url(#filter13_d_3893_337)">
          <rect
            width="284.951"
            height="284.951"
            fill="#F7F7F7"
            rx="49.747"
            transform="scale(1.22477 .70706)rotate(-45 71.921 346.172)"
          ></rect>
          <rect
            width="283.707"
            height="283.707"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="49.125"
            transform="scale(1.22477 .70706)rotate(-45 72.9 346.411)"
          ></rect>
        </g>
        <g filter="url(#filter14_d_3893_337)">
          <rect
            width="251.286"
            height="251.286"
            fill="#fff"
            rx="32.335"
            transform="scale(1.22477 .70706)rotate(-45 27.316 294.02)"
          ></rect>
          <rect
            width="250.042"
            height="250.042"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="31.714"
            transform="scale(1.22477 .70706)rotate(-45 28.294 294.26)"
          ></rect>
        </g>
        <path
          fill="#A6A6A6"
          d="M-79.96 98.384c-4.143 2.392-9.422 2.268-13.735-.222-4.24-2.448-4.563-5.6-.626-7.872 3.382-1.952 8.402-2.402 13.224.382l.01.005c.634.367.634.77 0 1.137l-8.59 4.959c2.38 1.343 5.144 1.337 7.238.129 1.074-.62 1.602-1.338 1.45-2.056-.108-.465-.018-.785.599-1.07l1.217-.557c.77-.351 1.503-.341 1.79.082 1.064 1.586.232 3.461-2.578 5.083m-11.892-2.877 6.46-3.73c-1.887-1.069-4.5-1.13-6.361-.056-1.933 1.115-1.754 2.717-.099 3.786m21.217-3.953c.635.367.635.77 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.969 0l-11.774-6.798c-.636-.366-.636-.77 0-1.136l1.127-.65a1.9 1.9 0 0 1 1.968 0l1.351.78.161-.094c-.903-1.245-.474-2.629 1.584-3.817 2.836-1.637 6.594-1.637 9.878.269l7.766 4.483c.635.367.635.77 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.969 0l-7.265-4.194c-1.834-1.06-3.937-1.116-5.61-.15-1.709.987-1.762 2.34.224 3.487zm23.004-5.863c-2.881 1.663-5.78 2.128-8.124 1.808-.93-.134-1.119-.594-.617-1.07l.796-.748c.42-.398.957-.48 1.762-.45 1.074.032 2.39-.18 3.785-.986 1.843-1.064 2.353-2.32.331-3.487l-2.603-1.503-.162.093c.51.873.672 2.237-1.682 3.595-3.167 1.829-7.9 1.979-12.383-.61-4.518-2.608-4.51-5.485-1.333-7.318 2.425-1.4 4.912-1.152 6.398-.863l.178-.103-1.288-.744c-.635-.367-.635-.77 0-1.136l1.226-.708a1.9 1.9 0 0 1 1.968 0l12.983 7.495c3.516 2.03 2.478 4.592-1.235 6.735m-15.613-5.273c2.532 1.461 5.324 1.771 7.462.537 2.067-1.194 1.655-2.774-.966-4.287-2.604-1.504-5.476-1.84-7.56-.636-2.157 1.245-1.432 2.944 1.064 4.386m20.686-5.073c.636.367.636.77 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.968 0l-16.356-9.442c-.635-.367-.635-.77 0-1.137l1.27-.733a1.9 1.9 0 0 1 1.969 0zM-53.82 64.863c-1.038.6-2.666.63-3.632.073-.976-.564-.922-1.504.116-2.103 1.029-.594 2.657-.625 3.633-.062.966.558.912 1.498-.117 2.092m13.081 9.432-11.774-6.797c-.636-.367-.636-.77 0-1.137l1.27-.733a1.9 1.9 0 0 1 1.969 0l11.774 6.797c.636.367.636.77 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.969 0m4.915-13.106c-.501.362-1.056.393-1.861.31a5.36 5.36 0 0 0-3.14.697c-1.352.78-1.736 1.746-.797 2.278.788.465 1.825.424 3.534-.201l2.846-1.064c3.158-1.173 5.618-1.209 7.587-.083 2.595 1.508 1.95 3.936-1.485 5.92-2.881 1.663-5.941 2.169-8.599 1.513-.895-.217-.957-.687-.349-1.11l1.11-.775c.519-.362 1.074-.383 1.888-.274 1.18.155 2.37-.109 3.498-.76 1.539-.888 1.852-1.885.913-2.427-.779-.45-1.88-.403-3.418.165l-2.837 1.07c-3.185 1.208-5.744 1.157-7.739-.006-2.55-1.461-1.924-3.703 1.387-5.614 2.711-1.565 5.52-1.968 7.99-1.41.904.211.993.676.385 1.11zm15.698 1.206c.636.367.636.77 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.969 0l-16.355-9.442c-.636-.367-.636-.77 0-1.137l1.199-.692a1.9 1.9 0 0 1 1.968 0l5.932 3.425.161-.093c-.921-1.266-.537-2.593 1.575-3.812 2.854-1.648 6.585-1.663 9.905.253l7.766 4.483c.635.367.635.77 0 1.137l-1.27.733a1.9 1.9 0 0 1-1.97 0l-7.264-4.194c-1.852-1.07-3.937-1.116-5.637-.134-1.736 1.002-1.825 2.376.161 3.523zm12.733-14.623c.635.367.635.77 0 1.136l-6.281 3.626a1.9 1.9 0 0 1-1.969 0l-.698-.402c-.635-.367-.635-.77 0-1.137l6.281-3.626a1.9 1.9 0 0 1 1.969 0zm9.33 3.023c-.725.418-1.494.346-1.933-.186l-10.62-12.805c-.358-.424-.25-.775.322-1.105l2.416-1.395c.572-.33 1.18-.393 1.914-.186l22.19 6.126c.921.253 1.047.697.322 1.116l-1.494.862c-.573.331-1.2.393-1.924.181l-4.966-1.42-6.89 3.977 2.47 2.862c.367.418.26.78-.313 1.11zm-2.434-6.89 5.1-2.945-9.86-2.83-.143.082zm26.089-6.363c-4.42 2.551-10.55 2.06-16.553-1.405-5.977-3.46-6.773-6.978-2.37-9.52 4.401-2.541 10.512-2.081 16.489 1.369 6.012 3.471 6.862 7.01 2.434 9.556M12.394 34.2c4.394 2.546 8.116 3.042 10.397 1.725 2.29-1.322 1.423-3.466-2.98-6.007-4.375-2.516-8.097-3.022-10.378-1.705-2.273 1.312-1.396 3.461 2.961 5.987"
        ></path>
        <g filter="url(#filter15_d_3893_337)">
          <rect
            width="284.951"
            height="284.951"
            fill="#F7F7F7"
            rx="49.747"
            transform="matrix(.86604 -.49997 .86604 .49997 26 -92.477)"
          ></rect>
          <rect
            width="283.707"
            height="283.707"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="49.125"
            transform="scale(1.22477 .70706)rotate(-45 -146.285 -90.782)"
          ></rect>
        </g>
        <g filter="url(#filter16_d_3893_337)">
          <rect
            width="251.286"
            height="251.286"
            fill="#fff"
            rx="32.335"
            transform="scale(1.22477 .70706)rotate(-45 -191.483 -143.012)"
          ></rect>
          <rect
            width="250.042"
            height="250.042"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="31.714"
            transform="scale(1.22477 .70706)rotate(-45 -190.504 -142.773)"
          ></rect>
        </g>
        <g filter="url(#filter17_d_3893_337)">
          <rect
            width="284.951"
            height="284.951"
            fill="#F7F7F7"
            rx="49.747"
            transform="scale(1.22477 .70706)rotate(-45 996.574 -2.889)"
          ></rect>
          <rect
            width="283.707"
            height="283.707"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="49.125"
            transform="scale(1.22477 .70706)rotate(-45 997.553 -2.65)"
          ></rect>
        </g>
        <g filter="url(#filter18_d_3893_337)">
          <rect
            width="251.286"
            height="251.286"
            fill="#fff"
            rx="32.335"
            transform="scale(1.22477 .70706)rotate(-45 951.928 -55.057)"
          ></rect>
          <rect
            width="250.042"
            height="250.042"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="31.714"
            transform="scale(1.22477 .70706)rotate(-45 952.907 -54.817)"
          ></rect>
        </g>
        <path
          fill="#A6A6A6"
          d="M552.364 478.433c-.501.361-1.056.392-1.861.31a5.36 5.36 0 0 0-3.14.697c-1.351.78-1.736 1.746-.797 2.278.788.465 1.826.423 3.535-.202l2.845-1.064c3.158-1.172 5.619-1.208 7.587-.082 2.595 1.508 1.951 3.936-1.485 5.919-2.881 1.663-5.941 2.169-8.599 1.513-.894-.216-.957-.686-.348-1.11l1.109-.775c.519-.361 1.074-.382 1.888-.274 1.181.155 2.371-.108 3.498-.759 1.539-.888 1.852-1.885.913-2.428-.779-.449-1.879-.402-3.418.166l-2.836 1.069c-3.185 1.209-5.744 1.157-7.74-.005-2.55-1.462-1.923-3.704 1.387-5.615 2.711-1.565 5.521-1.968 7.99-1.41.904.212.993.677.385 1.111zm.685-3.722c-.635-.367-.635-.77 0-1.136l1.217-.703a1.9 1.9 0 0 1 1.968 0l1.289.744.188-.109c-.501-.857-.949-2.283 1.476-3.682 3.176-1.834 8.16-1.839 12.741.805 4.527 2.614 4.67 5.496 1.431 7.366-2.362 1.364-4.831 1.167-6.343.883l-.134.078 6.334 3.657c.635.367.635.769 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.969 0zm9.064 1.565c2.666 1.539 5.619 1.901 7.685.708 2.139-1.235 1.387-2.97-1.19-4.458-2.559-1.477-5.502-1.896-7.659-.651-2.084 1.204-1.503 2.862 1.164 4.401m22.162-4.54c-2.621 1.513-6.03 1.828-8.732.268-3.096-1.787-1.342-3.719 1.038-5.423 2.165-1.55 3.096-2.139 2.165-2.676l-.054-.031c-1.351-.78-2.943-.749-4.446.119-1.155.666-1.522 1.374-1.405 1.988.107.465.027.78-.618 1.059l-1.234.537c-.788.341-1.593.259-1.888-.294-.85-1.617.188-3.29 2.648-4.711 2.622-1.513 6.675-2.593 10.308-.496l8.213 4.742c.635.367.635.77 0 1.137l-1.145.661c-.635.366-1.324.372-1.933.02l-.939-.542-.108.062c.564 1.007.287 2.335-1.87 3.58m-5.663-1.566c1.19.687 2.773.486 4.124-.294 1.951-1.126 1.888-2.588.358-3.471l-1.619-.935c-.081.439-1.566 1.544-2.3 2.102-1.243.956-1.807 1.88-.563 2.598m16.642-6.229c.635.367.635.77 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.969 0l-11.774-6.798c-.636-.367-.636-.769 0-1.136l1.127-.651a1.9 1.9 0 0 1 1.968 0l1.351.78.161-.093c-.903-1.245-.474-2.629 1.584-3.817 2.836-1.637 6.594-1.637 9.878.268l7.766 4.484c.635.367.635.77 0 1.136l-1.27.734a1.9 1.9 0 0 1-1.969 0l-7.265-4.194c-1.834-1.059-3.937-1.116-5.61-.15-1.709.986-1.763 2.34.224 3.486z"
        ></path>
        <g filter="url(#filter19_d_3893_337)">
          <rect
            width="284.951"
            height="284.951"
            fill="#F7F7F7"
            rx="49.747"
            transform="matrix(.86604 -.49997 .86604 .49997 60 697.531)"
          ></rect>
          <rect
            width="283.707"
            height="283.707"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="49.125"
            transform="scale(1.22477 .70706)rotate(-45 1216.312 434.366)"
          ></rect>
        </g>
        <g filter="url(#filter20_d_3893_337)">
          <rect
            width="251.286"
            height="251.286"
            fill="#fff"
            rx="32.335"
            transform="scale(1.22477 .70706)rotate(-45 1171.088 382.125)"
          ></rect>
          <rect
            width="250.042"
            height="250.042"
            x="1.077"
            stroke="#9B9B9B"
            strokeWidth="1.244"
            rx="31.714"
            transform="scale(1.22477 .70706)rotate(-45 1172.066 382.363)"
          ></rect>
        </g>
      </g>
      <defs>
        <filter
          id="filter0_d_3893_337"
          width="524.929"
          height="337.64"
          x="24.313"
          y="145.331"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter1_d_3893_337"
          width="484.28"
          height="314.171"
          x="44.649"
          y="123.721"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter2_f_3893_337"
          width="1333.8"
          height="1268.8"
          x="-228.9"
          y="-191.892"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend>
          <feGaussianBlur
            result="effect1_foregroundBlur_3893_337"
            stdDeviation="76.95"
          ></feGaussianBlur>
        </filter>
        <filter
          id="filter3_f_3893_337"
          width="1334.8"
          height="1269.8"
          x="368.1"
          y="79.108"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend>
          <feGaussianBlur
            result="effect1_foregroundBlur_3893_337"
            stdDeviation="76.95"
          ></feGaussianBlur>
        </filter>
        <filter
          id="filter4_f_3893_337"
          width="1334.8"
          height="1269.8"
          x="-800.9"
          y="-762.892"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend>
          <feGaussianBlur
            result="effect1_foregroundBlur_3893_337"
            stdDeviation="76.95"
          ></feGaussianBlur>
        </filter>
        <filter
          id="filter5_f_3893_337"
          width="1334.66"
          height="1242.85"
          x="-898.087"
          y="-51.666"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend>
          <feGaussianBlur
            result="effect1_foregroundBlur_3893_337"
            stdDeviation="76.95"
          ></feGaussianBlur>
        </filter>
        <filter
          id="filter6_f_3893_337"
          width="1334.66"
          height="1242.85"
          x="465.436"
          y="-578.353"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend>
          <feGaussianBlur
            result="effect1_foregroundBlur_3893_337"
            stdDeviation="76.95"
          ></feGaussianBlur>
        </filter>
        <filter
          id="filter7_f_3893_337"
          width="1288.3"
          height="1269.52"
          x="-157.314"
          y="214.498"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend>
          <feGaussianBlur
            result="effect1_foregroundBlur_3893_337"
            stdDeviation="76.95"
          ></feGaussianBlur>
        </filter>
        <filter
          id="filter8_f_3893_337"
          width="1288.3"
          height="1269.52"
          x="-182.752"
          y="-907.009"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"></feBlend>
          <feGaussianBlur
            result="effect1_foregroundBlur_3893_337"
            stdDeviation="76.95"
          ></feGaussianBlur>
        </filter>
        <filter
          id="filter9_d_3893_337"
          width="524.929"
          height="337.64"
          x="324.313"
          y="-54.794"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter10_d_3893_337"
          width="484.28"
          height="314.171"
          x="344.649"
          y="-76.185"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter11_d_3893_337"
          width="524.929"
          height="337.64"
          x="-275.687"
          y="345.213"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter12_d_3893_337"
          width="484.28"
          height="314.171"
          x="-255.351"
          y="323.815"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter13_d_3893_337"
          width="524.929"
          height="337.64"
          x="-289.687"
          y="-54.802"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter14_d_3893_337"
          width="484.28"
          height="314.171"
          x="-269.351"
          y="-76.169"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter15_d_3893_337"
          width="524.929"
          height="337.64"
          x="10.313"
          y="-254.927"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter16_d_3893_337"
          width="484.28"
          height="314.171"
          x="30.649"
          y="-276.068"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter17_d_3893_337"
          width="524.929"
          height="337.64"
          x="344.313"
          y="335.206"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter18_d_3893_337"
          width="484.28"
          height="314.171"
          x="364.649"
          y="313.815"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter19_d_3893_337"
          width="524.929"
          height="337.64"
          x="44.313"
          y="535.081"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <filter
          id="filter20_d_3893_337"
          width="484.28"
          height="314.171"
          x="64.649"
          y="513.924"
          colorInterpolationFilters="sRGB"
          filterUnits="userSpaceOnUse"
        >
          <feFlood floodOpacity="0" result="BackgroundImageFix"></feFlood>
          <feColorMatrix
            in="SourceAlpha"
            result="hardAlpha"
            values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
          ></feColorMatrix>
          <feOffset dy="6.369"></feOffset>
          <feGaussianBlur stdDeviation="20.461"></feGaussianBlur>
          <feComposite in2="hardAlpha" operator="out"></feComposite>
          <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0"></feColorMatrix>
          <feBlend in2="BackgroundImageFix" result="effect1_dropShadow_3893_337"></feBlend>
          <feBlend in="SourceGraphic" in2="effect1_dropShadow_3893_337" result="shape"></feBlend>
        </filter>
        <clipPath id="clip0_3893_337">
          <path fill="#fff" d="M0 0h580v579H0z"></path>
        </clipPath>
      </defs>
    </svg>
  );
}



================================================
FILE: components/ui/base/popover.jsx
================================================
'use client';

import * as React from 'react';
import * as PopoverPrimitive from '@radix-ui/react-popover';

import { cn } from '@/lib/styles';

const Popover = PopoverPrimitive.Root;

const PopoverTrigger = PopoverPrimitive.Trigger;

const PopoverContent = React.forwardRef(
  ({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
    <PopoverPrimitive.Portal>
      <PopoverPrimitive.Content
        ref={ref}
        align={align}
        sideOffset={sideOffset}
        className={cn(
          'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
          className,
        )}
        {...props}
      />
    </PopoverPrimitive.Portal>
  ),
);
PopoverContent.displayName = PopoverPrimitive.Content.displayName;

export { Popover, PopoverTrigger, PopoverContent };



================================================
FILE: components/ui/base/progress.jsx
================================================
'use client';

import * as React from 'react';
import * as ProgressPrimitive from '@radix-ui/react-progress';

import { cn } from '@/lib/styles';

const Progress = React.forwardRef(({ className, value, ...props }, ref) => (
  <ProgressPrimitive.Root
    ref={ref}
    className={cn('relative h-4 w-full overflow-hidden rounded-full bg-secondary', className)}
    {...props}
  >
    <ProgressPrimitive.Indicator
      className="h-full w-full flex-1 bg-primary transition-all"
      style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
    />
  </ProgressPrimitive.Root>
));
Progress.displayName = ProgressPrimitive.Root.displayName;

export { Progress };



================================================
FILE: components/ui/base/radio-group.jsx
================================================
'use client';

import * as React from 'react';
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
import { Circle } from 'lucide-react';

import { cn } from '@/lib/styles';

const RadioGroup = React.forwardRef(({ className, ...props }, ref) => {
  return <RadioGroupPrimitive.Root className={cn('grid gap-2', className)} {...props} ref={ref} />;
});
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;

const RadioGroupItem = React.forwardRef(({ className, ...props }, ref) => {
  return (
    <RadioGroupPrimitive.Item
      ref={ref}
      className={cn(
        'aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
        className,
      )}
      {...props}
    >
      <RadioGroupPrimitive.Indicator className="flex items-center justify-center">
        <Circle className="h-2.5 w-2.5 fill-current text-current" />
      </RadioGroupPrimitive.Indicator>
    </RadioGroupPrimitive.Item>
  );
});
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;

export { RadioGroup, RadioGroupItem };



================================================
FILE: components/ui/base/scroll-area.jsx
================================================
'use client';

import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
import * as React from 'react';

import { cn } from '@/lib/styles';

const ScrollArea = React.forwardRef(({ className, children, ...props }, ref) => (
  <ScrollAreaPrimitive.Root
    ref={ref}
    className={cn('relative overflow-hidden', className)}
    {...props}
  >
    <ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
      {children}
    </ScrollAreaPrimitive.Viewport>
    <ScrollBar />
    <ScrollAreaPrimitive.Corner />
  </ScrollAreaPrimitive.Root>
));
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;

const ScrollBar = React.forwardRef(({ className, orientation = 'vertical', ...props }, ref) => (
  <ScrollAreaPrimitive.ScrollAreaScrollbar
    ref={ref}
    orientation={orientation}
    className={cn(
      'flex touch-none select-none transition-colors',
      orientation === 'vertical' && 'h-full w-2.5 border-l border-l-transparent p-px',
      orientation === 'horizontal' && 'h-2.5 flex-col border-t border-t-transparent p-px',
      className,
    )}
    {...props}
  >
    <ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
  </ScrollAreaPrimitive.ScrollAreaScrollbar>
));
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;

export { ScrollArea, ScrollBar };



================================================
FILE: components/ui/base/select.tsx
================================================
'use client';

import * as React from 'react';
import * as SelectPrimitive from '@radix-ui/react-select';
import { Check, ChevronDown, ChevronUp } from 'lucide-react';

import { cn } from '@/lib/styles';

const Select = SelectPrimitive.Root;

const SelectGroup = SelectPrimitive.Group;

const SelectValue = SelectPrimitive.Value;

type SelectTriggerProps = React.HTMLAttributes<HTMLButtonElement> & {
  className?: string;
};

const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerProps>(
  ({ className, children, ...props }, ref) => (
    <SelectPrimitive.Trigger
      ref={ref}
      className={cn(
        'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
        className,
      )}
      {...props}
    >
      {children}
      <SelectPrimitive.Icon asChild>
        <ChevronDown className="h-4 w-4 opacity-50" />
      </SelectPrimitive.Icon>
    </SelectPrimitive.Trigger>
  ),
);
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;

type SelectScrollUpButtonProps = React.ButtonHTMLAttributes<HTMLDivElement>;

const SelectScrollUpButton = React.forwardRef<HTMLDivElement, SelectScrollUpButtonProps>(
  ({ className, ...props }, ref) => (
    <SelectPrimitive.ScrollUpButton
      ref={ref}
      className={cn('flex cursor-default items-center justify-center py-1', className)}
      {...props}
    >
      <ChevronUp className="h-4 w-4" />
    </SelectPrimitive.ScrollUpButton>
  ),
);
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;

type SelectScrollDownButtonProps = React.ButtonHTMLAttributes<HTMLDivElement>;

const SelectScrollDownButton = React.forwardRef<HTMLDivElement, SelectScrollDownButtonProps>(
  ({ className, ...props }, ref) => (
    <SelectPrimitive.ScrollDownButton
      ref={ref}
      className={cn('flex cursor-default items-center justify-center py-1', className)}
      {...props}
    >
      <ChevronDown className="h-4 w-4" />
    </SelectPrimitive.ScrollDownButton>
  ),
);
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;

type SelectContentProps = React.HTMLAttributes<HTMLDivElement> & {
  className?: string;
  noPadding?: boolean;
  position?: 'popper' | 'item-aligned' | undefined;
};

const SelectContent = React.forwardRef<HTMLDivElement, SelectContentProps>(
  ({ className, children, position = 'popper', noPadding = false, ...props }, ref) => (
    <SelectPrimitive.Portal>
      <SelectPrimitive.Content
        ref={ref}
        className={cn(
          'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 placeholder:text-muted-foreground',
          position === 'popper' &&
            'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
          noPadding && 'p-0',
          className,
        )}
        position={position}
        {...props}
      >
        <SelectScrollUpButton />
        <SelectPrimitive.Viewport
          className={cn(
            noPadding ? 'p-0' : 'p-1',
            position === 'popper' &&
              'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',
          )}
        >
          {children}
        </SelectPrimitive.Viewport>
        <SelectScrollDownButton />
      </SelectPrimitive.Content>
    </SelectPrimitive.Portal>
  ),
);
SelectContent.displayName = SelectPrimitive.Content.displayName;

type SelectLabelProps = React.HTMLAttributes<HTMLDivElement> & {
  className?: string;
};

const SelectLabel = React.forwardRef<HTMLDivElement, SelectLabelProps>(
  ({ className, ...props }, ref) => (
    <SelectPrimitive.Label
      ref={ref}
      className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
      {...props}
    />
  ),
);
SelectLabel.displayName = SelectPrimitive.Label.displayName;

type SelectItemProps = React.HTMLAttributes<HTMLDivElement> & {
  className?: string;
  value?: string;
  noCheck?: boolean;
  rightCheck?: boolean;
  disabled?: boolean;
};

const SelectItem = React.forwardRef<HTMLDivElement, SelectItemProps>(
  ({ className, children, value, noCheck = false, rightCheck = false, ...props }, ref) => (
    <SelectPrimitive.Item
      ref={ref}
      value={value ?? ''}
      className={cn(
        'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 placeholder:text-muted-foreground',
        className,
      )}
      {...props}
    >
      {!noCheck && !rightCheck && (
        <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
          <SelectPrimitive.ItemIndicator>
            <Check className="h-4 w-4" />
          </SelectPrimitive.ItemIndicator>
        </span>
      )}
      {rightCheck && (
        <span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
          <SelectPrimitive.ItemIndicator>
            <Check className="h-4 w-4" />
          </SelectPrimitive.ItemIndicator>
        </span>
      )}
      <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
    </SelectPrimitive.Item>
  ),
);
SelectItem.displayName = SelectPrimitive.Item.displayName;

type SelectSeparatorProps = React.HTMLAttributes<HTMLDivElement> & {
  className?: string;
};

const SelectSeparator = React.forwardRef<HTMLDivElement, SelectSeparatorProps>(
  ({ className, ...props }, ref) => (
    <SelectPrimitive.Separator
      ref={ref}
      className={cn('-mx-1 my-1 h-px bg-muted', className)}
      {...props}
    />
  ),
);
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;

export {
  Select,
  SelectGroup,
  SelectValue,
  SelectTrigger,
  SelectContent,
  SelectLabel,
  SelectItem,
  SelectSeparator,
  SelectScrollUpButton,
  SelectScrollDownButton,
};



================================================
FILE: components/ui/base/separator.jsx
================================================
'use client';

import * as React from 'react';
import * as SeparatorPrimitive from '@radix-ui/react-separator';

import { cn } from '@/lib/styles';

const Separator = React.forwardRef(
  ({ className, orientation = 'horizontal', decorative = true, ...props }, ref) => (
    <SeparatorPrimitive.Root
      ref={ref}
      decorative={decorative}
      orientation={orientation}
      className={cn(
        'shrink-0 bg-border',
        orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
        className,
      )}
      {...props}
    />
  ),
);
Separator.displayName = SeparatorPrimitive.Root.displayName;

export { Separator };



================================================
FILE: components/ui/base/sheet.jsx
================================================
'use client';
import * as React from 'react';
import * as SheetPrimitive from '@radix-ui/react-dialog';
import { cva } from 'class-variance-authority';
import { X } from 'lucide-react';

import { cn } from '@/lib/styles';

const Sheet = SheetPrimitive.Root;

const SheetTrigger = SheetPrimitive.Trigger;

const SheetClose = SheetPrimitive.Close;

const SheetPortal = SheetPrimitive.Portal;

const SheetOverlay = React.forwardRef(({ className, ...props }, ref) => (
  <SheetPrimitive.Overlay
    className={cn(
      'fixed inset-0 z-50 bg-black/80  data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
      className,
    )}
    {...props}
    ref={ref}
  />
));
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;

const sheetVariants = cva(
  'fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
  {
    variants: {
      side: {
        top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
        bottom:
          'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
        left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
        right:
          'inset-y-0 right-0 h-full w-3/4  border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
      },
    },
    defaultVariants: {
      side: 'right',
    },
  },
);

const SheetContent = React.forwardRef(({ side = 'right', className, children, ...props }, ref) => (
  <SheetPortal>
    <SheetOverlay />
    <SheetPrimitive.Content ref={ref} className={cn(sheetVariants({ side }), className)} {...props}>
      {children}
      <SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
        <X className="h-4 w-4" />
        <span className="sr-only">Close</span>
      </SheetPrimitive.Close>
    </SheetPrimitive.Content>
  </SheetPortal>
));
SheetContent.displayName = SheetPrimitive.Content.displayName;

const SheetHeader = ({ className, ...props }) => (
  <div className={cn('flex flex-col space-y-2 text-center sm:text-left', className)} {...props} />
);
SheetHeader.displayName = 'SheetHeader';

const SheetFooter = ({ className, ...props }) => (
  <div
    className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}
    {...props}
  />
);
SheetFooter.displayName = 'SheetFooter';

const SheetTitle = React.forwardRef(({ className, ...props }, ref) => (
  <SheetPrimitive.Title
    ref={ref}
    className={cn('text-lg font-semibold text-foreground', className)}
    {...props}
  />
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;

const SheetDescription = React.forwardRef(({ className, ...props }, ref) => (
  <SheetPrimitive.Description
    ref={ref}
    className={cn('text-sm text-muted-foreground', className)}
    {...props}
  />
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;

export {
  Sheet,
  SheetPortal,
  SheetOverlay,
  SheetTrigger,
  SheetClose,
  SheetContent,
  SheetHeader,
  SheetFooter,
  SheetTitle,
  SheetDescription,
};



================================================
FILE: components/ui/base/skeleton.jsx
================================================
import { cn } from '@/lib/styles';

function Skeleton({ className, ...props }) {
  return <div className={cn('animate-pulse rounded-md bg-muted', className)} {...props} />;
}

export { Skeleton };



================================================
FILE: components/ui/base/slider.jsx
================================================
'use client';

import * as React from 'react';
import * as SliderPrimitive from '@radix-ui/react-slider';

import { cn } from '@/lib/styles';

const Slider = React.forwardRef(({ className, ...props }, ref) => (
  <SliderPrimitive.Root
    ref={ref}
    className={cn('relative flex w-full touch-none select-none items-center', className)}
    {...props}
  >
    <SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
      <SliderPrimitive.Range className="absolute h-full bg-primary" />
    </SliderPrimitive.Track>
    <SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" />
  </SliderPrimitive.Root>
));
Slider.displayName = SliderPrimitive.Root.displayName;

export { Slider };



================================================
FILE: components/ui/base/tabs.jsx
================================================
'use client';

import * as TabsPrimitive from '@radix-ui/react-tabs';
import * as React from 'react';

import { cn } from '@/lib/styles';

const Tabs = TabsPrimitive.Root;

const TabsList = React.forwardRef(({ className, ...props }, ref) => (
  <TabsPrimitive.List
    ref={ref}
    className={cn(
      'inline-flex items-center justify-center rounded-lg bg-muted p-0.5 text-muted-foreground/70',
      className,
    )}
    {...props}
  />
));
TabsList.displayName = TabsPrimitive.List.displayName;

const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (
  <TabsPrimitive.Trigger
    ref={ref}
    className={cn(
      'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium outline-offset-2 transition-all hover:text-muted-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring/70 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-xs data-[state=active]:shadow-black/5',
      className,
    )}
    {...props}
  />
));
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;

const TabsContent = React.forwardRef(({ className, ...props }, ref) => (
  <TabsPrimitive.Content
    ref={ref}
    className={cn(
      'mt-2 outline-offset-2 focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring/70',
      className,
    )}
    {...props}
  />
));
TabsContent.displayName = TabsPrimitive.Content.displayName;

export { Tabs, TabsContent, TabsList, TabsTrigger };



================================================
FILE: components/ui/base/textarea.tsx
================================================
import * as React from 'react';

import { cn } from '@/lib/styles';

type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement> & {
  className?: string;
};

const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
  ({ className, ...props }, ref) => {
    return (
      <textarea
        className={cn(
          'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-hidden disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
          className,
        )}
        ref={ref}
        {...props}
      />
    );
  },
);
Textarea.displayName = 'Textarea';

export { Textarea };



================================================
FILE: components/ui/base/theme-provider.tsx
================================================
'use client';

import * as React from 'react';
import { ThemeProvider as NextThemesProvider } from 'next-themes';
import { type ThemeProviderProps } from 'next-themes/dist/types';

export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
  return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}



================================================
FILE: components/ui/base/tooltip.tsx
================================================
'use client';

import * as React from 'react';
import * as TooltipPrimitive from '@radix-ui/react-tooltip';

import { cn } from '@/lib/styles';

const TooltipProvider = TooltipPrimitive.Provider;

const Tooltip = TooltipPrimitive.Root;

const TooltipTrigger = TooltipPrimitive.Trigger;

type TooltipContentProps = React.HTMLAttributes<HTMLDivElement> & {
  className?: string;
  sideOffset?: number;
};

const TooltipContent = React.forwardRef<HTMLDivElement, TooltipContentProps>(
  ({ className, sideOffset = 4, ...props }, ref) => (
    <TooltipPrimitive.Content
      ref={ref}
      sideOffset={sideOffset}
      className={cn(
        'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
        className,
      )}
      {...props}
    />
  ),
);
TooltipContent.displayName = TooltipPrimitive.Content.displayName;

export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };



================================================
FILE: components/ui/dashboard/ClipsList.tsx
================================================
'use client';

import * as React from 'react';
import { Card, CardContent } from '@/components/ui/base/card';
import { ChevronLeft, ChevronRight, Clock } from 'lucide-react';
import { Button } from '@/components/ui/base/button';
import { cn } from '@/lib/styles';
import Image from 'next/image';
import Link from 'next/link';
import { Badge } from '@/components/ui/base/badge';
import { useRouter } from 'next/navigation';
import { associateUserVideo } from '@/lib/videos';

interface BaseClip {
  id: string | number;
  title: string;
  duration: string;
  thumbnail: string;
  difficulty: string;
  dialect: string;
  dialectFlag: string;
}

interface RevisitClip {
  id: string;
  title: string;
  thumbnail: string;
  vtt: string | null;
  video: string;
  link: string | null;
  badge: string | null;
  difficulty: string | null;
  dialect: string | null;
  dialectFlag: string | null;
  dialectIcon: string | null;
  completedSections: number | null;
  duration: string | null;
  addedAt: Date | null;
  lastWatched: Date | null;
}

interface ClipsListProps {
  title: string;
  clips: (BaseClip | RevisitClip)[];
  isRevisitList?: boolean;
  onVideoAdded?: (videoId: string) => Promise<void>;
}

export default function ClipsList({
  title,
  clips,
  isRevisitList = false,
  onVideoAdded,
}: ClipsListProps) {
  const router = useRouter();
  const scrollContainerRef = React.useRef<HTMLDivElement>(null);
  const [showLeftArrow, setShowLeftArrow] = React.useState(false);
  const [showRightArrow, setShowRightArrow] = React.useState(false);
  const [isExpanded, setIsExpanded] = React.useState(false);

  // Memoize clip rendering to prevent unnecessary re-renders
  const handleRecommendedClipClick = React.useCallback(
    async (clip: BaseClip | RevisitClip) => {
      console.log('Video clicked:', clip.title, clip.id);

      try {
        console.log('Adding video to user collection...');
        // Start navigation and API call in parallel
        const navigationPromise = router.prefetch(`/dashboard/${clip.id}`);

        try {
          await associateUserVideo(clip.id.toString());
          console.log('Video added successfully');
        } catch (error) {
          console.warn('Failed to add video:', error);
        }

        // Store in session storage early
        sessionStorage.setItem('lastClickedVideo', clip.id.toString());

        if (onVideoAdded) {
          console.log('Updating parent state...');
          await onVideoAdded(clip.id.toString());
        }

        console.log('Navigating to video page...');
        router.push(`/dashboard/${clip.id}`);
      } catch (error) {
        console.error('Error adding video to user collection:', error);
        console.log('Navigating anyway...'); // TODO: what kind if error handling is this lol, should show something to the user
        router.push(`/dashboard/${clip.id}`);
      }
    },
    [router, onVideoAdded],
  );

  const handleScroll = React.useCallback(() => {
    if (scrollContainerRef.current) {
      const { scrollLeft, scrollWidth, clientWidth } = scrollContainerRef.current;
      setShowLeftArrow(scrollLeft > 0);
      setShowRightArrow(scrollLeft < scrollWidth - clientWidth - 10 && scrollWidth > clientWidth);
    }
  }, []);

  const scroll = React.useCallback((direction: 'left' | 'right') => {
    if (scrollContainerRef.current) {
      const scrollAmount = scrollContainerRef.current.clientWidth / 2;
      scrollContainerRef.current.scrollBy({
        left: direction === 'left' ? -scrollAmount : scrollAmount,
        behavior: 'smooth',
      });
    }
  }, []);

  React.useEffect(() => {
    const scrollContainer = scrollContainerRef.current;
    if (scrollContainer) {
      scrollContainer.addEventListener('scroll', handleScroll);
      // Use ResizeObserver to detect changes in container size
      const resizeObserver = new ResizeObserver(() => {
        handleScroll();
      });
      resizeObserver.observe(scrollContainer);

      // Initial check for overflow
      handleScroll();

      return () => {
        scrollContainer.removeEventListener('scroll', handleScroll);
        resizeObserver.disconnect();
      };
    }
  }, [handleScroll]);

  const toggleExpand = React.useCallback(() => {
    setIsExpanded(prev => !prev);
  }, []);

  const renderClip = React.useCallback(
    (clip: BaseClip | RevisitClip, index: number) => {
      const clipContent = (
        <>
          <Card className="border text-neutral-500 relative overflow-hidden dark:text-neutral-400 rounded-lg bg-neutral-200/50 dark:bg-neutral-800/50 border-neutral-300 dark:border-neutral-800">
            <CardContent
              className={cn(
                'flex aspect-video items-center justify-center',
                isRevisitList ? 'p-2' : 'p-0',
              )}
            >
              <Image
                src={clip.thumbnail}
                alt={clip.title}
                width={298}
                height={167.33}
                className={cn('w-full h-full object-cover', {
                  'absolute inset-0': isRevisitList,
                  'rounded-[7px]': !isRevisitList,
                })}
                loading="lazy"
              />
            </CardContent>
          </Card>
          <div className="flex justify-between mt-1.5">
            <h2 className="text-sm font-medium tracking-tight ml-1 line-clamp-1 text-neutral-700 dark:text-neutral-300 h-full">
              {clip.title}
            </h2>
            <p className="text-sm font-medium mr-1 text-neutral-500 dark:text-neutral-400">
              {clip.duration}
            </p>
          </div>
          <div className="flex justify-between mt-1.5">
            <Badge
              variant="outline"
              className="inline-flex items-center justify-center rounded-full border px-2 py-0 text-xs font-normal leading-normal text-foreground gap-1.5"
            >
              <span
                className={cn('size-1.5 rounded-full', {
                  'bg-green-500': clip.difficulty === 'Easy',
                  'bg-yellow-500': clip.difficulty === 'Medium',
                  'bg-red-500': clip.difficulty === 'Hard',
                })}
                aria-hidden="true"
              ></span>
              {clip.difficulty}
            </Badge>
            <Badge
              variant="outline"
              className="inline-flex items-center justify-center rounded-full border px-2 py-0 text-xs font-normal leading-normal text-foreground gap-2"
            >
              {clip.dialectFlag} {clip.dialect}
            </Badge>
          </div>
        </>
      );

      const clipWrapper = (
        <div
          key={index}
          className={cn('flex-none w-[200px] sm:w-[364px]', {
            'w-full sm:w-1/2 md:w-1/3 lg:w-1/4 px-1.5 pb-6': isExpanded,
          })}
        >
          {isRevisitList ? (
            <Link href={`dashboard/${clip.id}`} className="block">
              {clipContent}
            </Link>
          ) : (
            <button
              onClick={() => handleRecommendedClipClick(clip)}
              className="block w-full text-left cursor-pointer transition-transform duration-200 rounded-lg"
            >
              {clipContent}
            </button>
          )}
        </div>
      );

      return clipWrapper;
    },
    [isRevisitList, handleRecommendedClipClick],
  );

  // Memoize this calculation
  const showViewAllButton = React.useMemo(() => clips.length >= 5, [clips.length]);

  // Render empty state with call to action for "Previously Practiced"
  const renderEmptyState = React.useCallback(() => {
    if (isRevisitList) {
      return (
        <div className="flex relative flex-col items-center justify-center text-center border mx-4 border-neutral-200 dark:border-neutral-800 rounded-xl border-dashed bg-[url('/NoPractice.svg')] dark:bg-[url('/DarkNoPractice.svg')] bg-cover bg-center">
          <div className="relative flex-col items-center justify-center flex bg-white/50 dark:bg-transparent py-10 px-4">
            <p className="mb-3 text-3xl">🎬</p>
            <h3 className="text-lg font-medium tracking-tight mb-2">No Practice History</h3>
            <p className="text-sm text-neutral-500 dark:text-neutral-400 mb-4 max-w-xs text-balance">
              Start practicing with any clip from the home page to build history.
            </p>
            <Button
              variant="outline"
              className="flex items-center gap-2 tracking-tight"
              onClick={() => {
                // Scroll to recommended section
                const recommendedSection = document.querySelector('[data-section="recommended"]');
                if (recommendedSection) {
                  recommendedSection.scrollIntoView({ behavior: 'smooth' });
                }
              }}
            >
              Browse Recommendations
              <svg
                width="16"
                height="16"
                viewBox="0 0 24 24"
                fill="none"
                xmlns="http://www.w3.org/2000/svg"
              >
                <path
                  d="M12 5V19M12 19L19 12M12 19L5 12"
                  stroke="currentColor"
                  strokeWidth="2"
                  strokeLinecap="round"
                  strokeLinejoin="round"
                />
              </svg>
            </Button>
          </div>
        </div>
      );
    }
    return null;
  }, [isRevisitList]);

  const renderedClips = React.useMemo(() => {
    return clips.map((clip, index) => (
      <div
        key={`clip-${clip.id}`}
        className={cn('snap-center', {
          'pr-4': index === clips.length - 1,
        })}
      >
        {renderClip(clip, index)}
      </div>
    ));
  }, [clips, renderClip]);

  return (
    <div className="w-full" data-section={isRevisitList ? 'previously-practiced' : 'recommended'}>
      <div className="flex justify-between items-center p-4">
        <h1 className="text-xl sm:text-2xl font-semibold tracking-tighter text-neutral-900 dark:text-neutral-100 pt-0.5 px-0.5">
          {title}
        </h1>
        {clips.length > 0 && showViewAllButton && (
          <Button
            onClick={toggleExpand}
            variant="outline"
            size="sm"
            className="tracking-tight dark:border-neutral-800 dark:text-neutral-300"
          >
            {isExpanded ? 'Collapse' : 'View All'}
          </Button>
        )}
      </div>

      {clips.length === 0 && renderEmptyState()}

      {clips.length > 0 && (
        <div className={cn('relative', { 'px-5': isExpanded })}>
          {isExpanded ? (
            <div className="flex flex-wrap -mx-2">
              {clips.map((clip, index) => renderClip(clip, index))}
            </div>
          ) : (
            <div
              ref={scrollContainerRef}
              className="overflow-x-scroll pb-4 scrollbar-hide snap-x snap-mandatory"
            >
              <div className="flex space-x-3 px-4">{renderedClips}</div>
            </div>
          )}
          {!isExpanded && showLeftArrow && (
            <Button
              variant="outline"
              size="icon"
              className="absolute left-2 top-1/2 -translate-y-1/2 bg-white dark:bg-neutral-800 border border-accent dark:border-accent-dark rounded-full h-8 w-8"
              onClick={() => scroll('left')}
            >
              <ChevronLeft className="h-4 w-4" />
            </Button>
          )}
          {!isExpanded && showRightArrow && (
            <Button
              variant="outline"
              size="icon"
              className="absolute right-2 top-1/2 -translate-y-1/2 bg-white dark:bg-neutral-800 border border-accent dark:border-accent-dark rounded-full h-8 w-8"
              onClick={() => scroll('right')}
            >
              <ChevronRight className="h-4 w-4" />
            </Button>
          )}
        </div>
      )}
    </div>
  );
}



================================================
FILE: components/ui/dashboard/ImportVideos.tsx
================================================
'use client';

import React, { useState } from 'react';
import { Button } from '@/components/ui/base/button';
import { Input } from '@/components/ui/base/input';
import { Label } from '@/components/ui/base/label';
import { validateAndSubmitYoutubeUrl } from '@/components/actions/youtube-video-validate';
import { useFormState, useFormStatus } from 'react-dom';
import { HelpCircle } from 'lucide-react';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '@/components/ui/base/dialog';
import {
  Drawer,
  DrawerClose,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
  DrawerTrigger,
} from '@/components/ui/base/drawer';
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/base/tooltip';
import { Card, CardContent } from '@/components/ui/base/card';
import { Carousel, CarouselContent, CarouselItem } from '@/components/ui/base/carousel';
import { useMediaQuery } from '@custom-react-hooks/use-media-query';
import { Badge } from '@/components/ui/base/badge';

function SubmitButton() {
  const { pending } = useFormStatus();

  return (
    <Button type="submit" className="tracking-tight" disabled={pending}>
      {pending ? 'Submitting...' : 'Import Video'}
    </Button>
  );
}

function YouTubeUrlHelpContent() {
  const steps = [
    { title: 'Find the Video', content: 'Go to YouTube and find the video you want to import.' },
    { title: 'Click Share', content: "Click on the 'Share' button below the video." },
    { title: 'Copy URL', content: "In the 'Share' popup, copy the URL provided." },
    { title: 'Paste URL', content: "Paste the copied URL into the 'YouTube URL' input field." },
    { title: 'Example', content: 'Example URL: https://www.youtube.com/watch?v=dQw4w9WgXcQ' },
  ];

  return (
    <Carousel className="w-full max-w-xs mx-auto">
      <CarouselContent>
        {steps.map((step, index) => (
          <CarouselItem key={index}>
            <Card>
              <CardContent className="flex flex-col items-center justify-center p-6">
                <h3 className="text-lg font-semibold mb-2">{step.title}</h3>
                <p className="text-center">{step.content}</p>
              </CardContent>
            </Card>
          </CarouselItem>
        ))}
      </CarouselContent>
    </Carousel>
  );
}

function YouTubeUrlHelpModal() {
  const [open, setOpen] = React.useState(false);
  const isDesktop = useMediaQuery('(min-width: 768px)');

  if (isDesktop) {
    return (
      <Dialog open={open} onOpenChange={setOpen}>
        <TooltipProvider>
          <Tooltip>
            <TooltipTrigger asChild>
              <DialogTrigger asChild>
                <Button variant="ghost" size="icon" className="h-4 w-4 ml-1">
                  <HelpCircle className="h-4 w-4" />
                  <span className="sr-only">How to get YouTube URL</span>
                </Button>
              </DialogTrigger>
            </TooltipTrigger>
            <TooltipContent>
              <p>Click for help on getting a YouTube URL</p>
            </TooltipContent>
          </Tooltip>
        </TooltipProvider>
        <DialogContent className="sm:max-w-[425px]">
          <DialogHeader className="flex flex-col gap-2">
            <DialogTitle className="text-left">How to get a YouTube URL</DialogTitle>
            <DialogDescription className="text-left">
              Follow these steps to get a YouTube video URL:
            </DialogDescription>
          </DialogHeader>
          <YouTubeUrlHelpContent />
        </DialogContent>
      </Dialog>
    );
  }

  return (
    <Drawer open={open} onOpenChange={setOpen}>
      <TooltipProvider>
        <Tooltip>
          <TooltipTrigger asChild>
            <DrawerTrigger asChild>
              <Button variant="ghost" size="icon" className="h-4 w-4 ml-1">
                <HelpCircle className="h-4 w-4" />
                <span className="sr-only">How to get YouTube URL</span>
              </Button>
            </DrawerTrigger>
          </TooltipTrigger>
          <TooltipContent>
            <p>Click for help on getting a YouTube URL</p>
          </TooltipContent>
        </Tooltip>
      </TooltipProvider>
      <DrawerContent>
        <DrawerHeader className="text-left">
          <DrawerTitle>How to get a YouTube URL</DrawerTitle>
          <DrawerDescription>Follow these steps to get a YouTube video URL:</DrawerDescription>
        </DrawerHeader>
        <YouTubeUrlHelpContent />
        <DrawerFooter className="pt-2">
          <DrawerClose asChild>
            <Button variant="outline">Close</Button>
          </DrawerClose>
        </DrawerFooter>
      </DrawerContent>
    </Drawer>
  );
}

export default function ImportVideos() {
  const [state, formAction] = useFormState(validateAndSubmitYoutubeUrl, {
    message: '',
    success: false,
  });

  return (
    <div className="w-full">
      <div className="flex justify-between items-center pt-4 px-4">
        <div className="flex items-center gap-2">
          <h1 className="text-xl sm:text-2xl font-semibold tracking-tighter text-neutral-900 dark:text-neutral-100">
            Import Videos{' '}
          </h1>
          <Badge variant="outline" className="tracking-tight">
            Coming Soon
          </Badge>
        </div>
      </div>
      <div className="p-4">
        <div className="flex items-center justify-center border border-dashed border-neutral-200 dark:border-neutral-700 rounded-xl">
          <div className="text-left w-full p-4">
            <form action={formAction} className="space-y-2">
              <div className="flex items-center">
                <Label htmlFor="youtubeUrl">YouTube URL</Label>
              </div>
              <div className="flex flex-col sm:flex-row gap-2 just">
                <div className="space-y-2 w-full">
                  <Input
                    id="youtubeUrl"
                    name="youtubeUrl"
                    className="w-full"
                    placeholder="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
                  />
                </div>
                <SubmitButton />
              </div>
              {state.message && (
                <p className={`text-sm ${state.success ? 'text-green-500' : 'text-red-500'}`}>
                  {state.message}
                </p>
              )}
            </form>
          </div>
        </div>
      </div>
    </div>
  );
}



================================================
FILE: components/ui/dashboard/SearchCenter.tsx
================================================
'use client';

import React, { useState, useEffect, useMemo } from 'react';
import { Button } from '@/components/ui/base/button';
import { Input } from '@/components/ui/base/input';
import { Dot, Search } from 'lucide-react';
import ClipsList from './ClipsList';
import { useId } from 'react';
import Fuse from 'fuse.js';
import { useUserVideos } from '@/hooks/use-user-videos';

const shows = [
  {
    id: 'jumanji',
    name: 'Jumanji',
    color: '#228B22',
  },
];

// Fuse.js options
const fuseOptions = {
  keys: ['title'],
  threshold: 0.3, // 0.0 = perfect match, 1.0 = match anything
  distance: 100, // How far to search for matches
  minMatchCharLength: 1,
};

interface RecommendedClip {
  id: string | number;
  title: string;
  duration: string;
  thumbnail: string;
  show: string;
  difficulty: string;
  dialect: string;
  dialectFlag: string;
}

const recommendedClips: RecommendedClip[] = [
  {
    id: 'Y82ck2bct8sbG',
    title: 'Jumanji: The Next Level from Sony Pictures Entertainment',
    duration: '9:35',
    thumbnail: '/images/thumbnails/jumanji-next-level-full-res.jpg',
    show: 'jumanji',
    difficulty: 'Medium',
    dialect: 'US Midlands',
    dialectFlag: '🇺🇸',
  },
];

interface RevisitClip {
  id: string;
  title: string;
  thumbnail: string;
  vtt: string | null;
  video: string;
  link: string | null;
  badge: string | null;
  difficulty: string | null;
  dialect: string | null;
  dialectFlag: string | null;
  dialectIcon: string | null;
  completedSections: number | null;
  duration: string | null;
  addedAt: Date | null;
  lastWatched: Date | null;
}

interface SearchCenterProps {}

export default function SearchCenter({}: SearchCenterProps) {
  const [activeShow, setActiveShow] = useState<string | null>(null);
  const [searchQuery, setSearchQuery] = useState('');
  const { videos: userClips, isLoading, mutate: refreshUserVideos } = useUserVideos();
  const [filteredRevisitClips, setFilteredRevisitClips] = useState<RevisitClip[]>([]);
  const [filteredRecommendedClips, setFilteredRecommendedClips] = useState(recommendedClips);
  const searchId = useId();

  const revisitFuse = useMemo(() => new Fuse(userClips, fuseOptions), [userClips]);
  const recommendedFuse = useMemo(() => new Fuse(recommendedClips, fuseOptions), []);

  useEffect(() => {
    let revisitResults = [...userClips];
    let recommendedResults = [...recommendedClips];

    if (activeShow) {
      const showMatch = shows.find(show => show.id === activeShow);
      const showName = showMatch?.name.toLowerCase() || '';

      revisitResults = revisitResults.filter(clip => clip.title.toLowerCase().includes(showName));
      recommendedResults = recommendedResults.filter(clip =>
        clip.title.toLowerCase().includes(showName),
      );
    }

    if (searchQuery) {
      const filteredRevisitFuse = new Fuse(revisitResults, fuseOptions);
      const filteredRecommendedFuse = new Fuse(recommendedResults, fuseOptions);

      revisitResults = filteredRevisitFuse.search(searchQuery).map(result => result.item);
      recommendedResults = filteredRecommendedFuse.search(searchQuery).map(result => result.item);
    }

    const userClipIds = revisitResults.map(clip => clip.id.toString());

    recommendedResults = recommendedResults.filter(
      clip => !userClipIds.includes(clip.id.toString()),
    );

    setFilteredRevisitClips(revisitResults);
    setFilteredRecommendedClips(recommendedResults);
  }, [searchQuery, activeShow, userClips]);

  const handleSearch = (e: React.FormEvent) => {
    e.preventDefault();
  };

  const handleVideoAdded = async (videoId: string) => {
    try {
      console.log('Video added:', videoId);

      await refreshUserVideos();

      const updateEvent = new CustomEvent('koellabs:userVideosUpdated', {
        detail: {
          timestamp: Date.now(),
          videoId: videoId,
          action: 'add',
        },
        bubbles: true,
      });

      window.dispatchEvent(updateEvent);
    } catch (error) {
      console.error('Error refreshing user videos:', error);
    }
  };

  return (
    <div className="w-full">
      <div className="flex flex-col gap-4 w-full h-fit">
        <div className="flex gap-2 w-full h-fit pt-4.5 px-4.5">
          <h1 className="text-2xl font-semibold text-black dark:text-white tracking-tighter">
            Search Clips
          </h1>
        </div>

        {/* Search Bar */}
        <form onSubmit={handleSearch} className="flex w-full gap-2 px-4">
          <div className="space-y-2 w-full">
            <div className="flex gap-1 w-full relative">
              <div className="pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 text-muted-foreground/80 peer-disabled:opacity-50">
                <Search size={16} strokeWidth={2} aria-hidden="true" />
              </div>
              <Input
                id={searchId}
                value={searchQuery}
                onChange={e => setSearchQuery(e.target.value)}
                className="flex-1 tracking-tight w-full rounded-full focus-visible:ring-neutral-500 focus-visible:ring-1 pl-8"
                placeholder="Search for your favorite clips, shows, or movies..."
                type="text"
              />
              <Button variant="outline" className="rounded-full tracking-tight h-10 px-4">
                Search
              </Button>
            </div>
          </div>
        </form>

        {/* Show Tabs */}
        <div className="flex gap-1 overflow-x-auto overflow-y-hidden scrollbar-hide px-4 pb-6">
          <Button
            size="badge"
            variant="outline"
            onClick={() => setActiveShow(null)}
            className={`tracking-tight ${activeShow === null ? ' border border-neutral-500 dark:border-neutral-700' : ''}`}
          >
            <div className="w-4 overflow-hidden justify-center items-center grid pr-1.5 -ml-0.5">
              <Dot className="size-12 text-black dark:text-white" />
            </div>
            All Shows
          </Button>
          {shows.map(show => (
            <Button
              key={show.id}
              size="badge"
              variant="outline"
              onClick={() => setActiveShow(show.id)}
              className={`tracking-tight ${activeShow === show.id ? ' border border-neutral-500 dark:border-neutral-700' : ''}`}
            >
              <div className="w-4 overflow-hidden justify-center items-center grid pr-1.5 -ml-0.5">
                <Dot className="size-12 text-black dark:text-white" style={{ color: show.color }} />
              </div>
              {show.name}
            </Button>
          ))}
        </div>
      </div>

      <div className="h-px w-full border-t border-dashed"></div>

      {/* Display filtered clips with loading states */}
      <div>
        {isLoading ? (
          <>
            {/* Skeleton for Previously Practiced */}
            <div className="w-full">
              <div className="flex justify-between items-center p-4">
                <div className="h-8 bg-neutral-200 dark:bg-neutral-800 rounded w-48 animate-pulse"></div>
              </div>
              <div className="relative">
                <div className="overflow-x-scroll pb-4 scrollbar-hide">
                  <div className="flex space-x-3 px-4">
                    {Array(3)
                      .fill(0)
                      .map((_, index) => (
                        <div
                          key={`skeleton-revisit-${index}`}
                          className="flex-none w-[200px] sm:w-[364px] animate-pulse"
                        >
                          <div className="rounded-lg bg-neutral-200 dark:bg-neutral-800 aspect-video mb-2"></div>
                          <div className="h-4 bg-neutral-200 dark:bg-neutral-800 rounded w-3/4 mb-2"></div>
                          <div className="flex justify-between">
                            <div className="h-3 bg-neutral-200 dark:bg-neutral-800 rounded w-1/3"></div>
                            <div className="h-3 bg-neutral-200 dark:bg-neutral-800 rounded w-1/3"></div>
                          </div>
                        </div>
                      ))}
                  </div>
                </div>
              </div>
            </div>

            {/* Skeleton for Recommended */}
            <div className="w-full mt-4">
              <div className="flex justify-between items-center p-4">
                <div className="h-8 bg-neutral-200 dark:bg-neutral-800 rounded w-48 animate-pulse"></div>
              </div>
              <div className="relative">
                <div className="overflow-x-scroll pb-4 scrollbar-hide">
                  <div className="flex space-x-3 px-4">
                    {Array(4)
                      .fill(0)
                      .map((_, index) => (
                        <div
                          key={`skeleton-recommended-${index}`}
                          className="flex-none w-[200px] sm:w-[364px] animate-pulse"
                        >
                          <div className="rounded-lg bg-neutral-200 dark:bg-neutral-800 aspect-video mb-2"></div>
                          <div className="h-4 bg-neutral-200 dark:bg-neutral-800 rounded w-3/4 mb-2"></div>
                          <div className="flex justify-between">
                            <div className="h-3 bg-neutral-200 dark:bg-neutral-800 rounded w-1/3"></div>
                            <div className="h-3 bg-neutral-200 dark:bg-neutral-800 rounded w-1/3"></div>
                          </div>
                        </div>
                      ))}
                  </div>
                </div>
              </div>
            </div>
          </>
        ) : (
          <>
            {/* Only show sections if there are matching results or no search/filter is applied */}
            {(filteredRevisitClips.length > 0 || (!searchQuery && !activeShow)) && (
              <ClipsList
                title="Previously Practiced"
                clips={filteredRevisitClips}
                isRevisitList={true}
              />
            )}

            {/* Only show recommended section if there are matching results */}
            {filteredRecommendedClips.length > 0 && (
              <ClipsList
                title="Recommended For You"
                clips={filteredRecommendedClips}
                onVideoAdded={handleVideoAdded}
              />
            )}
          </>
        )}
      </div>

      {/* Show "No clips found" only when there are no results for either section */}
      {!isLoading && filteredRevisitClips.length === 0 && filteredRecommendedClips.length === 0 && (
        <div className="flex flex-col gap-1 px-4 w-full justify-center items-center relative">
          <div className="relative xl:mt-48 mt-24 mb-8">
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="411"
              height="239"
              fill="none"
              viewBox="0 0 411 239"
              className="shadow-lg rounded-[14px] mb-12 absolute top-0 left-0 translate-x-[30px] translate-y-[30px] rotate-[3deg] empty-state-right dark:block hidden"
            >
              <g clipPath="url(#clip0_2588_330)">
                <rect width="411" height="239" fill="#27272A" rx="14"></rect>
                <rect
                  width="410"
                  height="238"
                  x="0.5"
                  y="0.5"
                  fill="#212121"
                  stroke="#2F2F2F"
                  rx="13.5"
                ></rect>
                <rect width="392" height="194" x="10" y="11" fill="#2F2F2F" rx="6"></rect>
                <rect
                  width="308"
                  height="16"
                  fill="#2F2F2F"
                  rx="6"
                  transform="matrix(1 0 0 -1 10 227)"
                ></rect>
                <rect
                  width="36"
                  height="16"
                  fill="#2F2F2F"
                  rx="6"
                  transform="matrix(1 0 0 -1 366 227)"
                ></rect>
                <path
                  fill="#3B3B3B"
                  d="M189.328 82.777c0-5.093 5.63-8.174 9.92-5.428l40.192 25.722c3.961 2.536 3.961 8.322 0 10.858l-40.192 25.722c-4.29 2.746-9.92-.335-9.92-5.428z"
                ></path>
              </g>
              <defs>
                <clipPath id="clip0_2588_330">
                  <rect width="411" height="239" fill="#fff" rx="14"></rect>
                </clipPath>
              </defs>
            </svg>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="411"
              height="239"
              fill="none"
              viewBox="0 0 411 239"
              className="shadow-lg rounded-[14px] mb-12 z-10 relative empty-state-center hidden dark:block"
            >
              <g clipPath="url(#clip0_2588_330)">
                <rect width="411" height="239" fill="#27272A" rx="14"></rect>
                <rect
                  width="410"
                  height="238"
                  x="0.5"
                  y="0.5"
                  fill="#212121"
                  stroke="#2F2F2F"
                  rx="13.5"
                ></rect>
                <rect width="392" height="194" x="10" y="11" fill="#2F2F2F" rx="6"></rect>
                <rect
                  width="308"
                  height="16"
                  fill="#2F2F2F"
                  rx="6"
                  transform="matrix(1 0 0 -1 10 227)"
                ></rect>
                <rect
                  width="36"
                  height="16"
                  fill="#2F2F2F"
                  rx="6"
                  transform="matrix(1 0 0 -1 366 227)"
                ></rect>
                <path
                  fill="#3B3B3B"
                  d="M189.328 82.777c0-5.093 5.63-8.174 9.92-5.428l40.192 25.722c3.961 2.536 3.961 8.322 0 10.858l-40.192 25.722c-4.29 2.746-9.92-.335-9.92-5.428z"
                ></path>
              </g>
              <defs>
                <clipPath id="clip0_2588_330">
                  <rect width="411" height="239" fill="#fff" rx="14"></rect>
                </clipPath>
              </defs>
            </svg>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="411"
              height="239"
              fill="none"
              viewBox="0 0 411 239"
              className="shadow-lg rounded-[14px] mb-12 absolute top-0 left-0 translate-x-[30px] translate-y-[30px] rotate-[3deg] empty-state-right dark:block hidden"
            >
              <g clipPath="url(#clip0_2588_330)">
                <rect width="411" height="239" fill="#27272A" rx="14"></rect>
                <rect
                  width="410"
                  height="238"
                  x="0.5"
                  y="0.5"
                  fill="#212121"
                  stroke="#2F2F2F"
                  rx="13.5"
                ></rect>
                <rect width="392" height="194" x="10" y="11" fill="#2F2F2F" rx="6"></rect>
                <rect
                  width="308"
                  height="16"
                  fill="#2F2F2F"
                  rx="6"
                  transform="matrix(1 0 0 -1 10 227)"
                ></rect>
                <rect
                  width="36"
                  height="16"
                  fill="#2F2F2F"
                  rx="6"
                  transform="matrix(1 0 0 -1 366 227)"
                ></rect>
                <path
                  fill="#3B3B3B"
                  d="M189.328 82.777c0-5.093 5.63-8.174 9.92-5.428l40.192 25.722c3.961 2.536 3.961 8.322 0 10.858l-40.192 25.722c-4.29 2.746-9.92-.335-9.92-5.428z"
                ></path>
              </g>
              <defs>
                <clipPath id="clip0_2588_330">
                  <rect width="411" height="239" fill="#fff" rx="14"></rect>
                </clipPath>
              </defs>
            </svg>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="411"
              height="239"
              fill="none"
              viewBox="0 0 411 239"
              className="shadow-lg rounded-[14px] mb-12 absolute top-0 left-0 translate-x-[-30px] -translate-y-[30px] rotate-[-3deg] empty-state-left hidden dark:block"
            >
              <g clipPath="url(#clip0_2588_330)">
                <rect width="411" height="239" fill="#27272A" rx="14"></rect>
                <rect
                  width="410"
                  height="238"
                  x="0.5"
                  y="0.5"
                  fill="#212121"
                  stroke="#2F2F2F"
                  rx="13.5"
                ></rect>
                <rect width="392" height="194" x="10" y="11" fill="#2F2F2F" rx="6"></rect>
                <rect
                  width="308"
                  height="16"
                  fill="#2F2F2F"
                  rx="6"
                  transform="matrix(1 0 0 -1 10 227)"
                ></rect>
                <rect
                  width="36"
                  height="16"
                  fill="#2F2F2F"
                  rx="6"
                  transform="matrix(1 0 0 -1 366 227)"
                ></rect>
                <path
                  fill="#3B3B3B"
                  d="M189.328 82.777c0-5.093 5.63-8.174 9.92-5.428l40.192 25.722c3.961 2.536 3.961 8.322 0 10.858l-40.192 25.722c-4.29 2.746-9.92-.335-9.92-5.428z"
                ></path>
              </g>
              <defs>
                <clipPath id="clip0_2588_330">
                  <rect width="411" height="239" fill="#fff" rx="14"></rect>
                </clipPath>
              </defs>
            </svg>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="411"
              height="239"
              fill="none"
              className="shadow-lg rounded-[14px] mb-12 z-10 relative empty-state-center dark:hidden"
              viewBox="0 0 411 239"
            >
              <g clipPath="url(#clip0_2569_247)">
                <rect
                  width="410"
                  height="238"
                  x="0.5"
                  y="0.5"
                  fill="#fff"
                  stroke="#E1E1E1"
                  rx="13.5"
                ></rect>
                <rect width="392" height="194" x="10" y="11" fill="#F4F4F4" rx="6"></rect>
                <rect
                  width="308"
                  height="16"
                  fill="#F4F4F4"
                  rx="6"
                  transform="matrix(1 0 0 -1 10 227)"
                ></rect>
                <rect
                  width="36"
                  height="16"
                  fill="#F4F4F4"
                  rx="6"
                  transform="matrix(1 0 0 -1 366 227)"
                ></rect>
                <path
                  fill="#000"
                  fillOpacity="0.04"
                  d="M189.328 82.777c0-5.093 5.63-8.174 9.92-5.428l40.192 25.722c3.961 2.536 3.961 8.322 0 10.858l-40.192 25.722c-4.29 2.746-9.92-.335-9.92-5.428z"
                ></path>
              </g>
              <defs>
                <clipPath id="clip0_2569_247">
                  <rect width="411" height="239" fill="#fff" rx="14"></rect>
                </clipPath>
              </defs>
            </svg>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="411"
              height="239"
              fill="none"
              className="shadow-lg rounded-[14px] mb-12 absolute top-0 left-0 translate-x-[30px] translate-y-[30px] rotate-[3deg] empty-state-right dark:hidden"
              viewBox="0 0 411 239"
            >
              <g clipPath="url(#clip0_2569_247)">
                <rect
                  width="410"
                  height="238"
                  x="0.5"
                  y="0.5"
                  fill="#fff"
                  stroke="#E1E1E1"
                  rx="13.5"
                ></rect>
                <rect width="392" height="194" x="10" y="11" fill="#F4F4F4" rx="6"></rect>
                <rect
                  width="308"
                  height="16"
                  fill="#F4F4F4"
                  rx="6"
                  transform="matrix(1 0 0 -1 10 227)"
                ></rect>
                <rect
                  width="36"
                  height="16"
                  fill="#F4F4F4"
                  rx="6"
                  transform="matrix(1 0 0 -1 366 227)"
                ></rect>
                <path
                  fill="#000"
                  fillOpacity="0.04"
                  d="M189.328 82.777c0-5.093 5.63-8.174 9.92-5.428l40.192 25.722c3.961 2.536 3.961 8.322 0 10.858l-40.192 25.722c-4.29 2.746-9.92-.335-9.92-5.428z"
                ></path>
              </g>
              <defs>
                <clipPath id="clip0_2569_247">
                  <rect width="411" height="239" fill="#fff" rx="14"></rect>
                </clipPath>
              </defs>
            </svg>
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="411"
              height="239"
              fill="none"
              className="shadow-lg rounded-[14px] mb-12 absolute top-0 left-0 translate-x-[-30px] -translate-y-[30px] rotate-[-3deg] empty-state-left dark:hidden"
              viewBox="0 0 411 239"
            >
              <g clipPath="url(#clip0_2569_247)">
                <rect
                  width="410"
                  height="238"
                  x="0.5"
                  y="0.5"
                  fill="#fff"
                  stroke="#E1E1E1"
                  rx="13.5"
                ></rect>
                <rect width="392" height="194" x="10" y="11" fill="#F4F4F4" rx="6"></rect>
                <rect
                  width="308"
                  height="16"
                  fill="#F4F4F4"
                  rx="6"
                  transform="matrix(1 0 0 -1 10 227)"
                ></rect>
                <rect
                  width="36"
                  height="16"
                  fill="#F4F4F4"
                  rx="6"
                  transform="matrix(1 0 0 -1 366 227)"
                ></rect>
                <path
                  fill="#000"
                  fillOpacity="0.04"
                  d="M189.328 82.777c0-5.093 5.63-8.174 9.92-5.428l40.192 25.722c3.961 2.536 3.961 8.322 0 10.858l-40.192 25.722c-4.29 2.746-9.92-.335-9.92-5.428z"
                ></path>
              </g>
              <defs>
                <clipPath id="clip0_2569_247">
                  <rect width="411" height="239" fill="#fff" rx="14"></rect>
                </clipPath>
              </defs>
            </svg>
          </div>
          <h2 className="text-lg font-medium text-black dark:text-white tracking-tighter">
            No Clips Found
          </h2>
          <p className="text-sm text-muted-foreground dark:text-muted-foreground text-balance">
            Try searching for something different.
          </p>
        </div>
      )}
    </div>
  );
}



================================================
FILE: components/ui/dashboard/outdated/RecommendedClips.tsx
================================================
'use client';

import * as React from 'react';
import { Card, CardContent } from '@/components/ui/base/card';
import { ChevronLeft, ChevronRight } from 'lucide-react';
import { Button } from '@/components/ui/base/button';
import { cn } from '@/lib/styles';
import Image from 'next/image';

interface Clip {
  id: number;
  title: string;
  duration: string;
  thumbnail: string;
}

interface RecommendedClipsProps {
  clips: Clip[];
}

export default function RecommendedClips({ clips }: RecommendedClipsProps) {
  const scrollContainerRef = React.useRef<HTMLDivElement>(null);
  const [showLeftArrow, setShowLeftArrow] = React.useState(false);
  const [showRightArrow, setShowRightArrow] = React.useState(true);
  const [isExpanded, setIsExpanded] = React.useState(false);

  const handleScroll = () => {
    if (scrollContainerRef.current) {
      const { scrollLeft, scrollWidth, clientWidth } = scrollContainerRef.current;
      setShowLeftArrow(scrollLeft > 0);
      setShowRightArrow(scrollLeft < scrollWidth - clientWidth - 10);
    }
  };

  const scroll = (direction: 'left' | 'right') => {
    if (scrollContainerRef.current) {
      const scrollAmount = scrollContainerRef.current.clientWidth / 2;
      scrollContainerRef.current.scrollBy({
        left: direction === 'left' ? -scrollAmount : scrollAmount,
        behavior: 'smooth',
      });
    }
  };

  React.useEffect(() => {
    const scrollContainer = scrollContainerRef.current;
    if (scrollContainer) {
      scrollContainer.addEventListener('scroll', handleScroll);
      return () => scrollContainer.removeEventListener('scroll', handleScroll);
    }
  }, []);

  const toggleExpand = () => {
    setIsExpanded(!isExpanded);
  };

  const renderClip = (clip: Clip) => (
    <div
      key={clip.id}
      className={cn('flex-none w-[200px] sm:w-[364px]', {
        'w-full sm:w-1/2 md:w-1/3 lg:w-1/4 px-1.5 pb-6': isExpanded,
      })}
    >
      <Card className="border text-neutral-500 dark:text-neutral-400 border-accent dark:border-accent-dark rounded-lg bg-neutral-200/50 dark:bg-neutral-800/50 border-neutral-300 dark:border-neutral-700">
        <CardContent className="flex aspect-video items-center justify-center p-0">
          {/* <span className="font-medium text-xs">Video {clip.id}</span> */}
          <Image
            src={clip.thumbnail}
            alt={clip.title}
            width={298}
            height={167.33}
            className="w-full h-full object-cover rounded-[7px]"
          />
        </CardContent>
      </Card>
      <div className="flex justify-between mt-1.5">
        <h2 className="text-xs font-medium tracking-tight ml-1 line-clamp-1 text-neutral-700 dark:text-neutral-300">
          {clip.title}
        </h2>
        <p className="text-xs font-medium mr-1 text-neutral-500 dark:text-neutral-400">
          {clip.duration}
        </p>
      </div>
    </div>
  );

  const showViewAllButton = clips.length >= 5;

  return (
    <div className="w-full">
      <div className="flex justify-between items-center p-4">
        <h1 className="text-xl sm:text-2xl font-semibold tracking-tighter text-neutral-900 dark:text-neutral-100">
          Recommended Videos
        </h1>
        {showViewAllButton && (
          <Button
            onClick={toggleExpand}
            variant="outline"
            size="sm"
            className="rounded-xl tracking-tight dark:border-neutral-700 dark:text-neutral-300"
          >
            {isExpanded ? 'Collapse' : 'View All'}
          </Button>
        )}
      </div>
      <div className={cn('relative', { 'px-5': isExpanded })}>
        {isExpanded ? (
          <div className="flex flex-wrap -mx-2">{clips.map(renderClip)}</div>
        ) : (
          <div
            ref={scrollContainerRef}
            className="overflow-x-scroll pb-4 scrollbar-hide snap-x snap-mandatory"
          >
            <div className="flex space-x-3 px-4">
              {clips.map((clip, index) => (
                <div
                  key={clip.id}
                  className={cn('snap-center', {
                    'pr-4': index === clips.length - 1,
                  })}
                >
                  {renderClip(clip)}
                </div>
              ))}
            </div>
          </div>
        )}
        {!isExpanded && showLeftArrow && (
          <Button
            variant="outline"
            size="icon"
            className="absolute left-2 top-1/2 -translate-y-1/2 bg-white dark:bg-neutral-800 border border-accent dark:border-accent-dark rounded-full h-8 w-8"
            onClick={() => scroll('left')}
          >
            <ChevronLeft className="h-4 w-4" />
          </Button>
        )}
        {!isExpanded && showRightArrow && (
          <Button
            variant="outline"
            size="icon"
            className="absolute right-2 top-1/2 -translate-y-1/2 bg-white dark:bg-neutral-800 border border-accent dark:border-accent-dark rounded-full h-8 w-8"
            onClick={() => scroll('right')}
          >
            <ChevronRight className="h-4 w-4" />
          </Button>
        )}
      </div>
    </div>
  );
}



================================================
FILE: components/ui/dashboard/outdated/RevisitClips.tsx
================================================
'use client';

import * as React from 'react';
import { Card, CardContent } from '@/components/ui/base/card';
import { ChevronLeft, ChevronRight } from 'lucide-react';
import { Button } from '@/components/ui/base/button';
import { cn } from '@/lib/styles';
import Image from 'next/image';

interface Clip {
  title: string;
  thumbnail: string;
  vtt: string;
  video: string;
  link: string;
  id: string;
  badge: string;
  dialect: string;
  dialectIcon: string;
  completedSections: number;
  duration: string;
}

interface RevisitVideosProps {
  clips: Clip[];
}

export default function RevisitVideos({ clips }: RevisitVideosProps) {
  const scrollContainerRef = React.useRef<HTMLDivElement>(null);
  const [showLeftArrow, setShowLeftArrow] = React.useState(false);
  const [showRightArrow, setShowRightArrow] = React.useState(false);
  const [isExpanded, setIsExpanded] = React.useState(false);

  const handleScroll = () => {
    if (scrollContainerRef.current) {
      const { scrollLeft, scrollWidth, clientWidth } = scrollContainerRef.current;
      setShowLeftArrow(scrollLeft > 0);
      setShowRightArrow(scrollLeft < scrollWidth - clientWidth - 10);
    }
  };

  const scroll = (direction: 'left' | 'right') => {
    if (scrollContainerRef.current) {
      const scrollAmount = scrollContainerRef.current.clientWidth / 2;
      scrollContainerRef.current.scrollBy({
        left: direction === 'left' ? -scrollAmount : scrollAmount,
        behavior: 'smooth',
      });
    }
  };

  React.useEffect(() => {
    const scrollContainer = scrollContainerRef.current;
    if (scrollContainer) {
      scrollContainer.addEventListener('scroll', handleScroll);
      return () => scrollContainer.removeEventListener('scroll', handleScroll);
    }
  }, []);

  const toggleExpand = () => {
    setIsExpanded(!isExpanded);
  };

  const renderClip = (clip: Clip, index: number) => (
    <div
      key={index}
      className={cn('flex-none w-[200px] sm:w-[364px]', {
        'w-full sm:w-1/2 md:w-1/3 lg:w-1/4 px-1.5 pb-6': isExpanded,
      })}
    >
      <a href={`dashboard/${clip.id}`} className="block">
        <Card className="border text-neutral-500 relative overflow-hidden dark:text-neutral-400 border-accent dark:border-accent-dark rounded-lg bg-neutral-200/50 dark:bg-neutral-800/50 border-neutral-300 dark:border-neutral-700">
          <CardContent className="flex aspect-video items-center justify-center p-2">
            {/* <span className="font-medium text-xs">Video {index + 1}</span> */}
            <Image
              src={clip.thumbnail}
              alt={clip.title}
              width={298}
              height={167.33}
              className="w-full h-full object-cover absolute inset-0"
            />
          </CardContent>
        </Card>
        <div className="flex justify-between mt-1.5">
          <h2 className="text-xs font-medium tracking-tight ml-1 line-clamp-1 text-neutral-700 dark:text-neutral-300">
            {clip.title}
          </h2>
          <p className="text-xs font-medium mr-1 text-neutral-500 dark:text-neutral-400">
            {clip.duration}
          </p>
        </div>
      </a>
    </div>
  );

  const showViewAllButton = clips.length >= 5;

  return (
    <div className="w-full">
      <div className="flex justify-between items-center p-4">
        <h1 className="text-xl sm:text-2xl font-semibold tracking-tighter text-neutral-900 dark:text-neutral-100">
          Revisit Videos
        </h1>
        {showViewAllButton && (
          <Button
            onClick={toggleExpand}
            variant="outline"
            size="sm"
            className="rounded-2xl tracking-tight dark:border-neutral-700 dark:text-neutral-300"
          >
            {isExpanded ? 'Collapse' : 'View All'}
          </Button>
        )}
      </div>
      <div className={cn('relative', { 'px-5': isExpanded })}>
        {isExpanded ? (
          <div className="flex flex-wrap -mx-2">
            {clips.map((clip, index) => renderClip(clip, index))}
          </div>
        ) : (
          <div
            ref={scrollContainerRef}
            className="overflow-x-scroll pb-4 scrollbar-hide snap-x snap-mandatory"
          >
            <div className="flex space-x-3 px-4">
              {clips.map((clip, index) => (
                <div
                  key={index}
                  className={cn('snap-center', {
                    'pr-4': index === clips.length - 1,
                  })}
                >
                  {renderClip(clip, index)}
                </div>
              ))}
            </div>
          </div>
        )}
        {!isExpanded && showLeftArrow && (
          <Button
            variant="outline"
            size="icon"
            className="absolute left-2 top-1/2 -translate-y-1/2 bg-white dark:bg-neutral-800 border border-accent dark:border-accent-dark rounded-full h-8 w-8"
            onClick={() => scroll('left')}
          >
            <ChevronLeft className="h-4 w-4" />
          </Button>
        )}
        {!isExpanded && showRightArrow && (
          <Button
            variant="outline"
            size="icon"
            className="absolute right-2 top-1/2 -translate-y-1/2 bg-white dark:bg-neutral-800 border border-accent dark:border-accent-dark rounded-full h-8 w-8"
            onClick={() => scroll('right')}
          >
            <ChevronRight className="h-4 w-4" />
          </Button>
        )}
      </div>
    </div>
  );
}



================================================
FILE: components/ui/magicui/animated-beam.jsx
================================================
'use client';
import { useEffect, useId, useState } from 'react';
import { motion } from 'framer-motion';

import { cn } from '@/lib/styles';

export const AnimatedBeam = ({
  className,
  containerRef,
  fromRef,
  toRef,
  curvature = 0,
  reverse = false, // Include the reverse prop
  duration = Math.random() * 3 + 4,
  delay = 0,
  pathColor = 'gray',
  pathWidth = 2,
  pathOpacity = 0.2,
  gradientStartColor = '#ffaa40',
  gradientStopColor = '#9c40ff',
  startXOffset = 0,
  startYOffset = 0,
  endXOffset = 0,
  endYOffset = 0,
}) => {
  const id = useId();
  const [pathD, setPathD] = useState('');
  const [svgDimensions, setSvgDimensions] = useState({ width: 0, height: 0 });

  // Calculate the gradient coordinates based on the reverse prop
  const gradientCoordinates = reverse
    ? {
        x1: ['90%', '-10%'],
        x2: ['100%', '0%'],
        y1: ['0%', '0%'],
        y2: ['0%', '0%'],
      }
    : {
        x1: ['10%', '110%'],
        x2: ['0%', '100%'],
        y1: ['0%', '0%'],
        y2: ['0%', '0%'],
      };

  useEffect(() => {
    const updatePath = () => {
      if (containerRef.current && fromRef.current && toRef.current) {
        const containerRect = containerRef.current.getBoundingClientRect();
        const rectA = fromRef.current.getBoundingClientRect();
        const rectB = toRef.current.getBoundingClientRect();

        const svgWidth = containerRect.width;
        const svgHeight = containerRect.height;
        setSvgDimensions({ width: svgWidth, height: svgHeight });

        const startX = rectA.left - containerRect.left + rectA.width / 2 + startXOffset;
        const startY = rectA.top - containerRect.top + rectA.height / 2 + startYOffset;
        const endX = rectB.left - containerRect.left + rectB.width / 2 + endXOffset;
        const endY = rectB.top - containerRect.top + rectB.height / 2 + endYOffset;

        const controlY = startY - curvature;
        const d = `M ${startX},${startY} Q ${(startX + endX) / 2},${controlY} ${endX},${endY}`;
        setPathD(d);
      }
    };

    // Initialize ResizeObserver
    const resizeObserver = new ResizeObserver(entries => {
      // For all entries, recalculate the path
      for (let entry of entries) {
        updatePath();
      }
    });

    // Observe the container element
    if (containerRef.current) {
      resizeObserver.observe(containerRef.current);
    }

    // Call the updatePath initially to set the initial path
    updatePath();

    // Clean up the observer on component unmount
    return () => {
      resizeObserver.disconnect();
    };
  }, [containerRef, fromRef, toRef, curvature, startXOffset, startYOffset, endXOffset, endYOffset]);

  return (
    <svg
      fill="none"
      width={svgDimensions.width}
      height={svgDimensions.height}
      xmlns="http://www.w3.org/2000/svg"
      className={cn('pointer-events-none absolute left-0 top-0 transform-gpu stroke-2', className)}
      viewBox={`0 0 ${svgDimensions.width} ${svgDimensions.height}`}
    >
      <path
        d={pathD}
        stroke={pathColor}
        strokeWidth={pathWidth}
        strokeOpacity={pathOpacity}
        strokeLinecap="round"
      />
      <path
        d={pathD}
        strokeWidth={pathWidth}
        stroke={`url(#${id})`}
        strokeOpacity="1"
        strokeLinecap="round"
      />
      <defs>
        <motion.linearGradient
          className="transform-gpu"
          id={id}
          gradientUnits={'userSpaceOnUse'}
          initial={{
            x1: '0%',
            x2: '0%',
            y1: '0%',
            y2: '0%',
          }}
          animate={{
            x1: gradientCoordinates.x1,
            x2: gradientCoordinates.x2,
            y1: gradientCoordinates.y1,
            y2: gradientCoordinates.y2,
          }}
          transition={{
            delay,
            duration,
            ease: [0.16, 1, 0.3, 1], // https://easings.net/#easeOutExpo
            repeat: Infinity,
            repeatDelay: 0,
          }}
        >
          <stop stopColor={gradientStartColor} stopOpacity="0"></stop>
          <stop stopColor={gradientStartColor}></stop>
          <stop offset="32.5%" stopColor={gradientStopColor}></stop>
          <stop offset="100%" stopColor={gradientStopColor} stopOpacity="0"></stop>
        </motion.linearGradient>
      </defs>
    </svg>
  );
};



================================================
FILE: components/ui/magicui/bento-grid.jsx
================================================
import { ArrowRightIcon } from '@radix-ui/react-icons';

import { cn } from '@/lib/styles';
import { Button } from '@/components/ui/button';

const BentoGrid = ({ children, className }) => {
  return (
    <div className={cn('grid w-full auto-rows-[22rem] grid-cols-3 gap-4', className)}>
      {children}
    </div>
  );
};

const BentoCard = ({ name, className, background, Icon, description, href, cta }) => (
  <div
    key={name}
    className={cn(
      'group relative col-span-3 flex flex-col justify-between overflow-hidden rounded-xl',
      // light styles
      'bg-white [box-shadow:0_0_0_1px_rgba(0,0,0,.03),0_2px_4px_rgba(0,0,0,.05),0_12px_24px_rgba(0,0,0,.05)]',
      // dark styles
      'transform-gpu dark:bg-black dark:[border:1px_solid_rgba(255,255,255,.1)] dark:[box-shadow:0_-20px_80px_-20px_#ffffff1f_inset]',
      className,
    )}
  >
    <div>{background}</div>
    <div className="pointer-events-none z-10 flex transform-gpu flex-col gap-1 p-6 transition-all duration-300 group-hover:-translate-y-10">
      <Icon className="h-12 w-12 origin-left transform-gpu text-neutral-700 transition-all duration-300 ease-in-out group-hover:scale-75" />
      <h3 className="text-xl font-semibold text-neutral-700 dark:text-neutral-300">{name}</h3>
      <p className="max-w-lg text-neutral-400">{description}</p>
    </div>

    <div
      className={cn(
        'pointer-events-none absolute bottom-0 flex w-full translate-y-10 transform-gpu flex-row items-center p-4 opacity-0 transition-all duration-300 group-hover:translate-y-0 group-hover:opacity-100',
      )}
    >
      <Button variant="ghost" asChild size="sm" className="pointer-events-auto">
        <a href={href}>
          {cta}
          <ArrowRightIcon className="ml-2 h-4 w-4" />
        </a>
      </Button>
    </div>
    <div className="pointer-events-none absolute inset-0 transform-gpu transition-all duration-300 group-hover:bg-black/[.03] dark:group-hover:bg-neutral-800/10" />
  </div>
);

export { BentoCard, BentoGrid };



================================================
FILE: components/ui/magicui/hero-video-dialog.tsx
================================================
'use client';

import { useState } from 'react';
import { AnimatePresence, motion } from 'framer-motion';
import { ArrowUpRight, Play, XIcon } from 'lucide-react';

import { cn } from '@/lib/styles';
import React from 'react';
import Link from 'next/link';

type AnimationStyle =
  | 'from-bottom'
  | 'from-center'
  | 'from-top'
  | 'from-left'
  | 'from-right'
  | 'fade'
  | 'top-in-bottom-out'
  | 'left-in-right-out';

interface HeroVideoProps {
  animationStyle?: AnimationStyle;
  videoSrc: string;
  thumbnailSrc: string;
  thumbnailAlt?: string;
  className?: string;
}

const animationVariants = {
  'from-bottom': {
    initial: { y: '100%', opacity: 0 },
    animate: { y: 0, opacity: 1 },
    exit: { y: '100%', opacity: 0 },
  },
  'from-center': {
    initial: { scale: 0.5, opacity: 0 },
    animate: { scale: 1, opacity: 1 },
    exit: { scale: 0.5, opacity: 0 },
  },
  'from-top': {
    initial: { y: '-100%', opacity: 0 },
    animate: { y: 0, opacity: 1 },
    exit: { y: '-100%', opacity: 0 },
  },
  'from-left': {
    initial: { x: '-100%', opacity: 0 },
    animate: { x: 0, opacity: 1 },
    exit: { x: '-100%', opacity: 0 },
  },
  'from-right': {
    initial: { x: '100%', opacity: 0 },
    animate: { x: 0, opacity: 1 },
    exit: { x: '100%', opacity: 0 },
  },
  fade: {
    initial: { opacity: 0 },
    animate: { opacity: 1 },
    exit: { opacity: 0 },
  },
  'top-in-bottom-out': {
    initial: { y: '-100%', opacity: 0 },
    animate: { y: 0, opacity: 1 },
    exit: { y: '100%', opacity: 0 },
  },
  'left-in-right-out': {
    initial: { x: '-100%', opacity: 0 },
    animate: { x: 0, opacity: 1 },
    exit: { x: '100%', opacity: 0 },
  },
};

export default function HeroVideoDialog({
  animationStyle = 'from-center',
  videoSrc,
  thumbnailSrc,
  thumbnailAlt = 'Video thumbnail',
  className,
}: HeroVideoProps) {
  const [isVideoOpen, setIsVideoOpen] = useState(false);
  const selectedAnimation = animationVariants[animationStyle];

  return (
    <div className={cn('z-1000', className)}>
      <Link href={videoSrc} target="_blank">
        <div className="relative cursor-pointer group">
          <img
            src={thumbnailSrc}
            alt={thumbnailAlt}
            width={1920}
            height={1080}
            className="w-full transition-all duration-200 group-hover:brightness-[0.9] ease-out rounded-xl shadow-lg border"
          />
          <div className="absolute inset-0 flex items-center justify-center group-hover:scale-100 scale-[0.9] transition-all duration-200 ease-out rounded-2xl">
            <div className="bg-sky-900/20 flex items-center justify-center rounded-full backdrop-blur-md size-28">
              <div
                className={`flex items-center justify-center bg-linear-to-b from-black to-sky-900 shadow-md rounded-full size-20 transition-all ease-out duration-200 relative group-hover:scale-[1.2] scale-100`}
              >
                {/* <Play
                  className="size-8 text-white fill-white group-hover:scale-105 scale-100 transition-transform duration-200 ease-out group-hover:hidden"
                  style={{
                    filter:
                      'drop-shadow(0 4px 3px rgb(3 105 161 / 0.07)) drop-shadow(0 2px 2px rgb(3 105 161 / 0.06))',
                  }}
                /> */}
                <ArrowUpRight
                  className="size-8 text-white  group-hover:scale-105 scale-100 transition-transform duration-200 ease-out"
                  style={{
                    filter:
                      'drop-shadow(0 4px 3px rgb(3 105 161 / 0.07)) drop-shadow(0 2px 2px rgb(3 105 161 / 0.06))',
                  }}
                />
              </div>
            </div>
          </div>
        </div>
        <AnimatePresence>
          {isVideoOpen && (
            <motion.div
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              onClick={() => setIsVideoOpen(false)}
              exit={{ opacity: 0 }}
              className="fixed inset-0 z-9999 flex items-center justify-center bg-black/50 backdrop-blur-md"
            >
              <motion.div
                {...selectedAnimation}
                transition={{ type: 'spring', damping: 30, stiffness: 300 }}
                className="relative w-full max-w-4xl aspect-video mx-4 md:mx-0"
              >
                <motion.button className="absolute -top-16 right-0 text-white text-xl bg-neutral-900/50 ring-1 backdrop-blur-md rounded-full p-2 dark:bg-neutral-100/50 dark:text-black">
                  <XIcon className="size-5" />
                </motion.button>
                <div className="size-full border-2 border-white rounded-2xl overflow-hidden isolate z-5000 relative">
                  <iframe
                    src={videoSrc}
                    className="size-full rounded-2xl"
                    allowFullScreen
                    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
                  ></iframe>
                </div>
              </motion.div>
            </motion.div>
          )}
        </AnimatePresence>
      </Link>
    </div>
  );
}



================================================
FILE: components/ui/onboarding/gradient-logo.jsx
================================================
'use client';

import { useEffect, useRef } from 'react';

export default function GradientLogo() {
  const canvasRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    const ctx = canvas.getContext('2d');
    const dpr = window.devicePixelRatio || 1;

    // Set canvas size
    canvas.width = 200 * dpr;
    canvas.height = 200 * dpr;
    canvas.style.width = '200px';
    canvas.style.height = '200px';
    ctx.scale(dpr, dpr);

    // Animation variables
    let animationFrame;
    let hue = 0;

    const drawLogo = () => {
      // Clear canvas
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      // Create gradient
      const gradient = ctx.createLinearGradient(0, 0, 200, 200);
      gradient.addColorStop(0, `hsla(${hue}, 100%, 65%, 1)`);
      gradient.addColorStop(0.5, `hsla(${(hue + 60) % 360}, 100%, 65%, 1)`);
      gradient.addColorStop(1, `hsla(${(hue + 120) % 360}, 100%, 65%, 1)`);

      // Draw circle
      ctx.beginPath();
      ctx.arc(100, 100, 80, 0, Math.PI * 2);
      ctx.fillStyle = 'white';
      ctx.fill();

      // Draw "dub" text
      ctx.font = 'bold 60px sans-serif';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      ctx.fillStyle = gradient;
      ctx.fillText('koel', 100, 100);

      // Update hue for animation
      hue = (hue + 0.5) % 360;

      // Continue animation
      animationFrame = requestAnimationFrame(drawLogo);
    };

    // Start animation
    drawLogo();

    // Cleanup
    return () => {
      cancelAnimationFrame(animationFrame);
    };
  }, []);

  return <canvas ref={canvasRef} className="mx-auto mb-4" width="200" height="200" />;
}



================================================
FILE: components/ui/onboarding/grid-background.jsx
================================================
'use client';

import { useEffect, useRef } from 'react';

export default function GridBackground() {
  const canvasRef = useRef(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;

    const ctx = canvas.getContext('2d');
    const dpr = window.devicePixelRatio || 1;

    // Set canvas size
    const updateCanvasSize = () => {
      canvas.width = window.innerWidth * dpr;
      canvas.height = window.innerHeight * dpr;
      canvas.style.width = `${window.innerWidth}px`;
      canvas.style.height = `${window.innerHeight}px`;
      ctx.scale(dpr, dpr);

      // Clear canvas
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      // Draw grid
      drawGrid();
    };

    // Draw grid lines
    const drawGrid = () => {
      const gridSize = 40;
      const width = window.innerWidth;
      const height = window.innerHeight;

      ctx.strokeStyle = 'rgba(229, 231, 235, 0.3)';
      ctx.lineWidth = 1;

      // Draw vertical lines
      for (let x = 0; x <= width; x += gridSize) {
        ctx.beginPath();
        ctx.moveTo(x, 0);
        ctx.lineTo(x, height);
        ctx.stroke();
      }

      // Draw horizontal lines
      for (let y = 0; y <= height; y += gridSize) {
        ctx.beginPath();
        ctx.moveTo(0, y);
        ctx.lineTo(width, y);
        ctx.stroke();
      }

      // Add gradient overlay
      const centerX = width / 2;
      const centerY = height / 2;

      const gradient = ctx.createRadialGradient(
        centerX,
        centerY,
        0,
        centerX,
        centerY,
        Math.max(width, height) * 0.6,
      );

      gradient.addColorStop(0, 'rgba(186, 230, 253, 0.15)'); // Light blue
      gradient.addColorStop(0.5, 'rgba(125, 211, 252, 0.05)'); // Sky blue
      gradient.addColorStop(1, 'rgba(255, 255, 255, 0)'); // Transparent

      ctx.fillStyle = gradient;
      ctx.fillRect(0, 0, width, height);
    };

    // Initial setup
    updateCanvasSize();

    // Handle resize
    window.addEventListener('resize', updateCanvasSize);

    return () => {
      window.removeEventListener('resize', updateCanvasSize);
    };
  }, []);

  return <canvas ref={canvasRef} className="absolute top-0 left-0 w-full h-full -z-10" />;
}



================================================
FILE: components/ui/onboarding/onboarding-provider.jsx
================================================
'use client';

import { createContext, useContext, useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import KoelBirdRounded from '@/components/ui/base/koel-bird-rounded';

const OnboardingContext = createContext(null);

const OnboardingCompletionLoader = () => {
  return (
    <div className="inset-0 bg-white dark:bg-neutral-950 z-50 flex items-center justify-center h-screen relative">
      <div className="absolute top-0 left-0 w-full h-[5vh] overflow-hidden flex items-end justify-center bg-neutral-50 z-90">
        <div className="flex h-full items-end gap-2 border-b ">
          {Array(500)
            .fill(0)
            .map((_, i) => (
              <div
                key={`top-${i}`}
                className="h-full w-px bg-neutral-200 dark:bg-neutral-800"
              ></div>
            ))}
        </div>
      </div>
      <div className="flex items-center justify-center my-12 relative w-full h-full bg-neutral-50/20 backdrop-blur-md border-y border-neutral-200 transform-gpu dark:border-neutral-800 z-20">
        <div className="flex flex-col items-center justify-center text-center z-10">
          <div className="mb-6">
            <KoelBirdRounded className="w-[100px] h-fit mx-auto" />
          </div>

          <div className="space-y-3">
            <h2 className="text-2xl font-semibold tracking-tighter text-neutral-900 dark:text-neutral-100">
              Customizing your experience
            </h2>
            <p className="text-md text-neutral-500 dark:text-neutral-400 max-w-md text-balance">
              We're setting up your personalized learning journey based on your preferences
            </p>
          </div>

          <div className="mt-6 w-48 h-3 bg-neutral-200 dark:bg-neutral-800 rounded-full overflow-hidden">
            <div
              className="h-full bg-sky-600 rounded-full animate-[loadingBar_0.5s_linear_infinite]"
              style={{ width: '40%' }}
            ></div>
            <style jsx>{`
              @keyframes loadingBar {
                0% {
                  transform: translateX(-100%);
                  width: 50%;
                }
                100% {
                  transform: translateX(100%);
                  width: 100%;
                }
                200% {
                  transform: translateX(-100%);
                  width: 50%;
                }
              }
            `}</style>
          </div>
        </div>

        <div className="absolute bottom-0 left-0 w-full h-[5vh] overflow-hidden flex items-start justify-center bg-neutral-50">
          <div className="flex h-full items-start gap-2 border-t border-neutral-200 dark:border-neutral-800">
            {Array(500)
              .fill(0)
              .map((_, i) => (
                <div
                  key={`bottom-${i}`}
                  className="h-full w-px bg-neutral-200 dark:bg-neutral-800 -mb-12"
                ></div>
              ))}
          </div>
        </div>
      </div>
    </div>
  );
};

export function OnboardingProvider({ children }) {
  const [onboardingData, setOnboardingData] = useState({
    // Getting to Know You (Page 1)
    nativeLanguage: '',
    nativeLanguageCountry: '',
    birthday: '',

    // Language Goals (Page 2)
    targetLanguage: 'english',
    experienceLevel: '',
    learningCity: '',
    challengingWords: '',
  });

  const [isCompleting, setIsCompleting] = useState(false);
  const router = useRouter();

  const updateOnboardingData = (key, value) => {
    setOnboardingData(prev => ({
      ...prev,
      [key]: value,
    }));
  };

  const completeOnboarding = async () => {
    setIsCompleting(true);

    try {
      const response = await fetch('/api/user/preferences', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          nativeLanguage: onboardingData.nativeLanguage,
          nativeLanguageCountry: onboardingData.nativeLanguageCountry,
          birthday: onboardingData.birthday,
          targetLanguage: onboardingData.targetLanguage,
          experienceLevel: onboardingData.experienceLevel,
          learningCity: onboardingData.learningCity,
          challengingWords: onboardingData.challengingWords,
        }),
      });

      if (!response.ok) {
        throw new Error('Failed to save preferences');
      }

      console.log('Onboarding completed with data:', onboardingData);

      router.push('/dashboard');
    } catch (error) {
      console.error('Error completing onboarding:', error);
      setIsCompleting(false);
    }
  };

  return (
    <OnboardingContext.Provider
      value={{
        onboardingData,
        updateOnboardingData,
        completeOnboarding,
        isCompleting,
      }}
    >
      {!isCompleting && children}
      {isCompleting && <OnboardingCompletionLoader />}
    </OnboardingContext.Provider>
  );
}

export const useOnboarding = () => {
  const context = useContext(OnboardingContext);
  if (!context) {
    throw new Error('useOnboarding must be used within an OnboardingProvider');
  }
  return context;
};



================================================
FILE: db/schema.ts
================================================
import { pgTable, varchar, integer, timestamp, text, boolean, json } from 'drizzle-orm/pg-core';
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});
export const db = drizzle(pool);

// Auth
export const users = pgTable('users', {
  id: text('id').primaryKey(),
  name: text('name').notNull(),
  email: text('email').notNull().unique(),
  emailVerified: boolean('email_verified').notNull().default(false),
  image: text('image'),
  createdAt: timestamp('created_at')
    .$defaultFn(() => /* @__PURE__ */ new Date())
    .notNull(),
  updatedAt: timestamp('updated_at')
    .$defaultFn(() => /* @__PURE__ */ new Date())
    .notNull(),

  // extra columns, also add as additional fields in utils/auth.ts
  streak: integer('streak').notNull().default(0),
  stripeId: varchar('stripe_id'),

  // User preferences
  metadata: json('metadata'),
  onboardingCompleted: boolean('onboarding_completed').default(false),
});

export const sessions = pgTable('sessions', {
  id: text('id').primaryKey(),
  expiresAt: timestamp('expires_at').notNull(),
  token: text('token').notNull().unique(),
  createdAt: timestamp('created_at').notNull(),
  updatedAt: timestamp('updated_at').notNull(),
  ipAddress: text('ip_address'),
  userAgent: text('user_agent'),
  userId: text('user_id')
    .notNull()
    .references(() => users.id, { onDelete: 'cascade' }),
});

export const accounts = pgTable('accounts', {
  id: text('id').primaryKey(),
  accountId: text('account_id').notNull(),
  providerId: text('provider_id').notNull(),
  userId: text('user_id')
    .notNull()
    .references(() => users.id, { onDelete: 'cascade' }),
  accessToken: text('access_token'),
  refreshToken: text('refresh_token'),
  idToken: text('id_token'),
  accessTokenExpiresAt: timestamp('access_token_expires_at'),
  refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
  scope: text('scope'),
  password: text('password'),
  createdAt: timestamp('created_at').notNull(),
  updatedAt: timestamp('updated_at').notNull(),
});

export const verifications = pgTable('verifications', {
  id: text('id').primaryKey(),
  identifier: text('identifier').notNull(),
  value: text('value').notNull(),
  expiresAt: timestamp('expires_at').notNull(),
  createdAt: timestamp('created_at').$defaultFn(() => /* @__PURE__ */ new Date()),
  updatedAt: timestamp('updated_at').$defaultFn(() => /* @__PURE__ */ new Date()),
});

// Define a Video model
export const videos = pgTable('videos', {
  id: varchar('id').notNull().primaryKey(),
  title: varchar('title').notNull(),
  thumbnail: varchar('thumbnail').notNull(),
  vtt: varchar('vtt'),
  video: varchar('video').notNull(),
  link: varchar('link'),
  badge: varchar('badge'),
  difficulty: varchar('difficulty'),
  dialect: varchar('dialect'),
  dialectFlag: varchar('dialect_flag'),
  dialectIcon: text('dialect_icon'),
  duration: varchar('duration'),
  completedSections: integer('completed_sections').default(0),
  createdAt: timestamp('created_at', { mode: 'date', precision: 3 }).notNull().defaultNow(),
  updatedAt: timestamp('updated_at', { mode: 'date', precision: 3 })
    .notNull()
    .defaultNow()
    .$onUpdate(() => new Date()),
});

// Define a User-Video association model
export const userVideos = pgTable('user_videos', {
  id: varchar('id').notNull().primaryKey(),
  userId: varchar('user_id')
    .notNull()
    .references(() => users.id, { onDelete: 'cascade' }),
  videoId: varchar('video_id').notNull(),
  addedAt: timestamp('added_at', { mode: 'date', precision: 3 }).notNull().defaultNow(),
  lastWatched: timestamp('last_watched', { mode: 'date', precision: 3 }),
  completedSections: integer('completed_sections').default(0),
});



================================================
FILE: hooks/use-character-limit.js
================================================
"use client";;
import { useState } from "react";

export function useCharacterLimit({
  maxLength,
  initialValue = ""
}) {
  const [value, setValue] = useState(initialValue);
  const [characterCount, setCharacterCount] = useState(initialValue.length);

  const handleChange = (e) => {
    const newValue = e.target.value;
    if (newValue.length <= maxLength) {
      setValue(newValue);
      setCharacterCount(newValue.length);
    }
  };

  return {
    value,
    characterCount,
    handleChange,
    maxLength,
  };
}



================================================
FILE: hooks/use-image-upload.js
================================================
"use client";;
import { useCallback, useEffect, useRef, useState } from "react";

export function useImageUpload({
  onUpload
} = {}) {
  const previewRef = useRef(null);
  const fileInputRef = useRef(null);
  const [previewUrl, setPreviewUrl] = useState(null);
  const [fileName, setFileName] = useState(null);

  const handleThumbnailClick = useCallback(() => {
    fileInputRef.current?.click();
  }, []);

  const handleFileChange = useCallback((event) => {
    const file = event.target.files?.[0];
    if (file) {
      setFileName(file.name);
      const url = URL.createObjectURL(file);
      setPreviewUrl(url);
      previewRef.current = url;
      onUpload?.(url);
    }
  }, [onUpload]);

  const handleRemove = useCallback(() => {
    if (previewUrl) {
      URL.revokeObjectURL(previewUrl);
    }
    setPreviewUrl(null);
    setFileName(null);
    previewRef.current = null;
    if (fileInputRef.current) {
      fileInputRef.current.value = "";
    }
  }, [previewUrl]);

  useEffect(() => {
    return () => {
      if (previewRef.current) {
        URL.revokeObjectURL(previewRef.current);
      }
    };
  }, []);

  return {
    previewUrl,
    fileName,
    fileInputRef,
    handleThumbnailClick,
    handleFileChange,
    handleRemove,
  };
}



================================================
FILE: hooks/use-mobile.jsx
================================================
import * as React from 'react';

const MOBILE_BREAKPOINT = 768;

export function useIsMobile() {
  const [isMobile, setIsMobile] = React.useState(undefined);

  React.useEffect(() => {
    const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
    const onChange = () => {
      setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
    };
    mql.addEventListener('change', onChange);
    setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
    return () => mql.removeEventListener('change', onChange);
  }, []);

  return isMobile;
}



================================================
FILE: hooks/use-sidebar.jsx
================================================
'use client';

import * as React from 'react';

export function useSidebar() {
  const [open, setOpen] = React.useState(true);

  const onOpenChange = React.useCallback(value => {
    setOpen(value);

    // Set cookie to maintain state across page loads
    document.cookie = `sidebar_state=${value ? 'open' : 'closed'}; path=/; max-age=${60 * 60 * 24 * 7}`;
  }, []);

  // Toggle function for convenience
  const toggleSidebar = React.useCallback(() => {
    onOpenChange(!open);
  }, [open, onOpenChange]);

  // Read cookie on initial render
  React.useEffect(() => {
    const cookies = document.cookie.split(';');
    const sidebarCookie = cookies.find(cookie => cookie.trim().startsWith('sidebar_state='));
    if (sidebarCookie) {
      const value = sidebarCookie.split('=')[1].trim();
      setOpen(value === 'open');
    }
  }, []);

  return {
    open,
    onOpenChange,
    toggleSidebar,
    state: open ? 'expanded' : 'collapsed',
  };
}



================================================
FILE: hooks/use-toast.js
================================================
'use client';
// Inspired by react-hot-toast library
import * as React from 'react';

const TOAST_LIMIT = 1;
const TOAST_REMOVE_DELAY = 1000000;

const actionTypes = {
  ADD_TOAST: 'ADD_TOAST',
  UPDATE_TOAST: 'UPDATE_TOAST',
  DISMISS_TOAST: 'DISMISS_TOAST',
  REMOVE_TOAST: 'REMOVE_TOAST',
};

let count = 0;

function genId() {
  count = (count + 1) % Number.MAX_SAFE_INTEGER;
  return count.toString();
}

const toastTimeouts = new Map();

const addToRemoveQueue = toastId => {
  if (toastTimeouts.has(toastId)) {
    return;
  }

  const timeout = setTimeout(() => {
    toastTimeouts.delete(toastId);
    dispatch({
      type: 'REMOVE_TOAST',
      toastId: toastId,
    });
  }, TOAST_REMOVE_DELAY);

  toastTimeouts.set(toastId, timeout);
};

export const reducer = (state, action) => {
  switch (action.type) {
    case 'ADD_TOAST':
      return {
        ...state,
        toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
      };

    case 'UPDATE_TOAST':
      return {
        ...state,
        toasts: state.toasts.map(t => (t.id === action.toast.id ? { ...t, ...action.toast } : t)),
      };

    case 'DISMISS_TOAST': {
      const { toastId } = action;

      // ! Side effects ! - This could be extracted into a dismissToast() action,
      // but I'll keep it here for simplicity
      if (toastId) {
        addToRemoveQueue(toastId);
      } else {
        state.toasts.forEach(toast => {
          addToRemoveQueue(toast.id);
        });
      }

      return {
        ...state,
        toasts: state.toasts.map(t =>
          t.id === toastId || toastId === undefined
            ? {
                ...t,
                open: false,
              }
            : t,
        ),
      };
    }
    case 'REMOVE_TOAST':
      if (action.toastId === undefined) {
        return {
          ...state,
          toasts: [],
        };
      }
      return {
        ...state,
        toasts: state.toasts.filter(t => t.id !== action.toastId),
      };
  }
};

const listeners = [];

let memoryState = { toasts: [] };

function dispatch(action) {
  memoryState = reducer(memoryState, action);
  listeners.forEach(listener => {
    listener(memoryState);
  });
}

function toast({ ...props }) {
  const id = genId();

  const update = props =>
    dispatch({
      type: 'UPDATE_TOAST',
      toast: { ...props, id },
    });
  const dismiss = () => dispatch({ type: 'DISMISS_TOAST', toastId: id });

  dispatch({
    type: 'ADD_TOAST',
    toast: {
      ...props,
      id,
      open: true,
      onOpenChange: open => {
        if (!open) dismiss();
      },
    },
  });

  return {
    id: id,
    dismiss,
    update,
  };
}

function useToast() {
  const [state, setState] = React.useState(memoryState);

  React.useEffect(() => {
    listeners.push(setState);
    return () => {
      const index = listeners.indexOf(setState);
      if (index > -1) {
        listeners.splice(index, 1);
      }
    };
  }, [state]);

  return {
    ...state,
    toast,
    dismiss: toastId => dispatch({ type: 'DISMISS_TOAST', toastId }),
  };
}

export { useToast, toast };



================================================
FILE: hooks/use-user-videos.ts
================================================
'use client';

import useSWR from 'swr';
import { getUserVideos } from '@/lib/videos';
import { useMemo } from 'react';

async function fetchUserVideos() {
  try {
    return await getUserVideos();
  } catch (error) {
    console.error('Error fetching user videos:', error);
    return [];
  }
}

export function useUserVideos() {
  const { data, error, isLoading, mutate } = useSWR('user-videos', fetchUserVideos, {
    dedupingInterval: 5000,
    revalidateOnFocus: false,
    revalidateIfStale: true,
    revalidateOnReconnect: true,
  });

  const videos = useMemo(() => data || [], [data]);

  return {
    videos,
    error,
    isLoading,
    mutate,
  };
}



================================================
FILE: lib/auth-client.ts
================================================
import { createAuthClient } from 'better-auth/react';

export const authClient = createAuthClient();

export async function getUser() {
  const {
    data,
    error, // error object
  } = await authClient.getSession();

  return { user: data?.user, error };
}

// How to use as hook in client components:
// import { authClient } from "@/lib/auth-client"
// const {
//     data: session,
//     isPending, // loading state
//     error, // error object
//     refetch // refetch the session
// } = authClient.useSession()



================================================
FILE: lib/auth.ts
================================================
import { betterAuth } from 'better-auth';
import { nextCookies } from 'better-auth/next-js';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { db } from '@/db/schema';
import * as schema from '@/db/schema';

// How to use in server actions and server components:
// import { auth } from "@/lib/auth"
// import { headers } from "next/headers"

// const session = await auth.api.getSession({
//     headers: await headers()
// })
// if (!session) {
//     // handle not being authenticated, e.g. by returning placholder jsx
//     // or by redirecting to /sign-in
// }

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: 'pg',
    usePlural: true,
    schema,
  }),
  emailAndPassword: {
    enabled: true,
    sendResetPassword: async ({ user, url, token }, request) => {
      // TODO: hook up nice react email template
      // await sendEmail({
      //   to: user.email,
      //   subject: 'Reset your password',
      //   text: `Click the link to reset your password: ${url}`,
      // });
    },
    requireEmailVerification: false, // TODO: enable
  },
  emailVerification: {
    sendVerificationEmail: async ({ user, url, token }, request) => {
      // TODO: hook up nice react email template
      // await sendEmail({
      //     to: user.email,
      //     subject: 'Verify your email address',
      //     text: `Click the link to verify your email: ${url}`
      // })
    },
    sendOnSignUp: false, // TODO: enable
    autoSignInAfterVerification: true,
  },
  socialProviders: {
    google: {
      prompt: 'select_account',
      clientId: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
    },
    microsoft: {
      prompt: 'select_account',
      clientId: process.env.MICROSOFT_CLIENT_ID as string,
      clientSecret: process.env.MICROSOFT_CLIENT_SECRET as string,
      tenantId: process.env.MICROSOFT_TENANT_ID as string,
    },
  },
  plugins: [nextCookies()], // nextCookies must be last
  user: {
    additionalFields: {
      streak: {
        type: 'number',
        required: false,
        defaultValue: 0,
        input: false, // don't allow user to set
      },
      stripeId: {
        type: 'string',
        required: false,
        input: false, // don't allow user to set
      },
      metadata: {
        type: 'string',
        required: false,
        input: false, // don't allow user to set
      },
      onboardingCompleted: {
        type: 'boolean',
        required: false,
        defaultValue: false,
        input: false, // don't allow user to set
      },
    },
  },
});



================================================
FILE: lib/styles.js
================================================
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs) {
  return twMerge(clsx(inputs));
}



================================================
FILE: lib/use-character-limit.tsx
================================================
'use client';

import { ChangeEvent, useState } from 'react';

type UseCharacterLimitProps = {
  maxLength: number;
  initialValue?: string;
};

export function useCharacterLimit({ maxLength, initialValue = '' }: UseCharacterLimitProps) {
  const [value, setValue] = useState(initialValue);
  const [characterCount, setCharacterCount] = useState(initialValue.length);

  const handleChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
    const newValue = e.target.value;
    if (newValue.length <= maxLength) {
      setValue(newValue);
      setCharacterCount(newValue.length);
    }
  };

  return {
    value,
    characterCount,
    handleChange,
    maxLength,
  };
}



================================================
FILE: lib/videos.ts
================================================
'use server';

import { auth } from '@/lib/auth';
import { headers } from 'next/headers';
import { db, userVideos, videos } from '@/db/schema';
import { eq, and } from 'drizzle-orm';

// authenticated server actions for managing videos
export const resetUserVideos = async () => {
  'use server';
  const session = await auth.api.getSession({
    headers: await headers(),
  });

  if (!session) {
    throw new Error('Not authenticated');
  }

  console.log('Resetting video history for user:', session.user.id);

  // Delete all user-video associations for this user
  await db.delete(userVideos).where(eq(userVideos.userId, session.user.id));

  console.log('User video history reset successfully');
};

const jumanjiVideo = {
  id: 'Y82ck2bct8sbG',
  title: 'Jumanji: The Next Level from Sony Pictures Entertainment',
  thumbnail: '/images/thumbnails/jumanji-next-level-full-res.jpg',
  vtt: '/videos/jumanji-next-level.vtt',
  video: 'https://www.youtube.com/watch?v=pJ4c-4V9D_g',
  link: 'rBxcF-r9Ibs',
  badge: 'Medium',
  difficulty: 'Medium',
  dialect: 'US Midlands',
  dialectFlag: '🇺🇸',
  dialectIcon:
    '<svg     xmlns="http://www.w3.org/2000/svg"     width="15"     height="15"     fill="none"     viewBox="0 0 15 15"   >     <path       fill="#FFEDD5"       stroke="#9A3413"       d="M13.66 7.08A6.58 6.58 0 1 1 7.08.5c3.852 0 6.58 2.935 6.58 6.58Z"     ></path>     <path       fill="#9A3413"       d="M4.87 10v-.716L7.085 6.99q.354-.373.585-.655.232-.285.348-.54t.115-.543a1 1 0 0 0-.153-.563 1 1 0 0 0-.42-.367 1.3 1.3 0 0 0-.597-.131q-.352 0-.613.143a1 1 0 0 0-.403.406q-.14.263-.14.614h-.944q0-.597.275-1.045.276-.447.755-.694.479-.249 1.09-.249.616 0 1.086.246.473.243.738.665.266.418.266.946 0 .364-.138.713-.135.348-.47.776-.335.426-.933 1.033l-1.3 1.361v.048h2.946V10z"     ></path>   </svg>',
  duration: '9:35',
  completedSections: 0,
};

// TODO: when is this ever used??
export const seedVideos = async () => {
  'use server';
  const session = await auth.api.getSession({
    headers: await headers(),
  });

  if (!session) {
    throw new Error('Not authenticated');
  }

  // Insert Jumanji video if it doesn't already exist
  const existing = await db.select().from(videos).where(eq(videos.id, jumanjiVideo.id)).limit(1);
  if (existing.length === 0) {
    await db.insert(videos).values(jumanjiVideo);
  }
};

export const associateUserVideo = async (videoId: string) => {
  'use server';
  const session = await auth.api.getSession({
    headers: await headers(),
  });

  if (!session) {
    throw new Error('Not authenticated');
  }

  // If video doesn't exist in database, create a placeholder
  const videoExists = await db.select().from(videos).where(eq(videos.id, videoId)).limit(1);
  if (videoExists.length === 0) {
    console.log('Video not found in database, creating placeholder for:', videoId);
    await db.insert(videos).values(jumanjiVideo);
    console.log('Placeholder video created successfully');
  }

  // Check if association already exists
  const existing = await db
    .select()
    .from(userVideos)
    .where(and(eq(userVideos.userId, session.user.id), eq(userVideos.videoId, videoId)))
    .limit(1);

  console.log('Checking if user already has this video:', existing.length > 0);

  if (existing.length > 0) {
    // Update last watched timestamp
    console.log('Updating existing user-video association');
    await db
      .update(userVideos)
      .set({ lastWatched: new Date() })
      .where(and(eq(userVideos.userId, session.user.id), eq(userVideos.videoId, videoId)));
  } else {
    // Create new association
    console.log(
      'Creating new user-video association for user:',
      session.user.id,
      'video:',
      videoId,
    );
    const id = `${session.user.id}_${videoId}_${Date.now()}`;
    await db.insert(userVideos).values({
      id,
      userId: session.user.id,
      videoId,
      addedAt: new Date(),
      lastWatched: new Date(),
      completedSections: 0, // Initialize with 0 completed sections
    });
    console.log('User-video association created with ID:', id);
  }
};

export const getUserVideos = async () => {
  'use server';
  const session = await auth.api.getSession({
    headers: await headers(),
  });

  if (!session) {
    throw new Error('Not authenticated');
  }

  console.log('Fetching videos for user:', session.user.id);

  // First check if we have any user-video associations
  const userVideoAssociations = await db
    .select()
    .from(userVideos)
    .where(eq(userVideos.userId, session.user.id));

  console.log('Found user-video associations:', userVideoAssociations.length);

  if (userVideoAssociations.length === 0) {
    throw new Error('No videos associated with this user');
  }

  // Get user's videos with video details
  const userVideoList = await db
    .select({
      id: videos.id,
      title: videos.title,
      thumbnail: videos.thumbnail,
      vtt: videos.vtt,
      video: videos.video,
      link: videos.link,
      badge: videos.badge,
      difficulty: videos.difficulty,
      dialect: videos.dialect,
      dialectFlag: videos.dialectFlag,
      dialectIcon: videos.dialectIcon,
      duration: videos.duration,
      completedSections: userVideos.completedSections,
      addedAt: userVideos.addedAt,
      lastWatched: userVideos.lastWatched,
    })
    .from(userVideos)
    .innerJoin(videos, eq(userVideos.videoId, videos.id))
    .where(eq(userVideos.userId, session.user.id));

  console.log('Returning user videos:', userVideoList.length);
  return userVideoList;
};



================================================
FILE: lib/hooks/use-scroll.js
================================================
'use client';

import { useEffect, useState } from 'react';

export function useScroll(threshold = 50) {
  const [scrolled, setScrolled] = useState(false);

  useEffect(() => {
    const handleScroll = () => {
      const scrollPosition = window.scrollY;
      setScrolled(scrollPosition > threshold);
    };

    // Set initial state
    handleScroll();

    // Add scroll listener
    window.addEventListener('scroll', handleScroll, { passive: true });

    // Cleanup
    return () => window.removeEventListener('scroll', handleScroll);
  }, [threshold]);

  return scrolled;
}




================================================
FILE: migrations/0000_married_dark_beast.sql
================================================
CREATE TABLE IF NOT EXISTS "users" (
	"id" varchar PRIMARY KEY NOT NULL,
	"name" varchar NOT NULL,
	"email" varchar NOT NULL,
	"stripe_id" varchar
);



================================================
FILE: migrations/0001_zippy_snowbird.sql
================================================
ALTER TABLE "users" ADD COLUMN "streak" integer DEFAULT 0 NOT NULL;--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "created_at" timestamp (3) DEFAULT now() NOT NULL;--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "updated_at" timestamp (3) DEFAULT now() NOT NULL;


================================================
FILE: migrations/0002_orange_klaw.sql
================================================
CREATE TABLE IF NOT EXISTS "user_videos" (
	"id" varchar PRIMARY KEY NOT NULL,
	"user_id" varchar NOT NULL,
	"video_id" varchar NOT NULL,
	"added_at" timestamp (3) DEFAULT now() NOT NULL,
	"last_watched" timestamp (3),
	"completed_sections" integer DEFAULT 0
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "videos" (
	"id" varchar PRIMARY KEY NOT NULL,
	"title" varchar NOT NULL,
	"thumbnail" varchar NOT NULL,
	"vtt" varchar,
	"video" varchar NOT NULL,
	"link" varchar,
	"badge" varchar,
	"difficulty" varchar,
	"dialect" varchar,
	"dialect_flag" varchar,
	"dialect_icon" text,
	"duration" varchar,
	"completed_sections" integer DEFAULT 0,
	"created_at" timestamp (3) DEFAULT now() NOT NULL,
	"updated_at" timestamp (3) DEFAULT now() NOT NULL
);



================================================
FILE: migrations/0003_bouncy_betty_brant.sql
================================================
CREATE TABLE IF NOT EXISTS "user_section_progress" (
	"id" varchar PRIMARY KEY NOT NULL,
	"user_id" varchar NOT NULL,
	"video_id" varchar NOT NULL,
	"section_id" varchar NOT NULL,
	"score" real,
	"transcription" text,
	"feedback" json,
	"top3_feedback" json,
	"word_scores" json,
	"side_by_side_feedback" json,
	"completed_at" timestamp (3),
	"created_at" timestamp (3) DEFAULT now() NOT NULL,
	"updated_at" timestamp (3) DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "video_sections" (
	"id" varchar PRIMARY KEY NOT NULL,
	"video_id" varchar NOT NULL,
	"start" real NOT NULL,
	"end" real NOT NULL,
	"thumbnail" varchar,
	"target" text,
	"target_by_word" json,
	"order" integer NOT NULL,
	"created_at" timestamp (3) DEFAULT now() NOT NULL,
	"updated_at" timestamp (3) DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "videos" ADD COLUMN "captions" varchar;--> statement-breakpoint
ALTER TABLE "videos" ADD COLUMN "description" text;--> statement-breakpoint
ALTER TABLE "videos" ADD COLUMN "external_link" varchar;--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "user_section_progress" ADD CONSTRAINT "user_section_progress_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "user_section_progress" ADD CONSTRAINT "user_section_progress_video_id_videos_id_fk" FOREIGN KEY ("video_id") REFERENCES "public"."videos"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "user_section_progress" ADD CONSTRAINT "user_section_progress_section_id_video_sections_id_fk" FOREIGN KEY ("section_id") REFERENCES "public"."video_sections"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
 ALTER TABLE "video_sections" ADD CONSTRAINT "video_sections_video_id_videos_id_fk" FOREIGN KEY ("video_id") REFERENCES "public"."videos"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
 WHEN duplicate_object THEN null;
END $$;



================================================
FILE: migrations/0004_late_patriot.sql
================================================
CREATE TABLE "accounts" (
	"id" text PRIMARY KEY NOT NULL,
	"account_id" text NOT NULL,
	"provider_id" text NOT NULL,
	"user_id" text NOT NULL,
	"access_token" text,
	"refresh_token" text,
	"id_token" text,
	"access_token_expires_at" timestamp,
	"refresh_token_expires_at" timestamp,
	"scope" text,
	"password" text,
	"created_at" timestamp NOT NULL,
	"updated_at" timestamp NOT NULL
);
--> statement-breakpoint
CREATE TABLE "sessions" (
	"id" text PRIMARY KEY NOT NULL,
	"expires_at" timestamp NOT NULL,
	"token" text NOT NULL,
	"created_at" timestamp NOT NULL,
	"updated_at" timestamp NOT NULL,
	"ip_address" text,
	"user_agent" text,
	"user_id" text NOT NULL,
	CONSTRAINT "sessions_token_unique" UNIQUE("token")
);
--> statement-breakpoint
CREATE TABLE "verifications" (
	"id" text PRIMARY KEY NOT NULL,
	"identifier" text NOT NULL,
	"value" text NOT NULL,
	"expires_at" timestamp NOT NULL,
	"created_at" timestamp,
	"updated_at" timestamp
);
--> statement-breakpoint
ALTER TABLE "user_section_progress" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint
ALTER TABLE "video_sections" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint
DROP TABLE "user_section_progress" CASCADE;--> statement-breakpoint
DROP TABLE "video_sections" CASCADE;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "id" SET DATA TYPE text;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "name" SET DATA TYPE text;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "email" SET DATA TYPE text;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "created_at" SET DATA TYPE timestamp;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "created_at" DROP DEFAULT;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "updated_at" SET DATA TYPE timestamp;--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "updated_at" DROP DEFAULT;--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "email_verified" boolean DEFAULT false NOT NULL;--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "image" text;--> statement-breakpoint
ALTER TABLE "accounts" ADD CONSTRAINT "accounts_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "user_videos" ADD CONSTRAINT "user_videos_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "videos" DROP COLUMN "captions";--> statement-breakpoint
ALTER TABLE "videos" DROP COLUMN "description";--> statement-breakpoint
ALTER TABLE "videos" DROP COLUMN "external_link";--> statement-breakpoint
ALTER TABLE "users" ADD CONSTRAINT "users_email_unique" UNIQUE("email");


================================================
FILE: migrations/0005_sticky_phil_sheldon.sql
================================================
ALTER TABLE "users" ADD COLUMN "metadata" json;--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "onboarding_completed" boolean DEFAULT false;


================================================
FILE: migrations/meta/0000_snapshot.json
================================================
{
  "id": "e709378c-220b-4fbe-a5d4-9fd838d0840b",
  "prevId": "00000000-0000-0000-0000-000000000000",
  "version": "7",
  "dialect": "postgresql",
  "tables": {
    "public.users": {
      "name": "users",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "name": {
          "name": "name",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "email": {
          "name": "email",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "stripe_id": {
          "name": "stripe_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {}
    }
  },
  "enums": {},
  "schemas": {},
  "sequences": {},
  "_meta": {
    "columns": {},
    "schemas": {},
    "tables": {}
  }
}



================================================
FILE: migrations/meta/0001_snapshot.json
================================================
{
  "id": "ea981418-b0c7-40b4-ad88-4be6ea95338c",
  "prevId": "e709378c-220b-4fbe-a5d4-9fd838d0840b",
  "version": "7",
  "dialect": "postgresql",
  "tables": {
    "public.users": {
      "name": "users",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "name": {
          "name": "name",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "email": {
          "name": "email",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "streak": {
          "name": "streak",
          "type": "integer",
          "primaryKey": false,
          "notNull": true,
          "default": 0
        },
        "stripe_id": {
          "name": "stripe_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {}
    }
  },
  "enums": {},
  "schemas": {},
  "sequences": {},
  "_meta": {
    "columns": {},
    "schemas": {},
    "tables": {}
  }
}


================================================
FILE: migrations/meta/0002_snapshot.json
================================================
{
  "id": "f2c4faac-a1f8-4847-bab2-2c90a0a1ee8b",
  "prevId": "ea981418-b0c7-40b4-ad88-4be6ea95338c",
  "version": "7",
  "dialect": "postgresql",
  "tables": {
    "public.user_videos": {
      "name": "user_videos",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "user_id": {
          "name": "user_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "video_id": {
          "name": "video_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "added_at": {
          "name": "added_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "last_watched": {
          "name": "last_watched",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": false
        },
        "completed_sections": {
          "name": "completed_sections",
          "type": "integer",
          "primaryKey": false,
          "notNull": false,
          "default": 0
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {}
    },
    "public.users": {
      "name": "users",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "name": {
          "name": "name",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "email": {
          "name": "email",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "streak": {
          "name": "streak",
          "type": "integer",
          "primaryKey": false,
          "notNull": true,
          "default": 0
        },
        "stripe_id": {
          "name": "stripe_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {}
    },
    "public.videos": {
      "name": "videos",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "title": {
          "name": "title",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "thumbnail": {
          "name": "thumbnail",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "vtt": {
          "name": "vtt",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "video": {
          "name": "video",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "link": {
          "name": "link",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "badge": {
          "name": "badge",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "difficulty": {
          "name": "difficulty",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect": {
          "name": "dialect",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect_flag": {
          "name": "dialect_flag",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect_icon": {
          "name": "dialect_icon",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "duration": {
          "name": "duration",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "completed_sections": {
          "name": "completed_sections",
          "type": "integer",
          "primaryKey": false,
          "notNull": false,
          "default": 0
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {}
    }
  },
  "enums": {},
  "schemas": {},
  "sequences": {},
  "_meta": {
    "columns": {},
    "schemas": {},
    "tables": {}
  }
}


================================================
FILE: migrations/meta/0003_snapshot.json
================================================
{
  "id": "604ce754-9667-4b3e-90cc-03a5389f20e4",
  "prevId": "f2c4faac-a1f8-4847-bab2-2c90a0a1ee8b",
  "version": "7",
  "dialect": "postgresql",
  "tables": {
    "public.user_section_progress": {
      "name": "user_section_progress",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "user_id": {
          "name": "user_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "video_id": {
          "name": "video_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "section_id": {
          "name": "section_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "score": {
          "name": "score",
          "type": "real",
          "primaryKey": false,
          "notNull": false
        },
        "transcription": {
          "name": "transcription",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "feedback": {
          "name": "feedback",
          "type": "json",
          "primaryKey": false,
          "notNull": false
        },
        "top3_feedback": {
          "name": "top3_feedback",
          "type": "json",
          "primaryKey": false,
          "notNull": false
        },
        "word_scores": {
          "name": "word_scores",
          "type": "json",
          "primaryKey": false,
          "notNull": false
        },
        "side_by_side_feedback": {
          "name": "side_by_side_feedback",
          "type": "json",
          "primaryKey": false,
          "notNull": false
        },
        "completed_at": {
          "name": "completed_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": false
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        }
      },
      "indexes": {},
      "foreignKeys": {
        "user_section_progress_user_id_users_id_fk": {
          "name": "user_section_progress_user_id_users_id_fk",
          "tableFrom": "user_section_progress",
          "tableTo": "users",
          "columnsFrom": [
            "user_id"
          ],
          "columnsTo": [
            "id"
          ],
          "onDelete": "no action",
          "onUpdate": "no action"
        },
        "user_section_progress_video_id_videos_id_fk": {
          "name": "user_section_progress_video_id_videos_id_fk",
          "tableFrom": "user_section_progress",
          "tableTo": "videos",
          "columnsFrom": [
            "video_id"
          ],
          "columnsTo": [
            "id"
          ],
          "onDelete": "no action",
          "onUpdate": "no action"
        },
        "user_section_progress_section_id_video_sections_id_fk": {
          "name": "user_section_progress_section_id_video_sections_id_fk",
          "tableFrom": "user_section_progress",
          "tableTo": "video_sections",
          "columnsFrom": [
            "section_id"
          ],
          "columnsTo": [
            "id"
          ],
          "onDelete": "no action",
          "onUpdate": "no action"
        }
      },
      "compositePrimaryKeys": {},
      "uniqueConstraints": {}
    },
    "public.user_videos": {
      "name": "user_videos",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "user_id": {
          "name": "user_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "video_id": {
          "name": "video_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "added_at": {
          "name": "added_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "last_watched": {
          "name": "last_watched",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": false
        },
        "completed_sections": {
          "name": "completed_sections",
          "type": "integer",
          "primaryKey": false,
          "notNull": false,
          "default": 0
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {}
    },
    "public.users": {
      "name": "users",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "name": {
          "name": "name",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "email": {
          "name": "email",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "streak": {
          "name": "streak",
          "type": "integer",
          "primaryKey": false,
          "notNull": true,
          "default": 0
        },
        "stripe_id": {
          "name": "stripe_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {}
    },
    "public.video_sections": {
      "name": "video_sections",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "video_id": {
          "name": "video_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "start": {
          "name": "start",
          "type": "real",
          "primaryKey": false,
          "notNull": true
        },
        "end": {
          "name": "end",
          "type": "real",
          "primaryKey": false,
          "notNull": true
        },
        "thumbnail": {
          "name": "thumbnail",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "target": {
          "name": "target",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "target_by_word": {
          "name": "target_by_word",
          "type": "json",
          "primaryKey": false,
          "notNull": false
        },
        "order": {
          "name": "order",
          "type": "integer",
          "primaryKey": false,
          "notNull": true
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        }
      },
      "indexes": {},
      "foreignKeys": {
        "video_sections_video_id_videos_id_fk": {
          "name": "video_sections_video_id_videos_id_fk",
          "tableFrom": "video_sections",
          "tableTo": "videos",
          "columnsFrom": [
            "video_id"
          ],
          "columnsTo": [
            "id"
          ],
          "onDelete": "no action",
          "onUpdate": "no action"
        }
      },
      "compositePrimaryKeys": {},
      "uniqueConstraints": {}
    },
    "public.videos": {
      "name": "videos",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "title": {
          "name": "title",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "thumbnail": {
          "name": "thumbnail",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "vtt": {
          "name": "vtt",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "captions": {
          "name": "captions",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "video": {
          "name": "video",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "link": {
          "name": "link",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "badge": {
          "name": "badge",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "difficulty": {
          "name": "difficulty",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect": {
          "name": "dialect",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect_flag": {
          "name": "dialect_flag",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect_icon": {
          "name": "dialect_icon",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "duration": {
          "name": "duration",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "description": {
          "name": "description",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "external_link": {
          "name": "external_link",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "completed_sections": {
          "name": "completed_sections",
          "type": "integer",
          "primaryKey": false,
          "notNull": false,
          "default": 0
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {}
    }
  },
  "enums": {},
  "schemas": {},
  "sequences": {},
  "_meta": {
    "columns": {},
    "schemas": {},
    "tables": {}
  }
}


================================================
FILE: migrations/meta/0004_snapshot.json
================================================
{
  "id": "58d46986-7b24-4ba7-aa27-a6b141021e85",
  "prevId": "604ce754-9667-4b3e-90cc-03a5389f20e4",
  "version": "7",
  "dialect": "postgresql",
  "tables": {
    "public.accounts": {
      "name": "accounts",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "text",
          "primaryKey": true,
          "notNull": true
        },
        "account_id": {
          "name": "account_id",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "provider_id": {
          "name": "provider_id",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "user_id": {
          "name": "user_id",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "access_token": {
          "name": "access_token",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "refresh_token": {
          "name": "refresh_token",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "id_token": {
          "name": "id_token",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "access_token_expires_at": {
          "name": "access_token_expires_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": false
        },
        "refresh_token_expires_at": {
          "name": "refresh_token_expires_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": false
        },
        "scope": {
          "name": "scope",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "password": {
          "name": "password",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        }
      },
      "indexes": {},
      "foreignKeys": {
        "accounts_user_id_users_id_fk": {
          "name": "accounts_user_id_users_id_fk",
          "tableFrom": "accounts",
          "tableTo": "users",
          "columnsFrom": [
            "user_id"
          ],
          "columnsTo": [
            "id"
          ],
          "onDelete": "cascade",
          "onUpdate": "no action"
        }
      },
      "compositePrimaryKeys": {},
      "uniqueConstraints": {},
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    },
    "public.sessions": {
      "name": "sessions",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "text",
          "primaryKey": true,
          "notNull": true
        },
        "expires_at": {
          "name": "expires_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "token": {
          "name": "token",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "ip_address": {
          "name": "ip_address",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "user_agent": {
          "name": "user_agent",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "user_id": {
          "name": "user_id",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        }
      },
      "indexes": {},
      "foreignKeys": {
        "sessions_user_id_users_id_fk": {
          "name": "sessions_user_id_users_id_fk",
          "tableFrom": "sessions",
          "tableTo": "users",
          "columnsFrom": [
            "user_id"
          ],
          "columnsTo": [
            "id"
          ],
          "onDelete": "cascade",
          "onUpdate": "no action"
        }
      },
      "compositePrimaryKeys": {},
      "uniqueConstraints": {
        "sessions_token_unique": {
          "name": "sessions_token_unique",
          "nullsNotDistinct": false,
          "columns": [
            "token"
          ]
        }
      },
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    },
    "public.user_videos": {
      "name": "user_videos",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "user_id": {
          "name": "user_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "video_id": {
          "name": "video_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "added_at": {
          "name": "added_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "last_watched": {
          "name": "last_watched",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": false
        },
        "completed_sections": {
          "name": "completed_sections",
          "type": "integer",
          "primaryKey": false,
          "notNull": false,
          "default": 0
        }
      },
      "indexes": {},
      "foreignKeys": {
        "user_videos_user_id_users_id_fk": {
          "name": "user_videos_user_id_users_id_fk",
          "tableFrom": "user_videos",
          "tableTo": "users",
          "columnsFrom": [
            "user_id"
          ],
          "columnsTo": [
            "id"
          ],
          "onDelete": "cascade",
          "onUpdate": "no action"
        }
      },
      "compositePrimaryKeys": {},
      "uniqueConstraints": {},
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    },
    "public.users": {
      "name": "users",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "text",
          "primaryKey": true,
          "notNull": true
        },
        "name": {
          "name": "name",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "email": {
          "name": "email",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "email_verified": {
          "name": "email_verified",
          "type": "boolean",
          "primaryKey": false,
          "notNull": true,
          "default": false
        },
        "image": {
          "name": "image",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "streak": {
          "name": "streak",
          "type": "integer",
          "primaryKey": false,
          "notNull": true,
          "default": 0
        },
        "stripe_id": {
          "name": "stripe_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {
        "users_email_unique": {
          "name": "users_email_unique",
          "nullsNotDistinct": false,
          "columns": [
            "email"
          ]
        }
      },
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    },
    "public.verifications": {
      "name": "verifications",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "text",
          "primaryKey": true,
          "notNull": true
        },
        "identifier": {
          "name": "identifier",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "value": {
          "name": "value",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "expires_at": {
          "name": "expires_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": false
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": false
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {},
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    },
    "public.videos": {
      "name": "videos",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "title": {
          "name": "title",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "thumbnail": {
          "name": "thumbnail",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "vtt": {
          "name": "vtt",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "video": {
          "name": "video",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "link": {
          "name": "link",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "badge": {
          "name": "badge",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "difficulty": {
          "name": "difficulty",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect": {
          "name": "dialect",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect_flag": {
          "name": "dialect_flag",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect_icon": {
          "name": "dialect_icon",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "duration": {
          "name": "duration",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "completed_sections": {
          "name": "completed_sections",
          "type": "integer",
          "primaryKey": false,
          "notNull": false,
          "default": 0
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {},
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    }
  },
  "enums": {},
  "schemas": {},
  "sequences": {},
  "roles": {},
  "policies": {},
  "views": {},
  "_meta": {
    "columns": {},
    "schemas": {},
    "tables": {}
  }
}


================================================
FILE: migrations/meta/0005_snapshot.json
================================================
{
  "id": "4a66e9a9-db64-45c8-b4db-aec9c7efba2e",
  "prevId": "58d46986-7b24-4ba7-aa27-a6b141021e85",
  "version": "7",
  "dialect": "postgresql",
  "tables": {
    "public.accounts": {
      "name": "accounts",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "text",
          "primaryKey": true,
          "notNull": true
        },
        "account_id": {
          "name": "account_id",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "provider_id": {
          "name": "provider_id",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "user_id": {
          "name": "user_id",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "access_token": {
          "name": "access_token",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "refresh_token": {
          "name": "refresh_token",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "id_token": {
          "name": "id_token",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "access_token_expires_at": {
          "name": "access_token_expires_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": false
        },
        "refresh_token_expires_at": {
          "name": "refresh_token_expires_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": false
        },
        "scope": {
          "name": "scope",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "password": {
          "name": "password",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        }
      },
      "indexes": {},
      "foreignKeys": {
        "accounts_user_id_users_id_fk": {
          "name": "accounts_user_id_users_id_fk",
          "tableFrom": "accounts",
          "tableTo": "users",
          "columnsFrom": [
            "user_id"
          ],
          "columnsTo": [
            "id"
          ],
          "onDelete": "cascade",
          "onUpdate": "no action"
        }
      },
      "compositePrimaryKeys": {},
      "uniqueConstraints": {},
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    },
    "public.sessions": {
      "name": "sessions",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "text",
          "primaryKey": true,
          "notNull": true
        },
        "expires_at": {
          "name": "expires_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "token": {
          "name": "token",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "ip_address": {
          "name": "ip_address",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "user_agent": {
          "name": "user_agent",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "user_id": {
          "name": "user_id",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        }
      },
      "indexes": {},
      "foreignKeys": {
        "sessions_user_id_users_id_fk": {
          "name": "sessions_user_id_users_id_fk",
          "tableFrom": "sessions",
          "tableTo": "users",
          "columnsFrom": [
            "user_id"
          ],
          "columnsTo": [
            "id"
          ],
          "onDelete": "cascade",
          "onUpdate": "no action"
        }
      },
      "compositePrimaryKeys": {},
      "uniqueConstraints": {
        "sessions_token_unique": {
          "name": "sessions_token_unique",
          "nullsNotDistinct": false,
          "columns": [
            "token"
          ]
        }
      },
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    },
    "public.user_videos": {
      "name": "user_videos",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "user_id": {
          "name": "user_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "video_id": {
          "name": "video_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "added_at": {
          "name": "added_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "last_watched": {
          "name": "last_watched",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": false
        },
        "completed_sections": {
          "name": "completed_sections",
          "type": "integer",
          "primaryKey": false,
          "notNull": false,
          "default": 0
        }
      },
      "indexes": {},
      "foreignKeys": {
        "user_videos_user_id_users_id_fk": {
          "name": "user_videos_user_id_users_id_fk",
          "tableFrom": "user_videos",
          "tableTo": "users",
          "columnsFrom": [
            "user_id"
          ],
          "columnsTo": [
            "id"
          ],
          "onDelete": "cascade",
          "onUpdate": "no action"
        }
      },
      "compositePrimaryKeys": {},
      "uniqueConstraints": {},
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    },
    "public.users": {
      "name": "users",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "text",
          "primaryKey": true,
          "notNull": true
        },
        "name": {
          "name": "name",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "email": {
          "name": "email",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "email_verified": {
          "name": "email_verified",
          "type": "boolean",
          "primaryKey": false,
          "notNull": true,
          "default": false
        },
        "image": {
          "name": "image",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "streak": {
          "name": "streak",
          "type": "integer",
          "primaryKey": false,
          "notNull": true,
          "default": 0
        },
        "stripe_id": {
          "name": "stripe_id",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "metadata": {
          "name": "metadata",
          "type": "json",
          "primaryKey": false,
          "notNull": false
        },
        "onboarding_completed": {
          "name": "onboarding_completed",
          "type": "boolean",
          "primaryKey": false,
          "notNull": false,
          "default": false
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {
        "users_email_unique": {
          "name": "users_email_unique",
          "nullsNotDistinct": false,
          "columns": [
            "email"
          ]
        }
      },
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    },
    "public.verifications": {
      "name": "verifications",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "text",
          "primaryKey": true,
          "notNull": true
        },
        "identifier": {
          "name": "identifier",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "value": {
          "name": "value",
          "type": "text",
          "primaryKey": false,
          "notNull": true
        },
        "expires_at": {
          "name": "expires_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": true
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": false
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp",
          "primaryKey": false,
          "notNull": false
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {},
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    },
    "public.videos": {
      "name": "videos",
      "schema": "",
      "columns": {
        "id": {
          "name": "id",
          "type": "varchar",
          "primaryKey": true,
          "notNull": true
        },
        "title": {
          "name": "title",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "thumbnail": {
          "name": "thumbnail",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "vtt": {
          "name": "vtt",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "video": {
          "name": "video",
          "type": "varchar",
          "primaryKey": false,
          "notNull": true
        },
        "link": {
          "name": "link",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "badge": {
          "name": "badge",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "difficulty": {
          "name": "difficulty",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect": {
          "name": "dialect",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect_flag": {
          "name": "dialect_flag",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "dialect_icon": {
          "name": "dialect_icon",
          "type": "text",
          "primaryKey": false,
          "notNull": false
        },
        "duration": {
          "name": "duration",
          "type": "varchar",
          "primaryKey": false,
          "notNull": false
        },
        "completed_sections": {
          "name": "completed_sections",
          "type": "integer",
          "primaryKey": false,
          "notNull": false,
          "default": 0
        },
        "created_at": {
          "name": "created_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        },
        "updated_at": {
          "name": "updated_at",
          "type": "timestamp (3)",
          "primaryKey": false,
          "notNull": true,
          "default": "now()"
        }
      },
      "indexes": {},
      "foreignKeys": {},
      "compositePrimaryKeys": {},
      "uniqueConstraints": {},
      "policies": {},
      "checkConstraints": {},
      "isRLSEnabled": false
    }
  },
  "enums": {},
  "schemas": {},
  "sequences": {},
  "roles": {},
  "policies": {},
  "views": {},
  "_meta": {
    "columns": {},
    "schemas": {},
    "tables": {}
  }
}


================================================
FILE: migrations/meta/_journal.json
================================================
{
  "version": "7",
  "dialect": "postgresql",
  "entries": [
    {
      "idx": 0,
      "version": "7",
      "when": 1725242612674,
      "tag": "0000_married_dark_beast",
      "breakpoints": true
    },
    {
      "idx": 1,
      "version": "7",
      "when": 1728112130005,
      "tag": "0001_zippy_snowbird",
      "breakpoints": true
    },
    {
      "idx": 2,
      "version": "7",
      "when": 1751141780646,
      "tag": "0002_orange_klaw",
      "breakpoints": true
    },
    {
      "idx": 3,
      "version": "7",
      "when": 1751150273940,
      "tag": "0003_bouncy_betty_brant",
      "breakpoints": true
    },
    {
      "idx": 4,
      "version": "7",
      "when": 1751273356752,
      "tag": "0004_late_patriot",
      "breakpoints": true
    },
    {
      "idx": 5,
      "version": "7",
      "when": 1751420122202,
      "tag": "0005_sticky_phil_sheldon",
      "breakpoints": true
    }
  ]
}


================================================
FILE: pages/api/submitGoogleFormWithReCaptcha.ts
================================================
// this endpoint submits one of the selected google forms with reCaptcha verification
// we explicitly define the form URLs here to not let the client pass any URL and to
// keep the underlying form URLs hidden (otherwise a bad actor could spam the form directly thus bypassing reCaptcha)

import { NextApiRequest, NextApiResponse } from 'next';
import * as formidable from 'formidable';

export const config = {
  api: {
    bodyParser: false,
  },
};

const FORMS = {
  contact: process.env.CONTACT_FORM_URL!,
};

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== 'POST') {
    // return new Response(JSON.stringify({ message: 'Only POST requests allowed' }), { status: 405 });
    res.status(405).json({ message: 'Only POST requests allowed' });
    return;
  }

  // verify the request parameters
  const form = new formidable.IncomingForm();
  const ip = req.headers['x-forwarded-for'];
  const formName = req.query.formName as string;
  const token = req.query.token as string;
  if (!formName || !FORMS[formName]) {
    res.status(400).json({ message: 'FormName not found' });
    return;
  }
  if (!token) {
    res.status(400).json({ message: 'Token not found' });
    return;
  }
  const formURL = FORMS[formName];
  const secretKey: string = process.env.RECAPTCHA_PRIVATE_KEY!;

  // verify the reCaptcha token
  const response = await fetch(
    `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${token}&remoteip=${ip}`,
    {
      method: 'POST',
    },
  );
  console.log({
    secret: secretKey,
    response: token,
    remoteip: ip,
  });
  const responseJson = await response.json();
  if (!responseJson['success']) {
    res.status(403).json({ message: 'Failed to verify because ' + responseJson['error-codes'] });
  }

  // parse the form data
  form.parse(req, (err, fields, files) => {
    if (err) {
      res.status(400).json({ message: 'Failed to parse form data' });
      return;
    }
    const formData = new FormData();
    Object.keys(fields).forEach(key => {
      formData.append(key, fields[key] as unknown as string);
    });
    Object.keys(files).forEach(key => {
      formData.append(key, files[key] as unknown as File);
    });

    // submit the form
    fetch(formURL, {
      method: 'POST',
      body: formData,
    });
    res.status(200).json({ message: 'Success' });
  });
}



================================================
FILE: public/news-sitemap.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">
        
  <url>
    <loc>https://koellabs.com/blog/building-open-source-leaderboards</loc>
    <news:news>
      <news:publication>
        <news:name>Koel Labs Blog</news:name>
        <news:language>en</news:language>
      </news:publication>
      <news:publication_date>2025-01-11T00:00:00+00:00</news:publication_date>
      <news:title>Building Open Source Hugging Face Leaderboards</news:title>
      <news:keywords>hugging face,open source,leaderboards,speech technology,hugging face leaderboards, how to build hugging face leaderboards</news:keywords>
    </news:news>
  </url>        
  <url>
    <loc>https://koellabs.com/blog/phonemic-transcription-metrics</loc>
    <news:news>
      <news:publication>
        <news:name>Koel Labs Blog</news:name>
        <news:language>en</news:language>
      </news:publication>
      <news:publication_date>2024-12-30T00:00:00+00:00</news:publication_date>
      <news:title>A Deep Dive into Phonemic Transcription Metrics</news:title>
      <news:keywords>pronunciation learning,phonemic transcription,speech technology,language learning</news:keywords>
    </news:news>
  </url>
  <url>
    <loc>https://koellabs.com/blog/open-source-project</loc>
    <news:news>
      <news:publication>
        <news:name>Koel Labs Blog</news:name>
        <news:language>en</news:language>
      </news:publication>
      <news:publication_date>2024-12-23T00:00:00+00:00</news:publication_date>
      <news:title>Hello World! — Our Open Source Project Launch</news:title>
      <news:keywords>open source,pronunciation learning,language learning,mozilla,announcement</news:keywords>
    </news:news>
  </url>
</urlset> 


================================================
FILE: public/sitemap.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <!-- Main pages -->
  <url>
    <loc>https://koellabs.com/</loc>
    <lastmod>2024-01-01</lastmod>
    <changefreq>monthly</changefreq>
    <priority>1.0</priority>
  </url>
  <url>
    <loc>https://koellabs.com/about</loc>
    <lastmod>2024-01-01</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.8</priority>
  </url>
  <url>
    <loc>https://koellabs.com/blog</loc>
    <lastmod>2024-01-01</lastmod>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
  </url>
  <url>
    <loc>https://koellabs.com/contact</loc>
    <lastmod>2024-01-01</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.7</priority>
  </url>

  <!-- Blog posts -->
  <url>
    <loc>https://koellabs.com/blog/building-open-source-leaderboards</loc>
    <lastmod>2025-01-11</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.6</priority>
  </url>
  <url>
    <loc>https://koellabs.com/blog/phonemic-transcription-metrics</loc>
    <lastmod>2024-12-30</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.6</priority>
  </url>
  <url>
    <loc>https://koellabs.com/blog/open-source-project</loc>
    <lastmod>2024-12-23</lastmod>
    <changefreq>monthly</changefreq>
    <priority>0.6</priority>
  </url>
</urlset> 


================================================
FILE: public/WavWorklet.js
================================================
class WavWorklet extends AudioWorkletProcessor {
  constructor() {
    super();
    this.port.onmessage = this.handleMessage.bind(this);
    this.sourceSampleRate = null;
    this.targetSampleRate = null;
    this.needsResampling = false;
    this.resampleBuffer = [];
    this.resampleRatio = 1.0;
    this.resampler = null; // LibSampleRate
  }

  process(inputs, outputs, parameters) {
    // convert to single channel but keep float32, post to main thread
    const input = inputs[0]; // Input is a 2D array: channels x samples
    if (input.length > 0) {
      const numChannels = input.length;
      const numSamples = input[0].length;

      // Create an array to hold mixed single channel data
      const mixedData = new Float32Array(numSamples);

      // Mix all channels to a single channel by averaging (or summing if preferred)
      for (let i = 0; i < numSamples; i++) {
        let sum = 0;
        for (let j = 0; j < numChannels; j++) {
          sum += input[j][i]; // Add the sample from each channel
        }
        mixedData[i] = sum / numChannels; // Average the samples from all channels
      }

      // Resample if needed (for Firefox compatibility)
      const finalData = this.resample(mixedData);

      // send to main thread
      this.port.postMessage(finalData);
    }

    // Return true to keep the processor alive
    return true;
  }

  async initializeLibSampleRate() {
    // Check if LibSampleRate is available in the global scope
    if (typeof globalThis.LibSampleRate === 'undefined') {
      console.warn('LibSampleRate not available, falling back to linear interpolation:');
      return;
    }

    console.log('Using LibSampleRate for resampling');
    try {
      const { create, ConverterType } = globalThis.LibSampleRate;
      this.resampler = await create(
        1, // mono channel
        this.sourceSampleRate,
        this.targetSampleRate,
        { converterType: ConverterType.SRC_SINC_FASTEST },
      );
      console.log('libsamplerate-js resampler initialized successfully');
    } catch (error) {
      console.warn(
        'Failed to initialize libsamplerate-js, falling back to linear interpolation:',
        error,
      );
    }
  }

  async handleMessage(event) {
    if (event.data.type === 'init') {
      const data = event.data;
      this.sourceSampleRate = data.sourceSampleRate;
      this.targetSampleRate = data.targetSampleRate;
      this.needsResampling = data.sourceSampleRate !== data.targetSampleRate;
      this.resampleRatio = data.sourceSampleRate / data.targetSampleRate;
      if (this.needsResampling) {
        this.initializeLibSampleRate();
      }
    }
  }

  resample(inputData) {
    if (!this.needsResampling || inputData.length === 0) {
      return inputData;
    }

    // Use libsamplerate-js if available and initialized
    if (this.resampler) {
      return this.resampler.full(inputData);
    }

    // Fallback: Linear interpolation (original implementation)
    return this.linearResample(inputData);
  }

  linearResample(inputData) {
    const outputLength = Math.floor((inputData.length - 1) / this.resampleRatio) + 1;
    const outputData = new Float32Array(outputLength);

    for (let i = 0; i < outputLength; i++) {
      const sourceIndex = i * this.resampleRatio;
      const sourceIndexInt = Math.floor(sourceIndex);
      const fraction = sourceIndex - sourceIndexInt;

      if (sourceIndexInt + 1 < inputData.length) {
        // Linear interpolation
        outputData[i] =
          inputData[sourceIndexInt] * (1 - fraction) + inputData[sourceIndexInt + 1] * fraction;
      } else {
        outputData[i] = inputData[sourceIndexInt];
      }
    }

    return outputData;
  }
}

registerProcessor('wav-worklet', WavWorklet);



================================================
FILE: public/images/models.webp
================================================
[Binary file]


================================================
FILE: public/videos/jumanji-next-level.vtt
================================================
09:27 --> 09:33
Practice Section 1



================================================
FILE: public/videos/the-office-michael-pyramid-scheme.captions.vtt
================================================
00:00.000 --> 00:04.359
So, Phil recruited me to sell these cards, and now I am recruiting you.

00:05.064 --> 00:05.696
Who is this guy again?

00:06.060 --> 00:06.720
Don't worry about Phil.

00:06.884 --> 00:07.620
He drives a Corvette.

00:07.620 --> 00:08.475
He's doing just fine.

00:09.000 --> 00:09.086
Okay.

00:09.481 --> 00:12.415
Calling cards are the wave of the future.

00:13.702 --> 00:14.720
These things sell themselves.

00:14.740 --> 00:16.020
Who uses calling cards anyway?

00:16.122 --> 00:16.520
You know what?

00:16.926 --> 00:17.820
That's a nice attitude, Ryan.

00:18.344 --> 00:20.299
I'm just helping you invest in your future, my friend.

00:20.540 --> 00:21.858
It sounds like a get-rich-quick scheme.

00:22.040 --> 00:22.104
Yes!

00:22.421 --> 00:22.957
Thank you!

00:23.386 --> 00:24.220
You will get rich quick.

00:24.670 --> 00:24.998
We all will!

00:25.640 --> 00:27.860
Didn't you lose a lot of money on that other investment?

00:27.860 --> 00:28.715
That one from the email?

00:29.144 --> 00:29.534
You know what, Toby?

00:30.061 --> 00:34.900
When the son of the deposed king of Nigeria emails you directly asking for help, you help.

00:35.260 --> 00:37.680
His father ran the freaking country, okay?

00:39.121 --> 00:42.539
Alright, so raise your hand if you wanna get rich.

00:43.424 --> 00:43.958
Alright.

00:44.463 --> 00:46.558
No, um, how is this not a pyramid scheme?

00:47.180 --> 00:47.913
Alright, let me explain.

00:48.693 --> 00:48.900
Again.

00:52.143 --> 00:54.760
Phil has recruited me and another guy.

00:55.463 --> 00:57.960
We are getting three people each.

00:58.280 --> 01:02.700
The more people that get involved, the more people who are investing, the more money we're all gonna make.

01:03.200 --> 01:04.300
It's not a pyramid scheme.

01:04.682 --> 01:06.919
It is a, it's not even a scheme per se, it's...



================================================
FILE: public/videos/the-office-michael-pyramid-scheme.VTT
================================================
00:09.6 --> 00:13.7
Practice Section 1

00:39 --> 00:43 
Practice Section 2

01:03 --> 01:04.5
Practice Section 3

01:17 --> 01:18.2
Practice Section 4


================================================
FILE: public/videos/the-office-michael-secret-keeper-full-res.VTT
================================================
00:02 --> 00:09
Practice Section 1

02:24 --> 02:30 
Practice Section 2

03:20 --> 03:30
Practice Section 3

04:10 --> 04:30
Practice Section 4



================================================
FILE: public/.well-known/microsoft-identity-association.json
================================================
{
  "associatedApplications": [
    {
      "applicationId": "1975b5cb-733d-4be0-83c1-45632a8c9796"
    }
  ]
}



================================================
FILE: scripts/docker-compose.dev.yaml
================================================
services:
  postgres:
    image: postgres
    env_file: '../.env.local'
    ports:
      - '5432:5432'
    volumes:
      - ../data:/var/lib/postgresql
  server:
    build:
      context: '../server'
      dockerfile: './scripts/Dockerfile.dev'
    env_file: '../server/.env'
    ports:
      - '8080:8080'
    volumes:
      - ../server/src:/app/src
      - ../server/.cache/huggingface/hub:/app/.cache/huggingface/hub
  webapp:
    entrypoint: bash -c "npm install && npm run migrate && npm run dev"
    build:
      context: ..
      dockerfile: ./scripts/Dockerfile.dev
    env_file: '../.env.local'
    depends_on:
      - postgres
      - server
    ports:
      - '3000:3000'
    volumes:
      - ..:/app
      - /app/node_modules/



================================================
FILE: scripts/docker-run-dev-cmd.sh
================================================
#!/bin/bash

docker build --tag 'scripts-webapp' -f ./scripts/Dockerfile.dev .

docker run -t -i -p 3000:3000 -v .:/app -v /app/node_modules/ --env-file .env.local 'scripts-webapp' $@



================================================
FILE: scripts/docker-run-dev.sh
================================================
#!/bin/bash

open http://localhost:3000 || start chrome \"http://localhost:3000\" || google-chrome 'http://localhost:3000' || echo 'Could not open browser automatically. Please open http://localhost:3000 manually'
docker-compose -f ./scripts/docker-compose.dev.yaml up -d
docker-compose -f ./scripts/docker-compose.dev.yaml logs -f
. ./scripts/docker-stop-dev.sh



================================================
FILE: scripts/docker-stop-dev.sh
================================================
#!/bin/bash

docker-compose -f ./scripts/docker-compose.dev.yaml down



================================================
FILE: scripts/Dockerfile.dev
================================================
FROM node:18.18.0-slim as base

# Node.js app lives here
WORKDIR /app

# Throw-away build stage to reduce size of final image
FROM base as build

# Install packages needed to build node modules
RUN apt-get update -qq && \
    apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3

# Install node modules
COPY --link package.json ./
RUN npm install

# Final stage for app image
FROM base

# Copy built application
COPY --from=build /app /app

# Next.js collects anonymous telemetry data about general usage. Learn more here: https://nextjs.org/telemetry
# The following environment variable disables this feature
ENV NEXT_TELEMETRY_DISABLED 1



================================================
FILE: styles/animations.css
================================================
@keyframes dash {
  100% {
    stroke-dashoffset: 4000;
  }
  50% {
    stroke-dashoffset: 0;
  }
  0% {
    stroke-dashoffset: 4000;
  }
}

.path-trace {
  stroke-dasharray: 4000;
  stroke-dashoffset: 4000;
  animation: dash 15s ease-in-out infinite;
  stroke-width: 1;
}

.pulse-effect {
  animation: pulse 2s ease-in-out infinite;
}

@keyframes path-trace-footer {
  100% {
    stroke-dashoffset: 0%;
  }
  0% {
    stroke-dashoffset: 100%;
  }
}

.path-trace-footer {
  offset-path: path(
    'm907.047 75.174-30.484 1.876q-.782-3.908-3.361-7.035-2.58-3.204-6.8-5.08-4.143-1.954-9.927-1.954-7.738 0-13.054 3.282-5.315 3.205-5.315 8.599 0 4.299 3.439 7.269t11.803 4.768l21.73 4.377q17.509 3.596 26.107 11.568 8.598 7.974 8.598 20.948 0 11.803-6.957 20.714-6.879 8.91-18.916 13.913-11.958 4.924-27.592 4.924-23.84 0-37.987-9.926-14.07-10.005-16.493-27.202l32.751-1.719q1.485 7.27 7.191 11.099 5.706 3.752 14.616 3.752 8.755 0 14.07-3.361 5.393-3.44 5.472-8.833-.079-4.533-3.831-7.425-3.751-2.97-11.568-4.534l-20.792-4.142q-17.586-3.518-26.185-12.194-8.519-8.677-8.519-22.12 0-11.57 6.253-19.932 6.331-8.364 17.743-12.897 11.49-4.534 26.888-4.534q22.746 0 35.8 9.614 13.131 9.615 15.32 26.185ZM681.051 160.998V.918h33.298v60.186h1.016q2.188-4.845 6.331-9.848 4.221-5.08 10.943-8.442 6.801-3.44 16.884-3.44 13.131 0 24.231 6.88 11.099 6.8 17.743 20.556 6.644 13.68 6.644 34.315 0 20.087-6.488 33.923-6.41 13.757-17.509 20.87-11.02 7.034-24.699 7.034-9.693 0-16.493-3.204-6.723-3.205-11.021-8.051-4.3-4.924-6.566-9.927h-1.485v19.228zm32.594-60.03q0 10.709 2.971 18.681t8.598 12.429q5.628 4.377 13.678 4.377 8.13 0 13.757-4.456 5.628-4.533 8.52-12.506 2.97-8.05 2.97-18.525 0-10.395-2.892-18.29t-8.52-12.35q-5.627-4.456-13.835-4.456-8.129 0-13.757 4.3-5.549 4.298-8.519 12.193-2.971 7.895-2.971 18.603ZM600.186 163.265q-11.49 0-20.479-3.986-8.99-4.065-14.226-11.959-5.159-7.972-5.159-19.854 0-10.005 3.674-16.805t10.005-10.943 14.382-6.253q8.13-2.11 17.04-2.97 10.474-1.094 16.884-2.033 6.41-1.016 9.301-2.97t2.892-5.784v-.47q0-7.425-4.69-11.49-4.611-4.064-13.131-4.064-8.99 0-14.304 3.986-5.316 3.909-7.035 9.85l-30.797-2.502q2.345-10.942 9.224-18.916 6.878-8.05 17.743-12.35 10.943-4.377 25.325-4.377q10.005 0 19.15 2.345 9.224 2.344 16.337 7.27 7.191 4.923 11.333 12.662 4.143 7.66 4.143 18.368V161H636.22V144.35h-.938q-2.892 5.627-7.738 9.926-4.846 4.221-11.647 6.644-6.8 2.345-15.711 2.345Zm9.536-22.98q7.347 0 12.975-2.892 5.628-2.97 8.833-7.973 3.204-5.002 3.205-11.334v-12.74q-1.565 1.015-4.299 1.876a79 79 0 0 1-6.019 1.485q-3.361.625-6.722 1.172-3.361.469-6.097.86-5.862.86-10.24 2.736-4.377 1.875-6.8 5.08-2.423 3.127-2.423 7.817 0 6.8 4.924 10.396 5.003 3.517 12.663 3.517ZM454.896 160.998V.918h33.846v132.176h68.628v27.904zM403.067.918v160.08H369.77V.918zM361.245 109.488v-9.145q0-15.32-4.299-26.732-4.299-11.49-12.037-19.072-7.66-7.582-17.978-11.334-10.24-3.83-22.121-3.83-17.665 0-30.796 7.816Q260.96 55.007 253.769 69t-7.191 32.517q0 18.993 7.191 32.907 7.192 13.834 20.479 21.417 13.366 7.503 31.891 7.503q14.851 0 26.185-4.533 11.412-4.612 18.603-12.819 7.27-8.285 9.615-19.385l-30.797-2.032q-1.72 4.534-5.003 7.66-3.282 3.126-7.894 4.69-4.612 1.563-10.162 1.563-8.363 0-14.46-3.517-6.096-3.518-9.458-10.005-3.282-6.487-3.283-15.399zm0 0h-81.76m.032-20.635h50.384q0-7.191-3.126-12.74t-8.677-8.677q-5.47-3.205-12.74-3.205-7.582 0-13.445 3.518-5.784 3.439-9.067 9.301c-2.188 3.856-3.277 7.061-3.329 11.803ZM183.889 163.343q-18.212 0-31.5-7.738-13.21-7.817-20.401-21.729-7.191-13.992-7.191-32.439 0-18.602 7.191-32.516 7.19-13.991 20.401-21.73 13.288-7.815 31.5-7.816 18.213 0 31.422 7.816 13.288 7.739 20.479 21.73 7.191 13.914 7.191 32.516 0 18.447-7.191 32.439-7.19 13.912-20.479 21.729-13.209 7.738-31.422 7.738Zm.156-25.794q8.286 0 13.835-4.69 5.55-4.767 8.364-12.975 2.892-8.207 2.892-18.681t-2.892-18.681q-2.814-8.208-8.364-12.976-5.549-4.767-13.835-4.768-8.363 0-14.069 4.768-5.628 4.769-8.52 12.976-2.814 8.206-2.814 18.681t2.814 18.681q2.892 8.208 8.52 12.975 5.706 4.69 14.069 4.69Z'
  );
  animation: path-trace-footer 22s linear infinite;
}

/* Highlight animation for newly added videos */
@keyframes highlight-pulse {
  0% {
    background-color: rgba(59, 130, 246, 0);
  }
  50% {
    background-color: rgba(59, 130, 246, 0.2);
  }
  100% {
    background-color: rgba(59, 130, 246, 0);
  }
}

.highlight-animation {
  animation: highlight-pulse 1s ease-in-out 3;
}

/* Dark mode version */
@media (prefers-color-scheme: dark) {
  @keyframes highlight-pulse-dark {
    0% {
      background-color: rgba(59, 130, 246, 0);
    }
    50% {
      background-color: rgba(59, 130, 246, 0.3);
    }
    100% {
      background-color: rgba(59, 130, 246, 0);
    }
  }

  .highlight-animation {
    animation: highlight-pulse-dark 1s ease-in-out 3;
  }
}

/* Sequential fade-in and move-up animation */
@keyframes fade-move-up {
  0% {
    opacity: 0;
    transform: translateY(20px);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.animate-in {
  opacity: 0;
  animation: fade-move-up 0.5s ease forwards;
}

.animate-in-1 {
  animation-delay: 0.1s;
}

.animate-in-2 {
  animation-delay: 0.3s;
}

.animate-in-3 {
  animation-delay: 0.5s;
}

.animate-in-4 {
  animation-delay: 0.7s;
}

.animate-in-5 {
  animation-delay: 0.9s;
}



================================================
FILE: .github/pull_request_template.md
================================================
### PR Description

- This PR addresses #[issue number]
- This PR [short description]

[screenshots if applicable]

### Q/A checklist

- [ ] If you added new dependencies, double-check there are no security vulnerabilities with `npm audit`, make sure they are well maintained, and generate a license report with `npm run license-report`. The report should be updated in [ACKNOWLEDGEMENTS.md](ACKNOWLEDGEMENTS.md) and the license for the dependency should be compatible with the [FSL-1.1-Apache-2.0](https://fsl.software/) license.
- [ ] Run formatting, linting, tests, and security checks (see [DEVELOPMENT.md](DEVELOPMENT.md))
- [ ] Do a self code review of the changes - Read the diff at least twice.
- [ ] I have written tests for any new features and regression tests for any bug fixes.

### Legal Boilerplate

Look, I get it. The entity doing business as "Koel Labs" needs some rights from me in order to utilize my contributions in this PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Koel Labs can use, modify, copy, and redistribute my contributions, under its choice of terms.



================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---

### Prerequisites

<!-- Put an x between the brackets for each of the steps below to indicate their completion. -->

- [ ] Use a clear and descriptive title for the issue to identify the problem
- [ ] Checked the FAQ for common solutions
- [ ] Checked that your issue isn't already filed

### Description

<!-- Description of the issue -->

### Steps to Reproduce

1. <!-- First Step -->
2. <!-- Second Step -->
3. <!-- and so on… -->

<!-- Include screenshots and animated GIFs which show you following the described steps and clearly demonstrate the problem -->
<!-- If the problem wasn't triggered by a specific action, describe what you were doing before the problem happened -->

**Expected behavior:**

<!-- What you expect to happen -->

**Actual behavior:**

<!-- What actually happens -->
<!-- Screenshots of any error messages in the terminal or browser console -->

**Reproduces how often:**

<!-- Can you reliably reproduce the issue? If not, provide details about how often the problem happens and under which conditions it normally happens. -->

**Did the problem start happening recently:**

<!-- Was this always a problem or did it start happening recently? -->
<!-- If it started recently, approximately when did it start? If running locally, can you pinpoint the first commit where it breaks? -->

**Configuration and environment:**

- Using the hosted version on koellabs.com or running locally with docker or running locally without docker
- Name and version of the OS you're using
- Name and version of the browser you're using

### Additional Information

<!-- Any additional information, configuration or data that might be necessary to reproduce the issue. -->



================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---

## Summary

<!-- One paragraph explanation of the feature. -->

## Motivation

<!-- Why are we doing this? What use cases does it support? What is the expected outcome? -->
<!-- A clear and concise description of what the problem being solved is. Ex. I'm always frustrated when... -->

## Describe alternatives you've considered

<!-- A clear and concise description of the alternative solutions you've considered. -->

## Additional context

<!-- Add any other context or screenshots about the feature request here. -->



================================================
FILE: .github/workflows/azure-static-web-apps-salmon-sky-0a6b6c10f.yml
================================================
name: Azure Static Web Apps CI/CD

on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, reopened, closed]
    branches:
      - main

permissions:
  contents: read           # Access to repository content for build and deploy

jobs:
  build_and_deploy_job:
    if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
    runs-on: ubuntu-latest
    name: Build and Deploy Job
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true
          lfs: false
          persist-credentials: false
      - name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@1a947af9992250f3bc2e68ad0754c0b0c11566c9
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_SALMON_SKY_0A6B6C10F }}
          repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
          action: 'upload'
          ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
          # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
          app_location: '/' # App source code path
          api_location: '' # Api source code path - optional
          output_location: '' # Built app content directory - optional
          ###### End of Repository/Build Configurations ######
        env:
          NEXT_PUBLIC_RECAPTCHA_SITE_KEY: '6Lfm4a0qAAAAADOh_Y470P2JtrGq5V84RHd2wSOv'

  close_pull_request_job:
    if: github.event_name == 'pull_request' && github.event.action == 'closed'
    runs-on: ubuntu-latest
    name: Close Pull Request Job
    steps:
      - name: Close Pull Request
        id: closepullrequest
        uses: Azure/static-web-apps-deploy@1a947af9992250f3bc2e68ad0754c0b0c11566c9
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_SALMON_SKY_0A6B6C10F }}
          action: 'close'



================================================
FILE: .github/workflows/gitleaks.yml
================================================
name: Secret Scanning

on: [push, pull_request]

permissions:
  contents: read

jobs:
  scan:
    name: gitleaks
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: false
          persist-credentials: false
          fetch-depth: 0
      - uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}



================================================
FILE: .github/workflows/zizmor.yml
================================================
name: Zizmor Actions Security

on: [push, pull_request]

jobs:
  zizmor:
    name: zizmor latest via PyPI
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          submodules: false
          persist-credentials: false

      - name: Install the latest version of uv
        uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04

      - name: Run zizmor 🌈
        run: uvx zizmor .
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}


