+ = e($post['title']) ?> +
+= e($post['description']) ?>
+diff --git a/.gitignore b/.gitignore index 2309cc8..096746c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,138 +1 @@ -# ---> Node -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# vitepress build output -**/.vitepress/dist - -# vitepress cache directory -**/.vitepress/cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - +/node_modules/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..52c09b3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "workbench.colorCustomizations": { + "titleBar.activeForeground": "#ffffff", + "titleBar.inactiveForeground": "#ffffff", + "titleBar.activeBackground": "#5920bc", + "titleBar.inactiveBackground": "#3f1883" + }, + + "editor.fontSize": 15, + "editor.tabSize": 2, + "terminal.integrated.fontSize": 15, + "window.zoomLevel": 1, + "[Log]": { + "editor.fontSize": 14 + }, + +"html-css-class-completion.includeGlobPattern": "public/css/**/*.{css,scss}", +"liveServer.settings.port": 5501 +} diff --git a/LICENSE b/LICENSE index 4d4a39d..99d100a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,73 +1,5 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ + Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: - - (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. - - You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - -To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. - -Copyright 2026 framex - -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. + Feel free to build anything you want! \ No newline at end of file diff --git a/README.md b/README.md index 9a4402e..57130f4 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,384 @@ -# framexEngine-pro +# Framex Engine +> A lightweight, high-performance PHP engine for building static sites and modern web applications. + +[](https://php.net) +[](https://tailwindcss.com) +[](LICENSE) + +--- + +## Table of Contents + +- [What is Framex?](#what-is-framex) +- [Features](#features) +- [Quick Start](#quick-start) +- [Project Structure](#project-structure) +- [Creating Pages](#creating-pages) + - [PHP Pages](#php-pages) + - [Markdown Pages](#markdown-pages) +- [Templates & Partials](#templates--partials) +- [Styling](#styling) +- [Helper Functions](#helper-functions) +- [Contributing](#contributing) +- [License](#license) + +--- + +## What is Framex? + +**Framex Engine** is a minimal PHP framework designed for developers who want to ship fast static sites without the bloat of traditional CMS platforms or over-engineered frameworks. + +No database. No complex routing files. No plugin ecosystem to maintain. Just **PHP files**, **Markdown content**, and a directory structure that mirrors your URLs. + +Framex is perfect for: + +- Landing pages & marketing sites +- Documentation & blogs +- Portfolios & personal sites +- Prototypes & MVPs +- Any site where content changes faster than architecture + +--- + +## Features + +| Feature | Description | +|---------|-------------| +| **URL-Driven Routing** | Your folder structure *is* your routing. Zero configuration. | +| **Infinite Pages** | Create a file → get a page. No database required. | +| **Markdown Support** | Write content in `.md` files. Rendered automatically via Parsedown. | +| **Template System** | Switch layouts per page. Reusable partials for DRY templates. | +| **Tailwind CSS v4** | Pre-configured with Lightning CSS. Utility-first, blazing fast builds. | +| **Asset Pipeline** | Built-in cache busting, file hashing, and development helpers. | +| **Zero Dependencies** | Works on any shared host. No Composer required for core features. | +| **Dark Theme Ready** | Modern dark UI components included out of the box. | +| **Light / Dark Mode** | Automatic system detection with manual toggle. Persisted in localStorage. | + +--- + +## Quick Start + +### Requirements + +- PHP 8.0 or higher +- Node.js 18+ (for CSS build pipeline) + +### Installation + +```bash +# Clone the repository +git clone https://github.com/yourusername/framex-engine.git my-project +cd my-project + +# Install dependencies +npm install + +# Start the development watcher +npm run dev +``` + +Point your web server to the `public/` directory and visit `http://localhost`. + +> **Note:** If you use PHP's built-in server, run it from the project root: +> ```bash +> php -S localhost:8000 -t public/ +> ``` + +--- + +## Project Structure + +``` +framexEngine-Base/ +├── app/ +│ ├── views/ # Your pages live here +│ │ ├── index.php +│ │ ├── about.php +│ │ └── blog/ +│ │ └── hello-world.md +│ └── about/ +│ +├── core/ +│ ├── classes/ +│ │ ├── Engine.php # Router & request handler +│ │ ├── Framex.php # View renderer +│ │ └── Parsedown.php # Markdown parser +│ ├── config.php # Constants & configuration +│ ├── functions.php # Global helper functions +│ └── ignition.php # Application bootstrap +│ +├── templates/ +│ ├── main.php # Default layout (nav + footer) +│ ├── clean.php # Minimal layout +│ ├── admin.php # Dashboard layout +│ ├── error404.php # 404 error page +│ └── partials/ +│ ├── topmenu.php +│ └── footer.php +│ +├── public/ +│ ├── css/ # Compiled stylesheets +│ ├── js/ # Scripts +│ ├── images/ +│ └── index.php # Entry point +│ +├── public/css/src/ # CSS source files +│ ├── style.css # Main site styles +│ ├── admin.css # Admin panel styles +│ └── ... +│ +└── package.json # Build scripts & dependencies +``` + +--- + +## Creating Pages + +### PHP Pages + +Create a file in `app/views/` and it instantly becomes a URL: + +| File | URL | +|------|-----| +| `app/views/index.php` | `/` | +| `app/views/about.php` | `/about` | +| `app/views/blog/post.php` | `/blog/post` | +| `app/views/contact/index.php` | `/contact` | + +Example page (`app/views/about.php`): + +```php + + +
This page was created by dropping a single PHP file in the views folder.
+``` + +### Markdown Pages + +Prefer writing in Markdown? Save your content as a `.md` file: + +| File | URL | +|------|-----| +| `app/views/changelog.md` | `/changelog` | +| `app/views/docs/installation.md` | `/docs/installation` | + +Framex automatically detects the extension, runs it through [Parsedown](https://parsedown.org/), and wraps it in your template. + +```markdown +# Installation + +1. Clone the repo +2. Run `npm install` +3. Start hacking +``` + +--- + +## Templates & Partials + +### Switching Templates + +By default, every page wraps inside `templates/main.php`. You can switch this per page: + +```php + +``` + +Built-in templates: + +| Template | Purpose | +|----------|---------| +| `main` | Default layout with navigation and footer | +| `clean` | Minimal layout, no wrappers | +| `admin` | Dashboard sidebar layout | + +### Partials + +Reusable chunks live in `templates/partials/`: + +```php + +``` + +Create your own: + +```bash +touch templates/partials/newsletter.php +``` + +```php + + +``` + +Include it anywhere: + +```php + +``` + +--- + +## Styling + +Framex ships with **Tailwind CSS v4** pre-configured. The build pipeline uses the Tailwind CLI with Lightning CSS for maximum performance. + +### Development + +```bash +# Watch for changes and rebuild automatically +npm run dev +``` + +### Production + +```bash +# Build minified CSS for production +npm run build +``` + +### CSS Source Files + +| File | Output | Purpose | +|------|--------|---------| +| `public/css/src/style.css` | `public/css/style.css` | Main site styles | +| `public/css/src/admin.css` | `public/css/admin.css` | Admin panel styles | +| `public/css/src/responsive.css` | `public/css/responsive.css` | Responsive overrides | +| `public/css/src/vendors.css` | `public/css/vendors.css` | Third-party styles | + +### Using Custom CSS + +You are not locked into Tailwind. The CSS pipeline is completely optional. You can: + +- Write vanilla CSS in `public/css/src/` +- Use Sass/SCSS (still installed) +- Link external CSS frameworks from a CDN +- Replace the entire build pipeline + +--- + +## Light & Dark Mode + +Framex includes a built-in light/dark mode toggle that respects the user's system preference and persists their choice in `localStorage`. + +- **Automatic detection** — Checks `prefers-color-scheme: dark` on first visit +- **Manual toggle** — Sun/moon button in the navbar +- **Instant switch** — Zero page reload, powered by Tailwind's `dark:` utilities +- **Persistent** — Choice is saved and restored on every page + +To style for dark mode in your templates, use Tailwind's `dark:` prefix: + +```html ++ Built with ❤️ by Prodigital Framex +
diff --git a/app/views/about/index.md b/app/views/about/index.md new file mode 100644 index 0000000..4fa7fd7 --- /dev/null +++ b/app/views/about/index.md @@ -0,0 +1,68 @@ + + +# About Framex + +Hi, I am **Thanos**. I have been involved with computers, hardware, and practical IT work since 1995. Framex is a small PHP project I built and refined through real use, mostly for fast static pages, custom CSS experiments, presentations, API-driven pages, and lightweight content sites. + + + +## Why this project exists + +Framex is built around one simple idea: a website should be easy to understand from its files. + +Routes map to files in `app/views`, templates live in `templates`, public assets live in `public`, and styling is handled through Tailwind CSS 4 or any CSS approach you prefer. There is no heavy framework layer to learn before you can build a page. + +## What it is good for + +- **Static websites** that need clean URLs and reusable templates. +- **Markdown documentation** with automatic typography and dark-mode support. +- **Small business websites** where speed and maintainability matter. +- **Custom landing pages** with modern Tailwind components. +- **API-powered pages** when you need PHP logic without a large framework. +- **Presentations and prototypes** that should stay portable and simple. + +## Design goals + +Framex tries to stay: + +- **Lightweight:** only the pieces needed to render pages clearly. +- **Fast:** no unnecessary runtime complexity. +- **Readable:** routes, views, templates, and assets are easy to find. +- **Flexible:** use PHP views, Markdown views, Tailwind CSS, or plain CSS. +- **Practical:** built for developers who want to ship pages without ceremony. + +## How pages work + +A URL such as `/about` resolves to a file like: + +```text +app/views/about/index.md +``` + +A URL such as `/demo/blog-post` resolves to: + +```text +app/views/demo/blog-post.php +``` + +Markdown pages are automatically parsed and styled. PHP pages can use custom markup, arrays, loops, metadata, and reusable helpers. + +## Usage + +You can use, extend, modify, reduce, or rebuild this project for personal and commercial work. Treat it as a starting point, not a locked system. + +Good next steps: + +- Read the [documentation](/docs). +- Explore the [demo pages](/demo). +- Create a new PHP view in `app/views`. +- Create a new Markdown page with `index.md`. +- Rebuild CSS with `npm run build:css` when you add new Tailwind classes. + +## Disclaimer + +This is a personal project shared for developers and people who understand how to work with PHP projects. I have used it for years without issues, but you are responsible for how you use it, modify it, deploy it, and secure it. + +Use it carefully, make backups, and review the code before using it in production. + +**Enjoy building.** diff --git a/app/views/blocks/accordion/accordion-1.php b/app/views/blocks/accordion/accordion-1.php new file mode 100644 index 0000000..28db820 --- /dev/null +++ b/app/views/blocks/accordion/accordion-1.php @@ -0,0 +1,53 @@ ++ Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ab hic veritatis molestias culpa + in, recusandae laboriosam neque aliquid libero nesciunt voluptate dicta quo officiis + explicabo consequuntur distinctio corporis earum similique! +
++ Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ab hic veritatis molestias culpa + in, recusandae laboriosam neque aliquid libero nesciunt voluptate dicta quo officiis + explicabo consequuntur distinctio corporis earum similique! +
++ Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ab hic veritatis molestias culpa + in, recusandae laboriosam neque aliquid libero nesciunt voluptate dicta quo officiis + explicabo consequuntur distinctio corporis earum similique! +
++ Lorem ipsum dolor sit amet elit ut aliquam +
+ ++ The latest news with Flowspark +
+Laila Bahar
+ +6 mins read
++ The latest news with Flowspark +
+Laila Bahar
+ +6 mins read
++ The latest news with Flowspark +
+Laila Bahar
+ +6 mins read
++ Lorem ipsum dolor sit amet elit ut aliquam +
+ ++ FramexEngine +
++ The latest news with Flowspark +
+Laila Bahar
+ +6 mins read
++ FramexEngine +
++ Here is the title for this blog +
+Laila Bahar
+ +6 mins read
++ FramexEngine +
++ Here is the title for this blog +
+Laila Bahar
+ +6 mins read
++ FramexEngine +
++ Here is the title for this blog +
+Laila Bahar
+ +6 mins read
++ Lorem ipsum dolor sit amet elit ut aliquam +
+ +Lorem ipsum dolor sit amet elit ut aliquam
+Lorem ipsum dolor sit amet elit ut aliquam
++ We make every expression of Hero Spirits with precision and + passion +
++ We make every expression of Hero Spirits with precision and + passion +
++ We make every expression of Hero Spirits with precision and + passion +
++ Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eaque, nisi. Natus, provident + accusamus impedit minima harum corporis iusto. +
+ ++ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse + varius enim in eros elementum tristique. Duis cursus, mi quis viverra + ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. +
+
+ Aliquet risus feugiat in ante metus. Arcu dui vivamus arcu felis
+ bibendum ut. Vestibulum lorem sed risus ultricies tristique nulla.
+ Vitae et leo duis ut diam quam. Bibendum arcu vitae elementum
+ curabitur vitae nunc. Dictumst vestibulum rhoncus est
+ pellentesque. Lectus proin nibh nisl condimentum id. Ullamcorper
+ dignissim cras tincidunt lobortis feugiat vivamus.
+
+
+ Massa id neque aliquam vestibulum morbi blandit. Nulla
+ pellentesque dignissim enim sit amet venenatis.
+
+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Tenetur doloremque saepe + architecto maiores repudiandae amet perferendis repellendus, reprehenderit voluptas + sequi. +
+Blog list demo
++ This page is a PHP view. It uses an array of posts, loops through the data, and renders a responsive grid without needing a separate component system. +
+= e($post['description']) ?>
+Architecture / 7 min read
++ A modern site does not need a heavy runtime to feel polished. Framex keeps page resolution, templates, assets, and Markdown close to the filesystem. +
+Framex Team
+Published May 12, 2026
+Routing
+Files become URLs
+Views
+PHP and Markdown
+Design
+Tailwind CSS 4
+Framex resolves URLs by checking for matching PHP and Markdown files inside app/views. This keeps page creation predictable for new developers and small teams.
A route such as /demo/blog-post can be backed by app/views/demo/blog-post.php, while documentation can be written as Markdown in app/views/docs/index.md.
Every page is wrapped by the main template, which includes the top menu, current view content, footer, compiled CSS, and JavaScript. PHP views can set metadata through the $data array.
++ +Keep page-specific content in views, shared structure in templates, and reusable visual rules in Tailwind source CSS.
+
Markdown pages are useful for documentation and simple publishing workflows. PHP views are better when a page needs custom data, cards, grids, forms, or conditional rendering.
+ +// PHP view route
+app/views/demo/blog-post.php
+
+// Markdown view route
+app/views/demo/page.md
+ Next demo
+Demo library
++ These demos show how PHP views and Markdown views can share the same template, navigation, footer, light/dark mode, and reusable Tailwind classes. +
+4
+Demo routes
+2
+View types
+4
+Preset colors
+1
+Shared layout
+Choose the right plan.
+Card content.
+PHP engine plus Tailwind CSS 4
++ FramexEngine keeps routing, markdown, templates, and assets simple so you can ship lightweight PHP sites with a modern design system already in place. +
+ +<?php
+$data['title'] = 'Framex';
+// templates, markdown, Tailwind
+?>
+CSS-first
+Tailwind v4 build flow.
+Markdown
+Auto styled pages.
+Features
+PHP and markdown views resolve cleanly from the app views directory.
+Sections, buttons, cards, containers, and preset backgrounds are ready to use.
+Theme preference follows the system first, then persists your manual choice.
+FramexEngine ideas
++ Framex works well for pages that should be easy to edit, fast to ship, and simple to understand from the filesystem. +
+Use Markdown views for guides, API notes, changelogs, and internal knowledge bases.
+Build fast campaign pages with shared templates, reusable cards, and Tailwind utilities.
+Use PHP views for simple data pages, status panels, metrics, and external API summaries.
+Create a lightweight blog, portfolio, or notes site without adding a database first.
+Markdown pages
++ Framex already parses markdown views. The refreshed `.prose` layer now styles content, code, images, tables, and blockquotes automatically in both themes. +
+Write normal content and let the design system handle spacing, readable line length, and theme colors.
++Markdown pages should look intentional without extra template work.
## Fast content
+- Create a view.md file
+- Publish clean HTML
+- Keep styling automatic
+ Preset colors
+Blue
+Primary calls and product highlights.
+Emerald
+Success states and fresh sections.
+Amber
+Notes, warnings, and warm accents.
+Rose
+Promos and energetic content blocks.
+Ready foundation
+Lorem ipsum dolor sit amet consectetur adipisicing elit. Qui excepturi soluta quos nostrum, est ex, maxime repudiandae laborum molestias inventore debitis. Nihil quidem explicabo assumenda debitis quas, beatae molestiae officiis.
+Lorem ipsum dolor sit amet consectetur adipisicing elit. Qui excepturi soluta quos nostrum, est ex, maxime repudiandae laborum molestias inventore debitis. Nihil quidem explicabo assumenda debitis quas, beatae molestiae officiis.
+ and tags with the appropriate class
+ $output = '';
+ $output .= $safe_code;
+ $output .= '
';
+
+ return $output;
+}
+
+
+/**
+ * Pre Helper
+ *
+ * @param mixed $array The data to print.
+ * @param bool|null $die Whether to stop execution after printing.
+ * @param bool $report Whether to echo the data directly.
+ */
+function pre($array, ?bool $die = null, bool $report = false): void {
+ if ($report) {
+ echo $array;
+ }
+ echo '' . print_r($array, true) . '
';
+ if ($die) {
+ die();
+ }
+}
+
+/**
+ * Get Random Image
+ *
+ * @param int $width The width of the image.
+ * @param int $height The height of the image.
+ * @return string The URL of the random image.
+ */
+function image(int $width = 960, int $height = 576): string {
+ return 'https://picsum.photos/' . $width . '/' . $height . '?v=' . rand();
+}
+
+/**
+ * Sanitize Input
+ *
+ * @param string $data The data to sanitize.
+ * @return string The sanitized data.
+ */
+function e(string $data): string {
+ return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
+}
+
+/**
+ * Summarize Text
+ *
+ * @param string $text The text to summarize.
+ * @param int $maxLength The maximum length of the summary.
+ * @return string The summarized text.
+ */
+function summarize(string $text, int $maxLength = 100): string {
+ if (strlen($text) <= $maxLength) {
+ return $text;
+ }
+ $summary = substr($text, 0, $maxLength);
+ return $summary . '...';
+}
+
+function urlSlug($value, $transliteration = true)
+{
+ if (extension_loaded('intl') && $transliteration == true) {
+ $transliterator = \Transliterator::create('Any-Latin; Latin-ASCII');
+ $value = $transliterator->transliterate($value);
+ }
+ $slug = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
+ $slug = preg_replace('~[^\pL\d]+~u', '-', $slug);
+ $slug = trim($slug, '-');
+ $slug = strtolower($slug);
+ return $slug;
+}
+
diff --git a/core/ignition.php b/core/ignition.php
new file mode 100644
index 0000000..28a8800
--- /dev/null
+++ b/core/ignition.php
@@ -0,0 +1,17 @@
+=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@parcel/watcher": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz",
+ "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^2.0.3",
+ "is-glob": "^4.0.3",
+ "node-addon-api": "^7.0.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher-android-arm64": "2.5.6",
+ "@parcel/watcher-darwin-arm64": "2.5.6",
+ "@parcel/watcher-darwin-x64": "2.5.6",
+ "@parcel/watcher-freebsd-x64": "2.5.6",
+ "@parcel/watcher-linux-arm-glibc": "2.5.6",
+ "@parcel/watcher-linux-arm-musl": "2.5.6",
+ "@parcel/watcher-linux-arm64-glibc": "2.5.6",
+ "@parcel/watcher-linux-arm64-musl": "2.5.6",
+ "@parcel/watcher-linux-x64-glibc": "2.5.6",
+ "@parcel/watcher-linux-x64-musl": "2.5.6",
+ "@parcel/watcher-win32-arm64": "2.5.6",
+ "@parcel/watcher-win32-ia32": "2.5.6",
+ "@parcel/watcher-win32-x64": "2.5.6"
+ }
+ },
+ "node_modules/@parcel/watcher-android-arm64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz",
+ "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-arm64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz",
+ "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-x64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz",
+ "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-freebsd-x64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz",
+ "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-glibc": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz",
+ "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-musl": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz",
+ "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-glibc": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz",
+ "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-musl": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz",
+ "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-glibc": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz",
+ "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-musl": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz",
+ "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-arm64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz",
+ "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-ia32": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz",
+ "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-x64": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz",
+ "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@tailwindcss/cli": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.3.0.tgz",
+ "integrity": "sha512-X9kdlqyMopO9fewbgHsEeuy31YzMHbdZ9VsKt004tB+mxSg1CNbyhZYCzvhciN0AM4R4b5lvIprPjtNq7iQxpQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/watcher": "^2.5.1",
+ "@tailwindcss/node": "4.3.0",
+ "@tailwindcss/oxide": "4.3.0",
+ "enhanced-resolve": "^5.21.0",
+ "mri": "^1.2.0",
+ "picocolors": "^1.1.1",
+ "tailwindcss": "4.3.0"
+ },
+ "bin": {
+ "tailwindcss": "dist/index.mjs"
+ }
+ },
+ "node_modules/@tailwindcss/node": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz",
+ "integrity": "sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.5",
+ "enhanced-resolve": "^5.21.0",
+ "jiti": "^2.6.1",
+ "lightningcss": "1.32.0",
+ "magic-string": "^0.30.21",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.3.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.0.tgz",
+ "integrity": "sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.3.0",
+ "@tailwindcss/oxide-darwin-arm64": "4.3.0",
+ "@tailwindcss/oxide-darwin-x64": "4.3.0",
+ "@tailwindcss/oxide-freebsd-x64": "4.3.0",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.0",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.3.0",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.3.0",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.3.0",
+ "@tailwindcss/oxide-linux-x64-musl": "4.3.0",
+ "@tailwindcss/oxide-wasm32-wasi": "4.3.0",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.3.0",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.3.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.0.tgz",
+ "integrity": "sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.0.tgz",
+ "integrity": "sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.0.tgz",
+ "integrity": "sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.0.tgz",
+ "integrity": "sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.0.tgz",
+ "integrity": "sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.0.tgz",
+ "integrity": "sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.0.tgz",
+ "integrity": "sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.0.tgz",
+ "integrity": "sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.0.tgz",
+ "integrity": "sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.0.tgz",
+ "integrity": "sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.10.0",
+ "@emnapi/runtime": "^1.10.0",
+ "@emnapi/wasi-threads": "^1.2.1",
+ "@napi-rs/wasm-runtime": "^1.1.4",
+ "@tybys/wasm-util": "^0.10.1",
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.0.tgz",
+ "integrity": "sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.0.tgz",
+ "integrity": "sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.21.3",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.3.tgz",
+ "integrity": "sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.3.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/jiti": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
+ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/mri": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
+ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
+ "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..e039306
--- /dev/null
+++ b/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "prodigital-framex",
+ "version": "1.0.0",
+ "description": "Framex Project",
+ "keywords": [
+ "Framex"
+ ],
+ "author": "Prodigital Framex",
+ "license": "ISC",
+ "scripts": {
+ "build:css": "tailwindcss -i ./public/css/src/style.css -o ./public/css/style.css --minify",
+ "watch:css": "tailwindcss -i ./public/css/src/style.css -o ./public/css/style.css --watch"
+ },
+ "devDependencies": {
+ "@tailwindcss/cli": "^4.3.0",
+ "tailwindcss": "^4.3.0"
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions"
+ ]
+}
diff --git a/public/.htaccess b/public/.htaccess
new file mode 100644
index 0000000..bc530cb
--- /dev/null
+++ b/public/.htaccess
@@ -0,0 +1,8 @@
+Options +FollowSymLinks
+RewriteEngine On
+
+# Ignore existing directories (!-d) and files (!-f)
+RewriteCond %{SCRIPT_FILENAME} !-d
+RewriteCond %{SCRIPT_FILENAME} !-f
+
+RewriteRule ^.*$ ./index.php
diff --git a/public/css/responsive.css b/public/css/responsive.css
new file mode 100644
index 0000000..65525ad
--- /dev/null
+++ b/public/css/responsive.css
@@ -0,0 +1,2 @@
+/* Tailwind responsive utilities are included automatically via the main styles.
+ Add any extra responsive overrides here if needed. */
diff --git a/public/css/src/responsive.css b/public/css/src/responsive.css
new file mode 100644
index 0000000..65525ad
--- /dev/null
+++ b/public/css/src/responsive.css
@@ -0,0 +1,2 @@
+/* Tailwind responsive utilities are included automatically via the main styles.
+ Add any extra responsive overrides here if needed. */
diff --git a/public/css/src/style.css b/public/css/src/style.css
new file mode 100644
index 0000000..00ea34d
--- /dev/null
+++ b/public/css/src/style.css
@@ -0,0 +1,449 @@
+@import url("https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,100..900&display=swap");
+@import "tailwindcss";
+
+@custom-variant dark (&:where(.dark, .dark *));
+
+@source "../../../templates/**/*.php";
+@source "../../../app/**/*.php";
+@source "../../../app/**/*.md";
+
+@theme {
+ --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
+ "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+}
+
+@layer base {
+ html {
+ color-scheme: light;
+ }
+
+ html.dark {
+ color-scheme: dark;
+ }
+
+ body {
+ @apply flex min-h-screen flex-col bg-slate-50 text-slate-950 antialiased transition-colors duration-300 dark:bg-slate-950 dark:text-slate-100;
+ font-feature-settings:
+ "cv02",
+ "cv03",
+ "cv04",
+ "cv11";
+ }
+
+ ::selection {
+ @apply bg-blue-600 text-white;
+ }
+
+ a {
+ @apply transition-colors;
+ }
+
+ :focus-visible {
+ @apply outline-2 outline-offset-2 outline-blue-500;
+ }
+
+ .wrap {
+ @apply grow shrink-0 basis-auto;
+ }
+
+ .contain, .band {
+ @apply mx-auto w-full max-w-6xl px-4 sm:px-6 lg:px-8;
+ }
+
+ .contain-narrow, .band-narrow {
+ @apply mx-auto w-full max-w-3xl px-4 sm:px-6 lg:px-8;
+ }
+
+ .contain-wide, .band-wide {
+ @apply mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8;
+ }
+}
+
+@layer components {
+ footer {
+ @apply grow-0;
+ }
+
+ .wrp {
+ @apply mx-auto w-full max-w-6xl px-4 sm:px-6 lg:px-8;
+ }
+
+ .section, section {
+ @apply py-10 md:py-16;
+ }
+
+ .section-tight {
+ @apply py-10 md:py-14;
+ }
+
+ .text-gradient {@apply bg-linear-to-r from-indigo-400 to-pink-600 bg-clip-text text-transparent}
+
+ .eyebrow {
+ @apply font-semibold tracking-widest text-blue-600 dark:text-blue-400;
+ }
+
+ .btn {
+ @apply inline-flex min-h-11 items-center justify-center gap-2 rounded-lg px-5 py-2.5 text-sm font-semibold leading-none transition duration-200 focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none disabled:opacity-50;
+ }
+
+ .btn-primary {
+ @apply bg-blue-600 text-white shadow-sm shadow-blue-600/25 hover:bg-blue-500 focus-visible:outline-blue-500 dark:bg-blue-500 dark:hover:bg-blue-400;
+ }
+
+ .btn-secondary {
+ @apply border border-slate-200 bg-white text-slate-900 hover:border-slate-300 hover:bg-slate-100 focus-visible:outline-blue-500 dark:border-slate-800 dark:bg-slate-900 dark:text-slate-100 dark:hover:border-slate-700 dark:hover:bg-slate-800;
+ }
+
+ .btn-ghost {
+ @apply text-slate-700 hover:bg-slate-100 hover:text-slate-950 focus-visible:outline-blue-500 dark:text-slate-300 dark:hover:bg-slate-900 dark:hover:text-white;
+ }
+
+ .card {
+ @apply rounded-lg border border-slate-200 bg-white p-6 shadow-sm shadow-slate-950/5 transition-colors dark:border-slate-800 dark:bg-slate-900/80 dark:shadow-black/20;
+ }
+
+ .bg-pre-blue {
+ @apply bg-blue-50 text-blue-950 dark:bg-blue-950/35 dark:text-blue-50;
+ }
+
+ .bg-pre-emerald {
+ @apply bg-emerald-50 text-emerald-950 dark:bg-emerald-950/35 dark:text-emerald-50;
+ }
+
+ .bg-pre-amber {
+ @apply bg-amber-50 text-amber-950 dark:bg-amber-950/35 dark:text-amber-50;
+ }
+
+ .bg-pre-rose {
+ @apply bg-rose-50 text-rose-950 dark:bg-rose-950/35 dark:text-rose-50;
+ }
+
+ .nav-link {
+ @apply rounded-md px-3 py-2 text-sm font-medium text-slate-700 hover:bg-slate-100 hover:text-slate-950 dark:text-slate-300 dark:hover:bg-slate-900 dark:hover:text-white;
+ }
+
+ .prose-shell {
+ @apply mx-auto max-w-4xl px-4 py-16 sm:px-6 lg:px-8;
+ }
+
+ .prose {
+ color: #475569;
+ line-height: 1.75;
+ }
+
+ .dark .prose {
+ color: #94a3b8;
+ }
+
+ .prose > * + * {
+ margin-top: 1.25em;
+ }
+
+ .prose h1,
+ .prose h2,
+ .prose h3,
+ .prose h4,
+ .prose h5,
+ .prose h6 {
+ color: #0f172a;
+ font-weight: 700;
+ line-height: 1.25;
+ }
+
+ .dark .prose h1,
+ .dark .prose h2,
+ .dark .prose h3,
+ .dark .prose h4,
+ .dark .prose h5,
+ .dark .prose h6 {
+ color: #f8fafc;
+ }
+
+ .prose h1 {
+ font-size: 2.25rem;
+ margin-top: 0;
+ margin-bottom: 0.5em;
+ }
+
+ .prose h2 {
+ font-size: 1.75rem;
+ margin-top: 2em;
+ margin-bottom: 0.75em;
+ padding-bottom: 0.4em;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
+ }
+
+ .dark .prose h2 {
+ border-bottom-color: rgba(255, 255, 255, 0.06);
+ }
+
+ .prose h3 {
+ font-size: 1.375rem;
+ margin-top: 1.75em;
+ margin-bottom: 0.6em;
+ }
+
+ .prose h4 {
+ font-size: 1.125rem;
+ margin-top: 1.5em;
+ margin-bottom: 0.5em;
+ }
+
+ .prose h5,
+ .prose h6 {
+ font-size: 1rem;
+ margin-top: 1.5em;
+ margin-bottom: 0.5em;
+ color: #334155;
+ }
+
+ .dark .prose h5,
+ .dark .prose h6 {
+ color: #cbd5e1;
+ }
+
+ .prose p {
+ margin-top: 1.25em;
+ margin-bottom: 1.25em;
+ }
+
+ .prose a {
+ color: #2563eb;
+ text-decoration: none;
+ font-weight: 500;
+ transition: color 0.15s ease;
+ }
+
+ .dark .prose a {
+ color: #60a5fa;
+ }
+
+ .prose a:hover {
+ color: #1d4ed8;
+ text-decoration: underline;
+ }
+
+ .dark .prose a:hover {
+ color: #93c5fd;
+ }
+
+ .prose strong,
+ .prose b {
+ color: #0f172a;
+ font-weight: 600;
+ }
+
+ .dark .prose strong,
+ .dark .prose b {
+ color: #f1f5f9;
+ }
+
+ .prose em,
+ .prose i {
+ color: #334155;
+ }
+
+ .dark .prose em,
+ .dark .prose i {
+ color: #cbd5e1;
+ }
+
+ .prose ul,
+ .prose ol {
+ margin-top: 1.25em;
+ margin-bottom: 1.25em;
+ padding-left: 1.625em;
+ }
+
+ .prose ul {
+ list-style-type: disc;
+ }
+
+ .prose ol {
+ list-style-type: decimal;
+ }
+
+ .prose ul > li,
+ .prose ol > li {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ padding-left: 0.375em;
+ }
+
+ .prose ul > li::marker,
+ .prose ol > li::marker {
+ color: #2563eb;
+ }
+
+ .dark .prose ul > li::marker,
+ .dark .prose ol > li::marker {
+ color: #3b82f6;
+ }
+
+ .prose ul ul,
+ .prose ul ol,
+ .prose ol ul,
+ .prose ol ol {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ }
+
+ .prose pre {
+ background-color: #f1f5f9;
+ border: 1px solid rgba(0, 0, 0, 0.08);
+ border-radius: 0.5rem;
+ padding: 1.25em;
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+ overflow-x: auto;
+ font-size: 0.875em;
+ line-height: 1.7;
+ }
+
+ .dark .prose pre {
+ background-color: #141f38;
+ border-color: rgba(255, 255, 255, 0.06);
+ }
+
+ .prose pre code {
+ background: none;
+ border: none;
+ padding: 0;
+ font-size: inherit;
+ color: #334155;
+ font-family:
+ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
+ "Courier New", monospace;
+ }
+
+ .dark .prose pre code {
+ color: #e2e8f0;
+ }
+
+ .prose code {
+ background-color: rgba(0, 0, 0, 0.05);
+ border: 1px solid rgba(0, 0, 0, 0.06);
+ border-radius: 0.375rem;
+ padding: 0.2em 0.4em;
+ font-size: 0.875em;
+ color: #1d4ed8;
+ font-family:
+ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
+ "Courier New", monospace;
+ }
+
+ .dark .prose code {
+ background-color: rgba(255, 255, 255, 0.06);
+ border-color: rgba(255, 255, 255, 0.06);
+ color: #93c5fd;
+ }
+
+ .prose blockquote {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+ padding-left: 1.25em;
+ border-left: 3px solid #2563eb;
+ font-style: italic;
+ color: #475569;
+ }
+
+ .dark .prose blockquote {
+ border-left-color: #3b82f6;
+ color: #cbd5e1;
+ }
+
+ .prose blockquote p:first-of-type {
+ margin-top: 0;
+ }
+
+ .prose blockquote p:last-of-type {
+ margin-bottom: 0;
+ }
+
+ .prose table {
+ width: 100%;
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+ border-collapse: collapse;
+ font-size: 0.875em;
+ line-height: 1.5;
+ }
+
+ .prose thead {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.15);
+ }
+
+ .dark .prose thead {
+ border-bottom-color: rgba(255, 255, 255, 0.1);
+ }
+
+ .prose th {
+ padding: 0.75em 1em;
+ text-align: left;
+ font-weight: 600;
+ color: #0f172a;
+ }
+
+ .dark .prose th {
+ color: #f1f5f9;
+ }
+
+ .prose td {
+ padding: 0.625em 1em;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.06);
+ vertical-align: top;
+ }
+
+ .dark .prose td {
+ border-bottom-color: rgba(255, 255, 255, 0.05);
+ }
+
+ .prose tbody tr:nth-child(even) {
+ background-color: rgba(0, 0, 0, 0.02);
+ }
+
+ .dark .prose tbody tr:nth-child(even) {
+ background-color: rgba(255, 255, 255, 0.02);
+ }
+
+ .prose tbody tr:hover {
+ background-color: rgba(0, 0, 0, 0.03);
+ }
+
+ .dark .prose tbody tr:hover {
+ background-color: rgba(255, 255, 255, 0.04);
+ }
+
+ .prose img {
+ border-radius: 0.5rem;
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+ max-width: 100%;
+ height: auto;
+ display: block;
+ box-shadow:
+ 0 4px 6px -1px rgba(0, 0, 0, 0.1),
+ 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+ }
+
+ .prose hr {
+ margin-top: 2.5em;
+ margin-bottom: 2.5em;
+ border: 0;
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ }
+
+ .dark .prose hr {
+ border-top-color: rgba(255, 255, 255, 0.08);
+ }
+
+ .prose li > p,
+ .prose blockquote > p {
+ margin-top: 0.75em;
+ margin-bottom: 0.75em;
+ }
+}
+
+@layer utilities {
+
+}
diff --git a/public/css/src/vendors.css b/public/css/src/vendors.css
new file mode 100644
index 0000000..d48b2cb
--- /dev/null
+++ b/public/css/src/vendors.css
@@ -0,0 +1,2 @@
+/* Vendor styles — add third-party CSS here or @import them.
+ Tailwind is NOT imported here by default. */
diff --git a/public/css/style.css b/public/css/style.css
new file mode 100644
index 0000000..e715f81
--- /dev/null
+++ b/public/css/style.css
@@ -0,0 +1,2787 @@
+/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */
+@import url("https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,100..900&display=swap");
+@layer properties;
+@layer theme, base, components, utilities;
+@layer theme {
+ :root, :host {
+ --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
+ "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
+ "Courier New", monospace;
+ --color-amber-50: oklch(98.7% 0.022 95.277);
+ --color-amber-100: oklch(96.2% 0.059 95.617);
+ --color-amber-200: oklch(92.4% 0.12 95.746);
+ --color-amber-400: oklch(82.8% 0.189 84.429);
+ --color-amber-950: oklch(27.9% 0.077 45.635);
+ --color-emerald-50: oklch(97.9% 0.021 166.113);
+ --color-emerald-300: oklch(84.5% 0.143 164.978);
+ --color-emerald-400: oklch(76.5% 0.177 163.223);
+ --color-emerald-950: oklch(26.2% 0.051 172.552);
+ --color-blue-50: oklch(97% 0.014 254.604);
+ --color-blue-300: oklch(80.9% 0.105 251.813);
+ --color-blue-400: oklch(70.7% 0.165 254.624);
+ --color-blue-500: oklch(62.3% 0.214 259.815);
+ --color-blue-600: oklch(54.6% 0.245 262.881);
+ --color-blue-950: oklch(28.2% 0.091 267.935);
+ --color-indigo-400: oklch(67.3% 0.182 276.935);
+ --color-indigo-600: oklch(51.1% 0.262 276.966);
+ --color-violet-600: oklch(54.1% 0.281 293.009);
+ --color-pink-600: oklch(59.2% 0.249 0.584);
+ --color-rose-50: oklch(96.9% 0.015 12.422);
+ --color-rose-300: oklch(81% 0.117 11.638);
+ --color-rose-400: oklch(71.2% 0.194 13.428);
+ --color-rose-950: oklch(27.1% 0.105 12.094);
+ --color-slate-50: oklch(98.4% 0.003 247.858);
+ --color-slate-100: oklch(96.8% 0.007 247.896);
+ --color-slate-200: oklch(92.9% 0.013 255.508);
+ --color-slate-300: oklch(86.9% 0.022 252.894);
+ --color-slate-400: oklch(70.4% 0.04 256.788);
+ --color-slate-500: oklch(55.4% 0.046 257.417);
+ --color-slate-600: oklch(44.6% 0.043 257.281);
+ --color-slate-700: oklch(37.2% 0.044 257.287);
+ --color-slate-800: oklch(27.9% 0.041 260.031);
+ --color-slate-900: oklch(20.8% 0.042 265.755);
+ --color-slate-950: oklch(12.9% 0.042 264.695);
+ --color-gray-50: oklch(98.5% 0.002 247.839);
+ --color-gray-100: oklch(96.7% 0.003 264.542);
+ --color-gray-300: oklch(87.2% 0.01 258.338);
+ --color-gray-400: oklch(70.7% 0.022 261.325);
+ --color-gray-500: oklch(55.1% 0.027 264.364);
+ --color-gray-700: oklch(37.3% 0.034 259.733);
+ --color-gray-900: oklch(21% 0.034 264.665);
+ --color-black: #000;
+ --color-white: #fff;
+ --spacing: 0.25rem;
+ --container-md: 28rem;
+ --container-lg: 32rem;
+ --container-xl: 36rem;
+ --container-2xl: 42rem;
+ --container-3xl: 48rem;
+ --container-4xl: 56rem;
+ --container-6xl: 72rem;
+ --container-7xl: 80rem;
+ --text-xs: 0.75rem;
+ --text-xs--line-height: calc(1 / 0.75);
+ --text-sm: 0.875rem;
+ --text-sm--line-height: calc(1.25 / 0.875);
+ --text-base: 1rem;
+ --text-base--line-height: calc(1.5 / 1);
+ --text-lg: 1.125rem;
+ --text-lg--line-height: calc(1.75 / 1.125);
+ --text-xl: 1.25rem;
+ --text-xl--line-height: calc(1.75 / 1.25);
+ --text-2xl: 1.5rem;
+ --text-2xl--line-height: calc(2 / 1.5);
+ --text-3xl: 1.875rem;
+ --text-3xl--line-height: calc(2.25 / 1.875);
+ --text-4xl: 2.25rem;
+ --text-4xl--line-height: calc(2.5 / 2.25);
+ --text-5xl: 3rem;
+ --text-5xl--line-height: 1;
+ --text-6xl: 3.75rem;
+ --text-6xl--line-height: 1;
+ --text-7xl: 4.5rem;
+ --text-7xl--line-height: 1;
+ --text-9xl: 8rem;
+ --text-9xl--line-height: 1;
+ --font-weight-medium: 500;
+ --font-weight-semibold: 600;
+ --font-weight-bold: 700;
+ --font-weight-extrabold: 800;
+ --font-weight-black: 900;
+ --tracking-tighter: -0.05em;
+ --tracking-tight: -0.025em;
+ --tracking-widest: 0.1em;
+ --leading-tight: 1.25;
+ --leading-relaxed: 1.625;
+ --radius-md: 0.375rem;
+ --radius-lg: 0.5rem;
+ --radius-xl: 0.75rem;
+ --radius-2xl: 1rem;
+ --blur-xl: 24px;
+ --default-transition-duration: 150ms;
+ --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ --default-font-family: var(--font-sans);
+ --default-mono-font-family: var(--font-mono);
+ }
+}
+@layer base {
+ *, ::after, ::before, ::backdrop, ::file-selector-button {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ border: 0 solid;
+ }
+ html, :host {
+ line-height: 1.5;
+ -webkit-text-size-adjust: 100%;
+ tab-size: 4;
+ font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");
+ font-feature-settings: var(--default-font-feature-settings, normal);
+ font-variation-settings: var(--default-font-variation-settings, normal);
+ -webkit-tap-highlight-color: transparent;
+ }
+ hr {
+ height: 0;
+ color: inherit;
+ border-top-width: 1px;
+ }
+ abbr:where([title]) {
+ -webkit-text-decoration: underline dotted;
+ text-decoration: underline dotted;
+ }
+ h1, h2, h3, h4, h5, h6 {
+ font-size: inherit;
+ font-weight: inherit;
+ }
+ a {
+ color: inherit;
+ -webkit-text-decoration: inherit;
+ text-decoration: inherit;
+ }
+ b, strong {
+ font-weight: bolder;
+ }
+ code, kbd, samp, pre {
+ font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);
+ font-feature-settings: var(--default-mono-font-feature-settings, normal);
+ font-variation-settings: var(--default-mono-font-variation-settings, normal);
+ font-size: 1em;
+ }
+ small {
+ font-size: 80%;
+ }
+ sub, sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+ }
+ sub {
+ bottom: -0.25em;
+ }
+ sup {
+ top: -0.5em;
+ }
+ table {
+ text-indent: 0;
+ border-color: inherit;
+ border-collapse: collapse;
+ }
+ :-moz-focusring {
+ outline: auto;
+ }
+ progress {
+ vertical-align: baseline;
+ }
+ summary {
+ display: list-item;
+ }
+ ol, ul, menu {
+ list-style: none;
+ }
+ img, svg, video, canvas, audio, iframe, embed, object {
+ display: block;
+ vertical-align: middle;
+ }
+ img, video {
+ max-width: 100%;
+ height: auto;
+ }
+ button, input, select, optgroup, textarea, ::file-selector-button {
+ font: inherit;
+ font-feature-settings: inherit;
+ font-variation-settings: inherit;
+ letter-spacing: inherit;
+ color: inherit;
+ border-radius: 0;
+ background-color: transparent;
+ opacity: 1;
+ }
+ :where(select:is([multiple], [size])) optgroup {
+ font-weight: bolder;
+ }
+ :where(select:is([multiple], [size])) optgroup option {
+ padding-inline-start: 20px;
+ }
+ ::file-selector-button {
+ margin-inline-end: 4px;
+ }
+ ::placeholder {
+ opacity: 1;
+ }
+ @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {
+ ::placeholder {
+ color: currentcolor;
+ @supports (color: color-mix(in lab, red, red)) {
+ color: color-mix(in oklab, currentcolor 50%, transparent);
+ }
+ }
+ }
+ textarea {
+ resize: vertical;
+ }
+ ::-webkit-search-decoration {
+ -webkit-appearance: none;
+ }
+ ::-webkit-date-and-time-value {
+ min-height: 1lh;
+ text-align: inherit;
+ }
+ ::-webkit-datetime-edit {
+ display: inline-flex;
+ }
+ ::-webkit-datetime-edit-fields-wrapper {
+ padding: 0;
+ }
+ ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {
+ padding-block: 0;
+ }
+ ::-webkit-calendar-picker-indicator {
+ line-height: 1;
+ }
+ :-moz-ui-invalid {
+ box-shadow: none;
+ }
+ button, input:where([type="button"], [type="reset"], [type="submit"]), ::file-selector-button {
+ appearance: button;
+ }
+ ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {
+ height: auto;
+ }
+ [hidden]:where(:not([hidden="until-found"])) {
+ display: none !important;
+ }
+}
+@layer utilities {
+ .absolute {
+ position: absolute;
+ }
+ .relative {
+ position: relative;
+ }
+ .static {
+ position: static;
+ }
+ .sticky {
+ position: sticky;
+ }
+ .inset-0 {
+ inset: calc(var(--spacing) * 0);
+ }
+ .top-0 {
+ top: calc(var(--spacing) * 0);
+ }
+ .top-1 {
+ top: calc(var(--spacing) * 1);
+ }
+ .top-1\/2 {
+ top: calc(1 / 2 * 100%);
+ }
+ .top-1\/3 {
+ top: calc(1 / 3 * 100%);
+ }
+ .right-1 {
+ right: calc(var(--spacing) * 1);
+ }
+ .right-1\/4 {
+ right: calc(1 / 4 * 100%);
+ }
+ .right-5 {
+ right: calc(var(--spacing) * 5);
+ }
+ .bottom-5 {
+ bottom: calc(var(--spacing) * 5);
+ }
+ .left-1 {
+ left: calc(var(--spacing) * 1);
+ }
+ .left-1\/2 {
+ left: calc(1 / 2 * 100%);
+ }
+ .isolate {
+ isolation: isolate;
+ }
+ .-z-10 {
+ z-index: calc(10 * -1);
+ }
+ .z-50 {
+ z-index: 50;
+ }
+ .m-4 {
+ margin: calc(var(--spacing) * 4);
+ }
+ .mx-2 {
+ margin-inline: calc(var(--spacing) * 2);
+ }
+ .mx-auto {
+ margin-inline: auto;
+ }
+ .my-10 {
+ margin-block: calc(var(--spacing) * 10);
+ }
+ .ms-1 {
+ margin-inline-start: calc(var(--spacing) * 1);
+ }
+ .ms-2 {
+ margin-inline-start: calc(var(--spacing) * 2);
+ }
+ .mt-1 {
+ margin-top: calc(var(--spacing) * 1);
+ }
+ .mt-2 {
+ margin-top: calc(var(--spacing) * 2);
+ }
+ .mt-3 {
+ margin-top: calc(var(--spacing) * 3);
+ }
+ .mt-4 {
+ margin-top: calc(var(--spacing) * 4);
+ }
+ .mt-5 {
+ margin-top: calc(var(--spacing) * 5);
+ }
+ .mt-6 {
+ margin-top: calc(var(--spacing) * 6);
+ }
+ .mt-8 {
+ margin-top: calc(var(--spacing) * 8);
+ }
+ .mt-10 {
+ margin-top: calc(var(--spacing) * 10);
+ }
+ .mt-12 {
+ margin-top: calc(var(--spacing) * 12);
+ }
+ .mr-2 {
+ margin-right: calc(var(--spacing) * 2);
+ }
+ .mb-2 {
+ margin-bottom: calc(var(--spacing) * 2);
+ }
+ .mb-4 {
+ margin-bottom: calc(var(--spacing) * 4);
+ }
+ .mb-5 {
+ margin-bottom: calc(var(--spacing) * 5);
+ }
+ .mb-6 {
+ margin-bottom: calc(var(--spacing) * 6);
+ }
+ .mb-8 {
+ margin-bottom: calc(var(--spacing) * 8);
+ }
+ .mb-12 {
+ margin-bottom: calc(var(--spacing) * 12);
+ }
+ .mb-16 {
+ margin-bottom: calc(var(--spacing) * 16);
+ }
+ .block {
+ display: block;
+ }
+ .flex {
+ display: flex;
+ }
+ .grid {
+ display: grid;
+ }
+ .hidden {
+ display: none;
+ }
+ .inline {
+ display: inline;
+ }
+ .inline-block {
+ display: inline-block;
+ }
+ .inline-flex {
+ display: inline-flex;
+ }
+ .table {
+ display: table;
+ }
+ .size-3 {
+ width: calc(var(--spacing) * 3);
+ height: calc(var(--spacing) * 3);
+ }
+ .size-5 {
+ width: calc(var(--spacing) * 5);
+ height: calc(var(--spacing) * 5);
+ }
+ .size-6 {
+ width: calc(var(--spacing) * 6);
+ height: calc(var(--spacing) * 6);
+ }
+ .size-9 {
+ width: calc(var(--spacing) * 9);
+ height: calc(var(--spacing) * 9);
+ }
+ .size-11 {
+ width: calc(var(--spacing) * 11);
+ height: calc(var(--spacing) * 11);
+ }
+ .h-4 {
+ height: calc(var(--spacing) * 4);
+ }
+ .h-14 {
+ height: calc(var(--spacing) * 14);
+ }
+ .h-60 {
+ height: calc(var(--spacing) * 60);
+ }
+ .h-72 {
+ height: calc(var(--spacing) * 72);
+ }
+ .h-80 {
+ height: calc(var(--spacing) * 80);
+ }
+ .h-\[300px\] {
+ height: 300px;
+ }
+ .h-\[600px\] {
+ height: 600px;
+ }
+ .h-full {
+ height: 100%;
+ }
+ .min-h-16 {
+ min-height: calc(var(--spacing) * 16);
+ }
+ .min-h-72 {
+ min-height: calc(var(--spacing) * 72);
+ }
+ .min-h-\[80vh\] {
+ min-height: 80vh;
+ }
+ .w-4 {
+ width: calc(var(--spacing) * 4);
+ }
+ .w-14 {
+ width: calc(var(--spacing) * 14);
+ }
+ .w-\[300px\] {
+ width: 300px;
+ }
+ .w-\[600px\] {
+ width: 600px;
+ }
+ .w-full {
+ width: 100%;
+ }
+ .w-screen {
+ width: 100vw;
+ }
+ .max-w-2xl {
+ max-width: var(--container-2xl);
+ }
+ .max-w-3xl {
+ max-width: var(--container-3xl);
+ }
+ .max-w-4xl {
+ max-width: var(--container-4xl);
+ }
+ .max-w-6xl {
+ max-width: var(--container-6xl);
+ }
+ .max-w-7xl {
+ max-width: var(--container-7xl);
+ }
+ .max-w-40 {
+ max-width: calc(var(--spacing) * 40);
+ }
+ .max-w-lg {
+ max-width: var(--container-lg);
+ }
+ .max-w-md {
+ max-width: var(--container-md);
+ }
+ .max-w-prose {
+ max-width: 65ch;
+ }
+ .max-w-xl {
+ max-width: var(--container-xl);
+ }
+ .flex-shrink {
+ flex-shrink: 1;
+ }
+ .shrink-0 {
+ flex-shrink: 0;
+ }
+ .flex-grow {
+ flex-grow: 1;
+ }
+ .grow {
+ flex-grow: 1;
+ }
+ .border-collapse {
+ border-collapse: collapse;
+ }
+ .-translate-x-1 {
+ --tw-translate-x: calc(var(--spacing) * -1);
+ translate: var(--tw-translate-x) var(--tw-translate-y);
+ }
+ .-translate-x-1\/2 {
+ --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);
+ translate: var(--tw-translate-x) var(--tw-translate-y);
+ }
+ .-translate-y-1 {
+ --tw-translate-y: calc(var(--spacing) * -1);
+ translate: var(--tw-translate-x) var(--tw-translate-y);
+ }
+ .-translate-y-1\/2 {
+ --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);
+ translate: var(--tw-translate-x) var(--tw-translate-y);
+ }
+ .cursor-pointer {
+ cursor: pointer;
+ }
+ .resize {
+ resize: both;
+ }
+ .grid-cols-1 {
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+ }
+ .flex-col {
+ flex-direction: column;
+ }
+ .flex-wrap {
+ flex-wrap: wrap;
+ }
+ .place-items-center {
+ place-items: center;
+ }
+ .items-center {
+ align-items: center;
+ }
+ .items-start {
+ align-items: flex-start;
+ }
+ .justify-between {
+ justify-content: space-between;
+ }
+ .justify-center {
+ justify-content: center;
+ }
+ .gap-1 {
+ gap: calc(var(--spacing) * 1);
+ }
+ .gap-1\.5 {
+ gap: calc(var(--spacing) * 1.5);
+ }
+ .gap-2 {
+ gap: calc(var(--spacing) * 2);
+ }
+ .gap-3 {
+ gap: calc(var(--spacing) * 3);
+ }
+ .gap-4 {
+ gap: calc(var(--spacing) * 4);
+ }
+ .gap-5 {
+ gap: calc(var(--spacing) * 5);
+ }
+ .gap-6 {
+ gap: calc(var(--spacing) * 6);
+ }
+ .gap-8 {
+ gap: calc(var(--spacing) * 8);
+ }
+ .gap-10 {
+ gap: calc(var(--spacing) * 10);
+ }
+ .gap-12 {
+ gap: calc(var(--spacing) * 12);
+ }
+ .space-y-4 {
+ :where(& > :not(:last-child)) {
+ --tw-space-y-reverse: 0;
+ margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));
+ margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)));
+ }
+ }
+ .space-y-5 {
+ :where(& > :not(:last-child)) {
+ --tw-space-y-reverse: 0;
+ margin-block-start: calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));
+ margin-block-end: calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)));
+ }
+ }
+ .overflow-hidden {
+ overflow: hidden;
+ }
+ .scroll-smooth {
+ scroll-behavior: smooth;
+ }
+ .rounded {
+ border-radius: 0.25rem;
+ }
+ .rounded-2xl {
+ border-radius: var(--radius-2xl);
+ }
+ .rounded-full {
+ border-radius: calc(infinity * 1px);
+ }
+ .rounded-lg {
+ border-radius: var(--radius-lg);
+ }
+ .rounded-md {
+ border-radius: var(--radius-md);
+ }
+ .rounded-xl {
+ border-radius: var(--radius-xl);
+ }
+ .rounded-t-lg {
+ border-top-left-radius: var(--radius-lg);
+ border-top-right-radius: var(--radius-lg);
+ }
+ .border {
+ border-style: var(--tw-border-style);
+ border-width: 1px;
+ }
+ .border-y {
+ border-block-style: var(--tw-border-style);
+ border-block-width: 1px;
+ }
+ .border-t {
+ border-top-style: var(--tw-border-style);
+ border-top-width: 1px;
+ }
+ .border-b {
+ border-bottom-style: var(--tw-border-style);
+ border-bottom-width: 1px;
+ }
+ .border-solid {
+ --tw-border-style: solid;
+ border-style: solid;
+ }
+ .border-black {
+ border-color: var(--color-black);
+ }
+ .border-black\/5 {
+ border-color: color-mix(in srgb, #000 5%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ border-color: color-mix(in oklab, var(--color-black) 5%, transparent);
+ }
+ }
+ .border-black\/10 {
+ border-color: color-mix(in srgb, #000 10%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ border-color: color-mix(in oklab, var(--color-black) 10%, transparent);
+ }
+ }
+ .border-gray-100 {
+ border-color: var(--color-gray-100);
+ }
+ .border-gray-300 {
+ border-color: var(--color-gray-300);
+ }
+ .border-slate-200 {
+ border-color: var(--color-slate-200);
+ }
+ .border-slate-200\/80 {
+ border-color: color-mix(in srgb, oklch(92.9% 0.013 255.508) 80%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ border-color: color-mix(in oklab, var(--color-slate-200) 80%, transparent);
+ }
+ }
+ .bg-amber-100 {
+ background-color: var(--color-amber-100);
+ }
+ .bg-amber-400 {
+ background-color: var(--color-amber-400);
+ }
+ .bg-black {
+ background-color: var(--color-black);
+ }
+ .bg-black\/5 {
+ background-color: color-mix(in srgb, #000 5%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-black) 5%, transparent);
+ }
+ }
+ .bg-black\/\[0\.02\] {
+ background-color: color-mix(in srgb, #000 2%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-black) 2%, transparent);
+ }
+ }
+ .bg-blue-600 {
+ background-color: var(--color-blue-600);
+ }
+ .bg-emerald-400 {
+ background-color: var(--color-emerald-400);
+ }
+ .bg-gray-50 {
+ background-color: var(--color-gray-50);
+ }
+ .bg-gray-100 {
+ background-color: var(--color-gray-100);
+ }
+ .bg-gray-400 {
+ background-color: var(--color-gray-400);
+ }
+ .bg-indigo-600 {
+ background-color: var(--color-indigo-600);
+ }
+ .bg-indigo-600\/10 {
+ background-color: color-mix(in srgb, oklch(51.1% 0.262 276.966) 10%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-indigo-600) 10%, transparent);
+ }
+ }
+ .bg-rose-400 {
+ background-color: var(--color-rose-400);
+ }
+ .bg-slate-50 {
+ background-color: var(--color-slate-50);
+ }
+ .bg-slate-950 {
+ background-color: var(--color-slate-950);
+ }
+ .bg-violet-600 {
+ background-color: var(--color-violet-600);
+ }
+ .bg-violet-600\/10 {
+ background-color: color-mix(in srgb, oklch(54.1% 0.281 293.009) 10%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-violet-600) 10%, transparent);
+ }
+ }
+ .bg-white {
+ background-color: var(--color-white);
+ }
+ .bg-white\/70 {
+ background-color: color-mix(in srgb, #fff 70%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-white) 70%, transparent);
+ }
+ }
+ .bg-white\/85 {
+ background-color: color-mix(in srgb, #fff 85%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-white) 85%, transparent);
+ }
+ }
+ .bg-gradient-to-b {
+ --tw-gradient-position: to bottom in oklab;
+ background-image: linear-gradient(var(--tw-gradient-stops));
+ }
+ .from-white {
+ --tw-gradient-from: var(--color-white);
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
+ }
+ .to-black {
+ --tw-gradient-to: var(--color-black);
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
+ }
+ .to-black\/20 {
+ --tw-gradient-to: color-mix(in srgb, #000 20%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-gradient-to: color-mix(in oklab, var(--color-black) 20%, transparent);
+ }
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
+ }
+ .bg-clip-text {
+ background-clip: text;
+ }
+ .object-cover {
+ object-fit: cover;
+ }
+ .p-0 {
+ padding: calc(var(--spacing) * 0);
+ }
+ .p-2 {
+ padding: calc(var(--spacing) * 2);
+ }
+ .p-4 {
+ padding: calc(var(--spacing) * 4);
+ }
+ .p-5 {
+ padding: calc(var(--spacing) * 5);
+ }
+ .p-6 {
+ padding: calc(var(--spacing) * 6);
+ }
+ .p-8 {
+ padding: calc(var(--spacing) * 8);
+ }
+ .p-10 {
+ padding: calc(var(--spacing) * 10);
+ }
+ .px-0 {
+ padding-inline: calc(var(--spacing) * 0);
+ }
+ .px-2 {
+ padding-inline: calc(var(--spacing) * 2);
+ }
+ .px-2\.5 {
+ padding-inline: calc(var(--spacing) * 2.5);
+ }
+ .px-3 {
+ padding-inline: calc(var(--spacing) * 3);
+ }
+ .px-4 {
+ padding-inline: calc(var(--spacing) * 4);
+ }
+ .px-5 {
+ padding-inline: calc(var(--spacing) * 5);
+ }
+ .px-6 {
+ padding-inline: calc(var(--spacing) * 6);
+ }
+ .px-8 {
+ padding-inline: calc(var(--spacing) * 8);
+ }
+ .py-1 {
+ padding-block: calc(var(--spacing) * 1);
+ }
+ .py-1\.5 {
+ padding-block: calc(var(--spacing) * 1.5);
+ }
+ .py-2 {
+ padding-block: calc(var(--spacing) * 2);
+ }
+ .py-3 {
+ padding-block: calc(var(--spacing) * 3);
+ }
+ .py-3\.5 {
+ padding-block: calc(var(--spacing) * 3.5);
+ }
+ .py-4 {
+ padding-block: calc(var(--spacing) * 4);
+ }
+ .py-5 {
+ padding-block: calc(var(--spacing) * 5);
+ }
+ .py-8 {
+ padding-block: calc(var(--spacing) * 8);
+ }
+ .py-10 {
+ padding-block: calc(var(--spacing) * 10);
+ }
+ .py-12 {
+ padding-block: calc(var(--spacing) * 12);
+ }
+ .py-16 {
+ padding-block: calc(var(--spacing) * 16);
+ }
+ .pt-4 {
+ padding-top: calc(var(--spacing) * 4);
+ }
+ .pb-4 {
+ padding-bottom: calc(var(--spacing) * 4);
+ }
+ .pb-5 {
+ padding-bottom: calc(var(--spacing) * 5);
+ }
+ .pb-8 {
+ padding-bottom: calc(var(--spacing) * 8);
+ }
+ .text-center {
+ text-align: center;
+ }
+ .text-left {
+ text-align: left;
+ }
+ .font-mono {
+ font-family: var(--font-mono);
+ }
+ .text-2xl {
+ font-size: var(--text-2xl);
+ line-height: var(--tw-leading, var(--text-2xl--line-height));
+ }
+ .text-3xl {
+ font-size: var(--text-3xl);
+ line-height: var(--tw-leading, var(--text-3xl--line-height));
+ }
+ .text-4xl {
+ font-size: var(--text-4xl);
+ line-height: var(--tw-leading, var(--text-4xl--line-height));
+ }
+ .text-5xl {
+ font-size: var(--text-5xl);
+ line-height: var(--tw-leading, var(--text-5xl--line-height));
+ }
+ .text-7xl {
+ font-size: var(--text-7xl);
+ line-height: var(--tw-leading, var(--text-7xl--line-height));
+ }
+ .text-9xl {
+ font-size: var(--text-9xl);
+ line-height: var(--tw-leading, var(--text-9xl--line-height));
+ }
+ .text-base {
+ font-size: var(--text-base);
+ line-height: var(--tw-leading, var(--text-base--line-height));
+ }
+ .text-lg {
+ font-size: var(--text-lg);
+ line-height: var(--tw-leading, var(--text-lg--line-height));
+ }
+ .text-sm {
+ font-size: var(--text-sm);
+ line-height: var(--tw-leading, var(--text-sm--line-height));
+ }
+ .text-xl {
+ font-size: var(--text-xl);
+ line-height: var(--tw-leading, var(--text-xl--line-height));
+ }
+ .text-xs {
+ font-size: var(--text-xs);
+ line-height: var(--tw-leading, var(--text-xs--line-height));
+ }
+ .leading-6 {
+ --tw-leading: calc(var(--spacing) * 6);
+ line-height: calc(var(--spacing) * 6);
+ }
+ .leading-7 {
+ --tw-leading: calc(var(--spacing) * 7);
+ line-height: calc(var(--spacing) * 7);
+ }
+ .leading-8 {
+ --tw-leading: calc(var(--spacing) * 8);
+ line-height: calc(var(--spacing) * 8);
+ }
+ .leading-tight {
+ --tw-leading: var(--leading-tight);
+ line-height: var(--leading-tight);
+ }
+ .font-black {
+ --tw-font-weight: var(--font-weight-black);
+ font-weight: var(--font-weight-black);
+ }
+ .font-bold {
+ --tw-font-weight: var(--font-weight-bold);
+ font-weight: var(--font-weight-bold);
+ }
+ .font-extrabold {
+ --tw-font-weight: var(--font-weight-extrabold);
+ font-weight: var(--font-weight-extrabold);
+ }
+ .font-medium {
+ --tw-font-weight: var(--font-weight-medium);
+ font-weight: var(--font-weight-medium);
+ }
+ .font-semibold {
+ --tw-font-weight: var(--font-weight-semibold);
+ font-weight: var(--font-weight-semibold);
+ }
+ .tracking-tight {
+ --tw-tracking: var(--tracking-tight);
+ letter-spacing: var(--tracking-tight);
+ }
+ .tracking-tighter {
+ --tw-tracking: var(--tracking-tighter);
+ letter-spacing: var(--tracking-tighter);
+ }
+ .tracking-widest {
+ --tw-tracking: var(--tracking-widest);
+ letter-spacing: var(--tracking-widest);
+ }
+ .text-pretty {
+ text-wrap: pretty;
+ }
+ .text-wrap {
+ text-wrap: wrap;
+ }
+ .text-amber-200 {
+ color: var(--color-amber-200);
+ }
+ .text-black {
+ color: var(--color-black);
+ }
+ .text-black\/5 {
+ color: color-mix(in srgb, #000 5%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ color: color-mix(in oklab, var(--color-black) 5%, transparent);
+ }
+ }
+ .text-blue-300 {
+ color: var(--color-blue-300);
+ }
+ .text-blue-600 {
+ color: var(--color-blue-600);
+ }
+ .text-current {
+ color: currentcolor;
+ }
+ .text-emerald-300 {
+ color: var(--color-emerald-300);
+ }
+ .text-gray-500 {
+ color: var(--color-gray-500);
+ }
+ .text-gray-700 {
+ color: var(--color-gray-700);
+ }
+ .text-gray-900 {
+ color: var(--color-gray-900);
+ }
+ .text-indigo-400 {
+ color: var(--color-indigo-400);
+ }
+ .text-indigo-600 {
+ color: var(--color-indigo-600);
+ }
+ .text-rose-300 {
+ color: var(--color-rose-300);
+ }
+ .text-slate-200 {
+ color: var(--color-slate-200);
+ }
+ .text-slate-500 {
+ color: var(--color-slate-500);
+ }
+ .text-slate-600 {
+ color: var(--color-slate-600);
+ }
+ .text-slate-700 {
+ color: var(--color-slate-700);
+ }
+ .text-slate-900 {
+ color: var(--color-slate-900);
+ }
+ .text-slate-950 {
+ color: var(--color-slate-950);
+ }
+ .text-transparent {
+ color: transparent;
+ }
+ .text-white {
+ color: var(--color-white);
+ }
+ .uppercase {
+ text-transform: uppercase;
+ }
+ .underline {
+ text-decoration-line: underline;
+ }
+ .antialiased {
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+ .opacity-60 {
+ opacity: 60%;
+ }
+ .opacity-70 {
+ opacity: 70%;
+ }
+ .opacity-80 {
+ opacity: 80%;
+ }
+ .shadow {
+ --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
+ }
+ .shadow-2xl {
+ --tw-shadow: 0 25px 50px -12px var(--tw-shadow-color, rgb(0 0 0 / 0.25));
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
+ }
+ .shadow-lg {
+ --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
+ }
+ .shadow-sm {
+ --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
+ }
+ .shadow-xl {
+ --tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
+ }
+ .ring-1 {
+ --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
+ }
+ .shadow-black {
+ --tw-shadow-color: #000;
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-shadow-color: color-mix(in oklab, var(--color-black) var(--tw-shadow-alpha), transparent);
+ }
+ }
+ .shadow-black\/10 {
+ --tw-shadow-color: color-mix(in srgb, #000 10%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-black) 10%, transparent) var(--tw-shadow-alpha), transparent);
+ }
+ }
+ .shadow-blue-600 {
+ --tw-shadow-color: oklch(54.6% 0.245 262.881);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-shadow-color: color-mix(in oklab, var(--color-blue-600) var(--tw-shadow-alpha), transparent);
+ }
+ }
+ .shadow-blue-600\/30 {
+ --tw-shadow-color: color-mix(in srgb, oklch(54.6% 0.245 262.881) 30%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-blue-600) 30%, transparent) var(--tw-shadow-alpha), transparent);
+ }
+ }
+ .shadow-slate-950 {
+ --tw-shadow-color: oklch(12.9% 0.042 264.695);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-shadow-color: color-mix(in oklab, var(--color-slate-950) var(--tw-shadow-alpha), transparent);
+ }
+ }
+ .shadow-slate-950\/10 {
+ --tw-shadow-color: color-mix(in srgb, oklch(12.9% 0.042 264.695) 10%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-slate-950) 10%, transparent) var(--tw-shadow-alpha), transparent);
+ }
+ }
+ .shadow-slate-950\/20 {
+ --tw-shadow-color: color-mix(in srgb, oklch(12.9% 0.042 264.695) 20%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-slate-950) 20%, transparent) var(--tw-shadow-alpha), transparent);
+ }
+ }
+ .ring-black {
+ --tw-ring-color: var(--color-black);
+ }
+ .ring-black\/5 {
+ --tw-ring-color: color-mix(in srgb, #000 5%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-ring-color: color-mix(in oklab, var(--color-black) 5%, transparent);
+ }
+ }
+ .outline {
+ outline-style: var(--tw-outline-style);
+ outline-width: 1px;
+ }
+ .blur-\[80px\] {
+ --tw-blur: blur(80px);
+ filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
+ }
+ .blur-\[120px\] {
+ --tw-blur: blur(120px);
+ filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
+ }
+ .filter {
+ filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
+ }
+ .backdrop-blur-xl {
+ --tw-backdrop-blur: blur(var(--blur-xl));
+ -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
+ backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
+ }
+ .backdrop-filter {
+ -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
+ backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
+ }
+ .transition {
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
+ }
+ .transition-all {
+ transition-property: all;
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
+ }
+ .transition-transform {
+ transition-property: transform, translate, scale, rotate;
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
+ }
+ .duration-300 {
+ --tw-duration: 300ms;
+ transition-duration: 300ms;
+ }
+ .select-none {
+ -webkit-user-select: none;
+ user-select: none;
+ }
+ .\[grid-area\:1\/1\/4\/2\] {
+ grid-area: 1/1/4/2;
+ }
+ .group-open\:-rotate-180 {
+ &:is(:where(.group):is([open], :popover-open, :open) *) {
+ rotate: calc(180deg * -1);
+ }
+ }
+ .group-hover\:text-blue-500 {
+ &:is(:where(.group):hover *) {
+ @media (hover: hover) {
+ color: var(--color-blue-500);
+ }
+ }
+ }
+ .hover\:bg-black\/10 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: color-mix(in srgb, #000 10%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-black) 10%, transparent);
+ }
+ }
+ }
+ }
+ .hover\:bg-slate-100 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-slate-100);
+ }
+ }
+ }
+ .hover\:bg-slate-200 {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-slate-200);
+ }
+ }
+ }
+ .hover\:text-blue-600 {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-blue-600);
+ }
+ }
+ }
+ .sm\:mt-6 {
+ @media (width >= 40rem) {
+ margin-top: calc(var(--spacing) * 6);
+ }
+ }
+ .sm\:grid-cols-2 {
+ @media (width >= 40rem) {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+ }
+ .sm\:flex-row {
+ @media (width >= 40rem) {
+ flex-direction: row;
+ }
+ }
+ .sm\:items-center {
+ @media (width >= 40rem) {
+ align-items: center;
+ }
+ }
+ .sm\:justify-between {
+ @media (width >= 40rem) {
+ justify-content: space-between;
+ }
+ }
+ .sm\:justify-items-stretch {
+ @media (width >= 40rem) {
+ justify-items: stretch;
+ }
+ }
+ .sm\:p-12 {
+ @media (width >= 40rem) {
+ padding: calc(var(--spacing) * 12);
+ }
+ }
+ .sm\:px-6 {
+ @media (width >= 40rem) {
+ padding-inline: calc(var(--spacing) * 6);
+ }
+ }
+ .sm\:py-24 {
+ @media (width >= 40rem) {
+ padding-block: calc(var(--spacing) * 24);
+ }
+ }
+ .sm\:text-left {
+ @media (width >= 40rem) {
+ text-align: left;
+ }
+ }
+ .sm\:text-3xl {
+ @media (width >= 40rem) {
+ font-size: var(--text-3xl);
+ line-height: var(--tw-leading, var(--text-3xl--line-height));
+ }
+ }
+ .sm\:text-4xl {
+ @media (width >= 40rem) {
+ font-size: var(--text-4xl);
+ line-height: var(--tw-leading, var(--text-4xl--line-height));
+ }
+ }
+ .sm\:text-5xl {
+ @media (width >= 40rem) {
+ font-size: var(--text-5xl);
+ line-height: var(--tw-leading, var(--text-5xl--line-height));
+ }
+ }
+ .sm\:text-6xl {
+ @media (width >= 40rem) {
+ font-size: var(--text-6xl);
+ line-height: var(--tw-leading, var(--text-6xl--line-height));
+ }
+ }
+ .sm\:text-9xl {
+ @media (width >= 40rem) {
+ font-size: var(--text-9xl);
+ line-height: var(--tw-leading, var(--text-9xl--line-height));
+ }
+ }
+ .sm\:text-base {
+ @media (width >= 40rem) {
+ font-size: var(--text-base);
+ line-height: var(--tw-leading, var(--text-base--line-height));
+ }
+ }
+ .sm\:text-lg\/relaxed {
+ @media (width >= 40rem) {
+ font-size: var(--text-lg);
+ line-height: var(--leading-relaxed);
+ }
+ }
+ .sm\:text-\[12rem\] {
+ @media (width >= 40rem) {
+ font-size: 12rem;
+ }
+ }
+ .md\:col-span-2 {
+ @media (width >= 48rem) {
+ grid-column: span 2 / span 2;
+ }
+ }
+ .md\:my-20 {
+ @media (width >= 48rem) {
+ margin-block: calc(var(--spacing) * 20);
+ }
+ }
+ .md\:mt-20 {
+ @media (width >= 48rem) {
+ margin-top: calc(var(--spacing) * 20);
+ }
+ }
+ .md\:mb-3 {
+ @media (width >= 48rem) {
+ margin-bottom: calc(var(--spacing) * 3);
+ }
+ }
+ .md\:mb-10 {
+ @media (width >= 48rem) {
+ margin-bottom: calc(var(--spacing) * 10);
+ }
+ }
+ .md\:mb-12 {
+ @media (width >= 48rem) {
+ margin-bottom: calc(var(--spacing) * 12);
+ }
+ }
+ .md\:mb-16 {
+ @media (width >= 48rem) {
+ margin-bottom: calc(var(--spacing) * 16);
+ }
+ }
+ .md\:block {
+ @media (width >= 48rem) {
+ display: block;
+ }
+ }
+ .md\:flex {
+ @media (width >= 48rem) {
+ display: flex;
+ }
+ }
+ .md\:hidden {
+ @media (width >= 48rem) {
+ display: none;
+ }
+ }
+ .md\:h-32 {
+ @media (width >= 48rem) {
+ height: calc(var(--spacing) * 32);
+ }
+ }
+ .md\:w-32 {
+ @media (width >= 48rem) {
+ width: calc(var(--spacing) * 32);
+ }
+ }
+ .md\:grid-cols-2 {
+ @media (width >= 48rem) {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+ }
+ .md\:grid-cols-3 {
+ @media (width >= 48rem) {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+ }
+ .md\:grid-cols-4 {
+ @media (width >= 48rem) {
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ }
+ }
+ .md\:grid-cols-\[1\.4fr_1fr_1fr\] {
+ @media (width >= 48rem) {
+ grid-template-columns: 1.4fr 1fr 1fr;
+ }
+ }
+ .md\:flex-col {
+ @media (width >= 48rem) {
+ flex-direction: column;
+ }
+ }
+ .md\:flex-row {
+ @media (width >= 48rem) {
+ flex-direction: row;
+ }
+ }
+ .md\:items-center {
+ @media (width >= 48rem) {
+ align-items: center;
+ }
+ }
+ .md\:justify-between {
+ @media (width >= 48rem) {
+ justify-content: space-between;
+ }
+ }
+ .md\:space-y-8 {
+ @media (width >= 48rem) {
+ :where(& > :not(:last-child)) {
+ --tw-space-y-reverse: 0;
+ margin-block-start: calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));
+ margin-block-end: calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)));
+ }
+ }
+ }
+ .md\:border-b {
+ @media (width >= 48rem) {
+ border-bottom-style: var(--tw-border-style);
+ border-bottom-width: 1px;
+ }
+ }
+ .md\:border-gray-300 {
+ @media (width >= 48rem) {
+ border-color: var(--color-gray-300);
+ }
+ }
+ .md\:p-0 {
+ @media (width >= 48rem) {
+ padding: calc(var(--spacing) * 0);
+ }
+ }
+ .md\:p-12 {
+ @media (width >= 48rem) {
+ padding: calc(var(--spacing) * 12);
+ }
+ }
+ .md\:px-8 {
+ @media (width >= 48rem) {
+ padding-inline: calc(var(--spacing) * 8);
+ }
+ }
+ .md\:px-10 {
+ @media (width >= 48rem) {
+ padding-inline: calc(var(--spacing) * 10);
+ }
+ }
+ .md\:py-20 {
+ @media (width >= 48rem) {
+ padding-block: calc(var(--spacing) * 20);
+ }
+ }
+ .md\:pr-8 {
+ @media (width >= 48rem) {
+ padding-right: calc(var(--spacing) * 8);
+ }
+ }
+ .md\:text-left {
+ @media (width >= 48rem) {
+ text-align: left;
+ }
+ }
+ .md\:text-2xl {
+ @media (width >= 48rem) {
+ font-size: var(--text-2xl);
+ line-height: var(--tw-leading, var(--text-2xl--line-height));
+ }
+ }
+ .md\:text-5xl {
+ @media (width >= 48rem) {
+ font-size: var(--text-5xl);
+ line-height: var(--tw-leading, var(--text-5xl--line-height));
+ }
+ }
+ .lg\:sticky {
+ @media (width >= 64rem) {
+ position: sticky;
+ }
+ }
+ .lg\:top-24 {
+ @media (width >= 64rem) {
+ top: calc(var(--spacing) * 24);
+ }
+ }
+ .lg\:mb-8 {
+ @media (width >= 64rem) {
+ margin-bottom: calc(var(--spacing) * 8);
+ }
+ }
+ .lg\:mb-16 {
+ @media (width >= 64rem) {
+ margin-bottom: calc(var(--spacing) * 16);
+ }
+ }
+ .lg\:block {
+ @media (width >= 64rem) {
+ display: block;
+ }
+ }
+ .lg\:grid-cols-2 {
+ @media (width >= 64rem) {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+ }
+ .lg\:grid-cols-\[0\.8fr_1\.2fr\] {
+ @media (width >= 64rem) {
+ grid-template-columns: 0.8fr 1.2fr;
+ }
+ }
+ .lg\:grid-cols-\[0\.9fr_1\.1fr\] {
+ @media (width >= 64rem) {
+ grid-template-columns: 0.9fr 1.1fr;
+ }
+ }
+ .lg\:grid-cols-\[0\.75fr_1\.25fr\] {
+ @media (width >= 64rem) {
+ grid-template-columns: 0.75fr 1.25fr;
+ }
+ }
+ .lg\:grid-cols-\[0\.85fr_1\.15fr\] {
+ @media (width >= 64rem) {
+ grid-template-columns: 0.85fr 1.15fr;
+ }
+ }
+ .lg\:grid-cols-\[1\.05fr_0\.95fr\] {
+ @media (width >= 64rem) {
+ grid-template-columns: 1.05fr 0.95fr;
+ }
+ }
+ .lg\:flex-row {
+ @media (width >= 64rem) {
+ flex-direction: row;
+ }
+ }
+ .lg\:items-center {
+ @media (width >= 64rem) {
+ align-items: center;
+ }
+ }
+ .lg\:items-end {
+ @media (width >= 64rem) {
+ align-items: flex-end;
+ }
+ }
+ .lg\:items-start {
+ @media (width >= 64rem) {
+ align-items: flex-start;
+ }
+ }
+ .lg\:gap-6 {
+ @media (width >= 64rem) {
+ gap: calc(var(--spacing) * 6);
+ }
+ }
+ .lg\:gap-10 {
+ @media (width >= 64rem) {
+ gap: calc(var(--spacing) * 10);
+ }
+ }
+ .lg\:self-start {
+ @media (width >= 64rem) {
+ align-self: flex-start;
+ }
+ }
+ .lg\:px-8 {
+ @media (width >= 64rem) {
+ padding-inline: calc(var(--spacing) * 8);
+ }
+ }
+ .lg\:py-32 {
+ @media (width >= 64rem) {
+ padding-block: calc(var(--spacing) * 32);
+ }
+ }
+ .lg\:text-7xl {
+ @media (width >= 64rem) {
+ font-size: var(--text-7xl);
+ line-height: var(--tw-leading, var(--text-7xl--line-height));
+ }
+ }
+ .dark\:block {
+ &:where(.dark, .dark *) {
+ display: block;
+ }
+ }
+ .dark\:hidden {
+ &:where(.dark, .dark *) {
+ display: none;
+ }
+ }
+ .dark\:border-slate-700 {
+ &:where(.dark, .dark *) {
+ border-color: var(--color-slate-700);
+ }
+ }
+ .dark\:border-slate-800 {
+ &:where(.dark, .dark *) {
+ border-color: var(--color-slate-800);
+ }
+ }
+ .dark\:border-slate-800\/80 {
+ &:where(.dark, .dark *) {
+ border-color: color-mix(in srgb, oklch(27.9% 0.041 260.031) 80%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ border-color: color-mix(in oklab, var(--color-slate-800) 80%, transparent);
+ }
+ }
+ }
+ .dark\:border-white\/5 {
+ &:where(.dark, .dark *) {
+ border-color: color-mix(in srgb, #fff 5%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ border-color: color-mix(in oklab, var(--color-white) 5%, transparent);
+ }
+ }
+ }
+ .dark\:border-white\/10 {
+ &:where(.dark, .dark *) {
+ border-color: color-mix(in srgb, #fff 10%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ border-color: color-mix(in oklab, var(--color-white) 10%, transparent);
+ }
+ }
+ }
+ .dark\:bg-black {
+ &:where(.dark, .dark *) {
+ background-color: var(--color-black);
+ }
+ }
+ .dark\:bg-black\/20 {
+ &:where(.dark, .dark *) {
+ background-color: color-mix(in srgb, #000 20%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-black) 20%, transparent);
+ }
+ }
+ }
+ .dark\:bg-slate-900 {
+ &:where(.dark, .dark *) {
+ background-color: var(--color-slate-900);
+ }
+ }
+ .dark\:bg-slate-900\/40 {
+ &:where(.dark, .dark *) {
+ background-color: color-mix(in srgb, oklch(20.8% 0.042 265.755) 40%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-slate-900) 40%, transparent);
+ }
+ }
+ }
+ .dark\:bg-slate-950 {
+ &:where(.dark, .dark *) {
+ background-color: var(--color-slate-950);
+ }
+ }
+ .dark\:bg-slate-950\/85 {
+ &:where(.dark, .dark *) {
+ background-color: color-mix(in srgb, oklch(12.9% 0.042 264.695) 85%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-slate-950) 85%, transparent);
+ }
+ }
+ }
+ .dark\:bg-white {
+ &:where(.dark, .dark *) {
+ background-color: var(--color-white);
+ }
+ }
+ .dark\:bg-white\/5 {
+ &:where(.dark, .dark *) {
+ background-color: color-mix(in srgb, #fff 5%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-white) 5%, transparent);
+ }
+ }
+ }
+ .dark\:bg-white\/\[0\.02\] {
+ &:where(.dark, .dark *) {
+ background-color: color-mix(in srgb, #fff 2%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-white) 2%, transparent);
+ }
+ }
+ }
+ .dark\:to-white\/20 {
+ &:where(.dark, .dark *) {
+ --tw-gradient-to: color-mix(in srgb, #fff 20%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-gradient-to: color-mix(in oklab, var(--color-white) 20%, transparent);
+ }
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
+ }
+ }
+ .dark\:text-blue-400 {
+ &:where(.dark, .dark *) {
+ color: var(--color-blue-400);
+ }
+ }
+ .dark\:text-blue-600 {
+ &:where(.dark, .dark *) {
+ color: var(--color-blue-600);
+ }
+ }
+ .dark\:text-slate-100 {
+ &:where(.dark, .dark *) {
+ color: var(--color-slate-100);
+ }
+ }
+ .dark\:text-slate-300 {
+ &:where(.dark, .dark *) {
+ color: var(--color-slate-300);
+ }
+ }
+ .dark\:text-slate-400 {
+ &:where(.dark, .dark *) {
+ color: var(--color-slate-400);
+ }
+ }
+ .dark\:text-slate-500 {
+ &:where(.dark, .dark *) {
+ color: var(--color-slate-500);
+ }
+ }
+ .dark\:text-slate-950 {
+ &:where(.dark, .dark *) {
+ color: var(--color-slate-950);
+ }
+ }
+ .dark\:text-white {
+ &:where(.dark, .dark *) {
+ color: var(--color-white);
+ }
+ }
+ .dark\:text-white\/5 {
+ &:where(.dark, .dark *) {
+ color: color-mix(in srgb, #fff 5%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ color: color-mix(in oklab, var(--color-white) 5%, transparent);
+ }
+ }
+ }
+ .dark\:text-white\/60 {
+ &:where(.dark, .dark *) {
+ color: color-mix(in srgb, #fff 60%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ color: color-mix(in oklab, var(--color-white) 60%, transparent);
+ }
+ }
+ }
+ .dark\:text-white\/80 {
+ &:where(.dark, .dark *) {
+ color: color-mix(in srgb, #fff 80%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ color: color-mix(in oklab, var(--color-white) 80%, transparent);
+ }
+ }
+ }
+ .dark\:text-white\/90 {
+ &:where(.dark, .dark *) {
+ color: color-mix(in srgb, #fff 90%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ color: color-mix(in oklab, var(--color-white) 90%, transparent);
+ }
+ }
+ }
+ .dark\:shadow-white\/10 {
+ &:where(.dark, .dark *) {
+ --tw-shadow-color: color-mix(in srgb, #fff 10%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-white) 10%, transparent) var(--tw-shadow-alpha), transparent);
+ }
+ }
+ }
+ .dark\:ring-white\/10 {
+ &:where(.dark, .dark *) {
+ --tw-ring-color: color-mix(in srgb, #fff 10%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-ring-color: color-mix(in oklab, var(--color-white) 10%, transparent);
+ }
+ }
+ }
+ .dark\:hover\:bg-slate-900 {
+ &:where(.dark, .dark *) {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-slate-900);
+ }
+ }
+ }
+ }
+ .dark\:hover\:bg-white\/10 {
+ &:where(.dark, .dark *) {
+ &:hover {
+ @media (hover: hover) {
+ background-color: color-mix(in srgb, #fff 10%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-white) 10%, transparent);
+ }
+ }
+ }
+ }
+ }
+ .dark\:hover\:text-blue-400 {
+ &:where(.dark, .dark *) {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-blue-400);
+ }
+ }
+ }
+ }
+}
+@layer base {
+ html {
+ color-scheme: light;
+ }
+ html.dark {
+ color-scheme: dark;
+ }
+ body {
+ display: flex;
+ min-height: 100vh;
+ flex-direction: column;
+ background-color: var(--color-slate-50);
+ color: var(--color-slate-950);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
+ --tw-duration: 300ms;
+ transition-duration: 300ms;
+ &:where(.dark, .dark *) {
+ background-color: var(--color-slate-950);
+ }
+ &:where(.dark, .dark *) {
+ color: var(--color-slate-100);
+ }
+ font-feature-settings: "cv02", "cv03", "cv04", "cv11";
+ }
+ ::selection {
+ background-color: var(--color-blue-600);
+ color: var(--color-white);
+ }
+ a {
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
+ }
+ :focus-visible {
+ outline-style: var(--tw-outline-style);
+ outline-width: 2px;
+ outline-offset: 2px;
+ outline-color: var(--color-blue-500);
+ }
+ .wrap {
+ flex-shrink: 0;
+ flex-grow: 1;
+ flex-basis: auto;
+ }
+ .contain, .band {
+ margin-inline: auto;
+ width: 100%;
+ max-width: var(--container-6xl);
+ padding-inline: calc(var(--spacing) * 4);
+ @media (width >= 40rem) {
+ padding-inline: calc(var(--spacing) * 6);
+ }
+ @media (width >= 64rem) {
+ padding-inline: calc(var(--spacing) * 8);
+ }
+ }
+ .contain-narrow, .band-narrow {
+ margin-inline: auto;
+ width: 100%;
+ max-width: var(--container-3xl);
+ padding-inline: calc(var(--spacing) * 4);
+ @media (width >= 40rem) {
+ padding-inline: calc(var(--spacing) * 6);
+ }
+ @media (width >= 64rem) {
+ padding-inline: calc(var(--spacing) * 8);
+ }
+ }
+ .contain-wide, .band-wide {
+ margin-inline: auto;
+ width: 100%;
+ max-width: var(--container-7xl);
+ padding-inline: calc(var(--spacing) * 4);
+ @media (width >= 40rem) {
+ padding-inline: calc(var(--spacing) * 6);
+ }
+ @media (width >= 64rem) {
+ padding-inline: calc(var(--spacing) * 8);
+ }
+ }
+}
+@layer components {
+ footer {
+ flex-grow: 0;
+ }
+ .wrp {
+ margin-inline: auto;
+ width: 100%;
+ max-width: var(--container-6xl);
+ padding-inline: calc(var(--spacing) * 4);
+ @media (width >= 40rem) {
+ padding-inline: calc(var(--spacing) * 6);
+ }
+ @media (width >= 64rem) {
+ padding-inline: calc(var(--spacing) * 8);
+ }
+ }
+ .section, section {
+ padding-block: calc(var(--spacing) * 10);
+ @media (width >= 48rem) {
+ padding-block: calc(var(--spacing) * 16);
+ }
+ }
+ .section-tight {
+ padding-block: calc(var(--spacing) * 10);
+ @media (width >= 48rem) {
+ padding-block: calc(var(--spacing) * 14);
+ }
+ }
+ .text-gradient {
+ --tw-gradient-position: to right;
+ @supports (background-image: linear-gradient(in lab, red, red)) {
+ --tw-gradient-position: to right in oklab;
+ }
+ background-image: linear-gradient(var(--tw-gradient-stops));
+ --tw-gradient-from: var(--color-indigo-400);
+ --tw-gradient-to: var(--color-pink-600);
+ --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));
+ background-clip: text;
+ color: transparent;
+ }
+ .eyebrow {
+ --tw-font-weight: var(--font-weight-semibold);
+ font-weight: var(--font-weight-semibold);
+ --tw-tracking: var(--tracking-widest);
+ letter-spacing: var(--tracking-widest);
+ color: var(--color-blue-600);
+ &:where(.dark, .dark *) {
+ color: var(--color-blue-400);
+ }
+ }
+ .btn {
+ display: inline-flex;
+ min-height: calc(var(--spacing) * 11);
+ align-items: center;
+ justify-content: center;
+ gap: calc(var(--spacing) * 2);
+ border-radius: var(--radius-lg);
+ padding-inline: calc(var(--spacing) * 5);
+ padding-block: calc(var(--spacing) * 2.5);
+ font-size: var(--text-sm);
+ line-height: var(--tw-leading, var(--text-sm--line-height));
+ --tw-leading: 1;
+ line-height: 1;
+ --tw-font-weight: var(--font-weight-semibold);
+ font-weight: var(--font-weight-semibold);
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
+ --tw-duration: 200ms;
+ transition-duration: 200ms;
+ &:focus-visible {
+ outline-style: var(--tw-outline-style);
+ outline-width: 2px;
+ }
+ &:focus-visible {
+ outline-offset: 2px;
+ }
+ &:disabled {
+ pointer-events: none;
+ }
+ &:disabled {
+ opacity: 50%;
+ }
+ }
+ .btn-primary {
+ background-color: var(--color-blue-600);
+ color: var(--color-white);
+ --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
+ --tw-shadow-color: color-mix(in srgb, oklch(54.6% 0.245 262.881) 25%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-blue-600) 25%, transparent) var(--tw-shadow-alpha), transparent);
+ }
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-blue-500);
+ }
+ }
+ &:focus-visible {
+ outline-color: var(--color-blue-500);
+ }
+ &:where(.dark, .dark *) {
+ background-color: var(--color-blue-500);
+ }
+ &:where(.dark, .dark *) {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-blue-400);
+ }
+ }
+ }
+ }
+ .btn-secondary {
+ border-style: var(--tw-border-style);
+ border-width: 1px;
+ border-color: var(--color-slate-200);
+ background-color: var(--color-white);
+ color: var(--color-slate-900);
+ &:hover {
+ @media (hover: hover) {
+ border-color: var(--color-slate-300);
+ }
+ }
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-slate-100);
+ }
+ }
+ &:focus-visible {
+ outline-color: var(--color-blue-500);
+ }
+ &:where(.dark, .dark *) {
+ border-color: var(--color-slate-800);
+ }
+ &:where(.dark, .dark *) {
+ background-color: var(--color-slate-900);
+ }
+ &:where(.dark, .dark *) {
+ color: var(--color-slate-100);
+ }
+ &:where(.dark, .dark *) {
+ &:hover {
+ @media (hover: hover) {
+ border-color: var(--color-slate-700);
+ }
+ }
+ }
+ &:where(.dark, .dark *) {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-slate-800);
+ }
+ }
+ }
+ }
+ .btn-ghost {
+ color: var(--color-slate-700);
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-slate-100);
+ }
+ }
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-slate-950);
+ }
+ }
+ &:focus-visible {
+ outline-color: var(--color-blue-500);
+ }
+ &:where(.dark, .dark *) {
+ color: var(--color-slate-300);
+ }
+ &:where(.dark, .dark *) {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-slate-900);
+ }
+ }
+ }
+ &:where(.dark, .dark *) {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-white);
+ }
+ }
+ }
+ }
+ .card {
+ border-radius: var(--radius-lg);
+ border-style: var(--tw-border-style);
+ border-width: 1px;
+ border-color: var(--color-slate-200);
+ background-color: var(--color-white);
+ padding: calc(var(--spacing) * 6);
+ --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
+ --tw-shadow-color: color-mix(in srgb, oklch(12.9% 0.042 264.695) 5%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-slate-950) 5%, transparent) var(--tw-shadow-alpha), transparent);
+ }
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
+ &:where(.dark, .dark *) {
+ border-color: var(--color-slate-800);
+ }
+ &:where(.dark, .dark *) {
+ background-color: color-mix(in srgb, oklch(20.8% 0.042 265.755) 80%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-slate-900) 80%, transparent);
+ }
+ }
+ &:where(.dark, .dark *) {
+ --tw-shadow-color: color-mix(in srgb, #000 20%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ --tw-shadow-color: color-mix(in oklab, color-mix(in oklab, var(--color-black) 20%, transparent) var(--tw-shadow-alpha), transparent);
+ }
+ }
+ }
+ .bg-pre-blue {
+ background-color: var(--color-blue-50);
+ color: var(--color-blue-950);
+ &:where(.dark, .dark *) {
+ background-color: color-mix(in srgb, oklch(28.2% 0.091 267.935) 35%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-blue-950) 35%, transparent);
+ }
+ }
+ &:where(.dark, .dark *) {
+ color: var(--color-blue-50);
+ }
+ }
+ .bg-pre-emerald {
+ background-color: var(--color-emerald-50);
+ color: var(--color-emerald-950);
+ &:where(.dark, .dark *) {
+ background-color: color-mix(in srgb, oklch(26.2% 0.051 172.552) 35%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-emerald-950) 35%, transparent);
+ }
+ }
+ &:where(.dark, .dark *) {
+ color: var(--color-emerald-50);
+ }
+ }
+ .bg-pre-amber {
+ background-color: var(--color-amber-50);
+ color: var(--color-amber-950);
+ &:where(.dark, .dark *) {
+ background-color: color-mix(in srgb, oklch(27.9% 0.077 45.635) 35%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-amber-950) 35%, transparent);
+ }
+ }
+ &:where(.dark, .dark *) {
+ color: var(--color-amber-50);
+ }
+ }
+ .bg-pre-rose {
+ background-color: var(--color-rose-50);
+ color: var(--color-rose-950);
+ &:where(.dark, .dark *) {
+ background-color: color-mix(in srgb, oklch(27.1% 0.105 12.094) 35%, transparent);
+ @supports (color: color-mix(in lab, red, red)) {
+ background-color: color-mix(in oklab, var(--color-rose-950) 35%, transparent);
+ }
+ }
+ &:where(.dark, .dark *) {
+ color: var(--color-rose-50);
+ }
+ }
+ .nav-link {
+ border-radius: var(--radius-md);
+ padding-inline: calc(var(--spacing) * 3);
+ padding-block: calc(var(--spacing) * 2);
+ font-size: var(--text-sm);
+ line-height: var(--tw-leading, var(--text-sm--line-height));
+ --tw-font-weight: var(--font-weight-medium);
+ font-weight: var(--font-weight-medium);
+ color: var(--color-slate-700);
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-slate-100);
+ }
+ }
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-slate-950);
+ }
+ }
+ &:where(.dark, .dark *) {
+ color: var(--color-slate-300);
+ }
+ &:where(.dark, .dark *) {
+ &:hover {
+ @media (hover: hover) {
+ background-color: var(--color-slate-900);
+ }
+ }
+ }
+ &:where(.dark, .dark *) {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-white);
+ }
+ }
+ }
+ }
+ .prose-shell {
+ margin-inline: auto;
+ max-width: var(--container-4xl);
+ padding-inline: calc(var(--spacing) * 4);
+ padding-block: calc(var(--spacing) * 16);
+ @media (width >= 40rem) {
+ padding-inline: calc(var(--spacing) * 6);
+ }
+ @media (width >= 64rem) {
+ padding-inline: calc(var(--spacing) * 8);
+ }
+ }
+ .prose {
+ color: #475569;
+ line-height: 1.75;
+ }
+ .dark .prose {
+ color: #94a3b8;
+ }
+ .prose > * + * {
+ margin-top: 1.25em;
+ }
+ .prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 {
+ color: #0f172a;
+ font-weight: 700;
+ line-height: 1.25;
+ }
+ .dark .prose h1, .dark .prose h2, .dark .prose h3, .dark .prose h4, .dark .prose h5, .dark .prose h6 {
+ color: #f8fafc;
+ }
+ .prose h1 {
+ font-size: 2.25rem;
+ margin-top: 0;
+ margin-bottom: 0.5em;
+ }
+ .prose h2 {
+ font-size: 1.75rem;
+ margin-top: 2em;
+ margin-bottom: 0.75em;
+ padding-bottom: 0.4em;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.08);
+ }
+ .dark .prose h2 {
+ border-bottom-color: rgba(255, 255, 255, 0.06);
+ }
+ .prose h3 {
+ font-size: 1.375rem;
+ margin-top: 1.75em;
+ margin-bottom: 0.6em;
+ }
+ .prose h4 {
+ font-size: 1.125rem;
+ margin-top: 1.5em;
+ margin-bottom: 0.5em;
+ }
+ .prose h5, .prose h6 {
+ font-size: 1rem;
+ margin-top: 1.5em;
+ margin-bottom: 0.5em;
+ color: #334155;
+ }
+ .dark .prose h5, .dark .prose h6 {
+ color: #cbd5e1;
+ }
+ .prose p {
+ margin-top: 1.25em;
+ margin-bottom: 1.25em;
+ }
+ .prose a {
+ color: #2563eb;
+ text-decoration: none;
+ font-weight: 500;
+ transition: color 0.15s ease;
+ }
+ .dark .prose a {
+ color: #60a5fa;
+ }
+ .prose a:hover {
+ color: #1d4ed8;
+ text-decoration: underline;
+ }
+ .dark .prose a:hover {
+ color: #93c5fd;
+ }
+ .prose strong, .prose b {
+ color: #0f172a;
+ font-weight: 600;
+ }
+ .dark .prose strong, .dark .prose b {
+ color: #f1f5f9;
+ }
+ .prose em, .prose i {
+ color: #334155;
+ }
+ .dark .prose em, .dark .prose i {
+ color: #cbd5e1;
+ }
+ .prose ul, .prose ol {
+ margin-top: 1.25em;
+ margin-bottom: 1.25em;
+ padding-left: 1.625em;
+ }
+ .prose ul {
+ list-style-type: disc;
+ }
+ .prose ol {
+ list-style-type: decimal;
+ }
+ .prose ul > li, .prose ol > li {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ padding-left: 0.375em;
+ }
+ .prose ul > li::marker, .prose ol > li::marker {
+ color: #2563eb;
+ }
+ .dark .prose ul > li::marker, .dark .prose ol > li::marker {
+ color: #3b82f6;
+ }
+ .prose ul ul, .prose ul ol, .prose ol ul, .prose ol ol {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ }
+ .prose pre {
+ background-color: #f1f5f9;
+ border: 1px solid rgba(0, 0, 0, 0.08);
+ border-radius: 0.5rem;
+ padding: 1.25em;
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+ overflow-x: auto;
+ font-size: 0.875em;
+ line-height: 1.7;
+ }
+ .dark .prose pre {
+ background-color: #141f38;
+ border-color: rgba(255, 255, 255, 0.06);
+ }
+ .prose pre code {
+ background: none;
+ border: none;
+ padding: 0;
+ font-size: inherit;
+ color: #334155;
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ }
+ .dark .prose pre code {
+ color: #e2e8f0;
+ }
+ .prose code {
+ background-color: rgba(0, 0, 0, 0.05);
+ border: 1px solid rgba(0, 0, 0, 0.06);
+ border-radius: 0.375rem;
+ padding: 0.2em 0.4em;
+ font-size: 0.875em;
+ color: #1d4ed8;
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ }
+ .dark .prose code {
+ background-color: rgba(255, 255, 255, 0.06);
+ border-color: rgba(255, 255, 255, 0.06);
+ color: #93c5fd;
+ }
+ .prose blockquote {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+ padding-left: 1.25em;
+ border-left: 3px solid #2563eb;
+ font-style: italic;
+ color: #475569;
+ }
+ .dark .prose blockquote {
+ border-left-color: #3b82f6;
+ color: #cbd5e1;
+ }
+ .prose blockquote p:first-of-type {
+ margin-top: 0;
+ }
+ .prose blockquote p:last-of-type {
+ margin-bottom: 0;
+ }
+ .prose table {
+ width: 100%;
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+ border-collapse: collapse;
+ font-size: 0.875em;
+ line-height: 1.5;
+ }
+ .prose thead {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.15);
+ }
+ .dark .prose thead {
+ border-bottom-color: rgba(255, 255, 255, 0.1);
+ }
+ .prose th {
+ padding: 0.75em 1em;
+ text-align: left;
+ font-weight: 600;
+ color: #0f172a;
+ }
+ .dark .prose th {
+ color: #f1f5f9;
+ }
+ .prose td {
+ padding: 0.625em 1em;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.06);
+ vertical-align: top;
+ }
+ .dark .prose td {
+ border-bottom-color: rgba(255, 255, 255, 0.05);
+ }
+ .prose tbody tr:nth-child(even) {
+ background-color: rgba(0, 0, 0, 0.02);
+ }
+ .dark .prose tbody tr:nth-child(even) {
+ background-color: rgba(255, 255, 255, 0.02);
+ }
+ .prose tbody tr:hover {
+ background-color: rgba(0, 0, 0, 0.03);
+ }
+ .dark .prose tbody tr:hover {
+ background-color: rgba(255, 255, 255, 0.04);
+ }
+ .prose img {
+ border-radius: 0.5rem;
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+ max-width: 100%;
+ height: auto;
+ display: block;
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+ }
+ .prose hr {
+ margin-top: 2.5em;
+ margin-bottom: 2.5em;
+ border: 0;
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ }
+ .dark .prose hr {
+ border-top-color: rgba(255, 255, 255, 0.08);
+ }
+ .prose li > p, .prose blockquote > p {
+ margin-top: 0.75em;
+ margin-bottom: 0.75em;
+ }
+}
+@layer utilities;
+@property --tw-translate-x {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0;
+}
+@property --tw-translate-y {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0;
+}
+@property --tw-translate-z {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0;
+}
+@property --tw-space-y-reverse {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0;
+}
+@property --tw-border-style {
+ syntax: "*";
+ inherits: false;
+ initial-value: solid;
+}
+@property --tw-gradient-position {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-gradient-from {
+ syntax: "";
+ inherits: false;
+ initial-value: #0000;
+}
+@property --tw-gradient-via {
+ syntax: "";
+ inherits: false;
+ initial-value: #0000;
+}
+@property --tw-gradient-to {
+ syntax: "";
+ inherits: false;
+ initial-value: #0000;
+}
+@property --tw-gradient-stops {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-gradient-via-stops {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-gradient-from-position {
+ syntax: "";
+ inherits: false;
+ initial-value: 0%;
+}
+@property --tw-gradient-via-position {
+ syntax: "";
+ inherits: false;
+ initial-value: 50%;
+}
+@property --tw-gradient-to-position {
+ syntax: "";
+ inherits: false;
+ initial-value: 100%;
+}
+@property --tw-leading {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-font-weight {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-tracking {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-shadow {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0 0 #0000;
+}
+@property --tw-shadow-color {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-shadow-alpha {
+ syntax: "";
+ inherits: false;
+ initial-value: 100%;
+}
+@property --tw-inset-shadow {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0 0 #0000;
+}
+@property --tw-inset-shadow-color {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-inset-shadow-alpha {
+ syntax: "";
+ inherits: false;
+ initial-value: 100%;
+}
+@property --tw-ring-color {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-ring-shadow {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0 0 #0000;
+}
+@property --tw-inset-ring-color {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-inset-ring-shadow {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0 0 #0000;
+}
+@property --tw-ring-inset {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-ring-offset-width {
+ syntax: "";
+ inherits: false;
+ initial-value: 0px;
+}
+@property --tw-ring-offset-color {
+ syntax: "*";
+ inherits: false;
+ initial-value: #fff;
+}
+@property --tw-ring-offset-shadow {
+ syntax: "*";
+ inherits: false;
+ initial-value: 0 0 #0000;
+}
+@property --tw-outline-style {
+ syntax: "*";
+ inherits: false;
+ initial-value: solid;
+}
+@property --tw-blur {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-brightness {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-contrast {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-grayscale {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-hue-rotate {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-invert {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-opacity {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-saturate {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-sepia {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-drop-shadow {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-drop-shadow-color {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-drop-shadow-alpha {
+ syntax: "";
+ inherits: false;
+ initial-value: 100%;
+}
+@property --tw-drop-shadow-size {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-backdrop-blur {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-backdrop-brightness {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-backdrop-contrast {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-backdrop-grayscale {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-backdrop-hue-rotate {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-backdrop-invert {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-backdrop-opacity {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-backdrop-saturate {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-backdrop-sepia {
+ syntax: "*";
+ inherits: false;
+}
+@property --tw-duration {
+ syntax: "*";
+ inherits: false;
+}
+@layer properties {
+ @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
+ *, ::before, ::after, ::backdrop {
+ --tw-translate-x: 0;
+ --tw-translate-y: 0;
+ --tw-translate-z: 0;
+ --tw-space-y-reverse: 0;
+ --tw-border-style: solid;
+ --tw-gradient-position: initial;
+ --tw-gradient-from: #0000;
+ --tw-gradient-via: #0000;
+ --tw-gradient-to: #0000;
+ --tw-gradient-stops: initial;
+ --tw-gradient-via-stops: initial;
+ --tw-gradient-from-position: 0%;
+ --tw-gradient-via-position: 50%;
+ --tw-gradient-to-position: 100%;
+ --tw-leading: initial;
+ --tw-font-weight: initial;
+ --tw-tracking: initial;
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-color: initial;
+ --tw-shadow-alpha: 100%;
+ --tw-inset-shadow: 0 0 #0000;
+ --tw-inset-shadow-color: initial;
+ --tw-inset-shadow-alpha: 100%;
+ --tw-ring-color: initial;
+ --tw-ring-shadow: 0 0 #0000;
+ --tw-inset-ring-color: initial;
+ --tw-inset-ring-shadow: 0 0 #0000;
+ --tw-ring-inset: initial;
+ --tw-ring-offset-width: 0px;
+ --tw-ring-offset-color: #fff;
+ --tw-ring-offset-shadow: 0 0 #0000;
+ --tw-outline-style: solid;
+ --tw-blur: initial;
+ --tw-brightness: initial;
+ --tw-contrast: initial;
+ --tw-grayscale: initial;
+ --tw-hue-rotate: initial;
+ --tw-invert: initial;
+ --tw-opacity: initial;
+ --tw-saturate: initial;
+ --tw-sepia: initial;
+ --tw-drop-shadow: initial;
+ --tw-drop-shadow-color: initial;
+ --tw-drop-shadow-alpha: 100%;
+ --tw-drop-shadow-size: initial;
+ --tw-backdrop-blur: initial;
+ --tw-backdrop-brightness: initial;
+ --tw-backdrop-contrast: initial;
+ --tw-backdrop-grayscale: initial;
+ --tw-backdrop-hue-rotate: initial;
+ --tw-backdrop-invert: initial;
+ --tw-backdrop-opacity: initial;
+ --tw-backdrop-saturate: initial;
+ --tw-backdrop-sepia: initial;
+ --tw-duration: initial;
+ }
+ }
+}
diff --git a/public/css/vendors.css b/public/css/vendors.css
new file mode 100644
index 0000000..d48b2cb
--- /dev/null
+++ b/public/css/vendors.css
@@ -0,0 +1,2 @@
+/* Vendor styles — add third-party CSS here or @import them.
+ Tailwind is NOT imported here by default. */
diff --git a/public/images/thanos.png b/public/images/thanos.png
new file mode 100644
index 0000000..52acfb4
Binary files /dev/null and b/public/images/thanos.png differ
diff --git a/public/index.php b/public/index.php
new file mode 100644
index 0000000..7d69cca
--- /dev/null
+++ b/public/index.php
@@ -0,0 +1,7 @@
+init();
diff --git a/public/js/init.js b/public/js/init.js
new file mode 100644
index 0000000..f8cf22b
--- /dev/null
+++ b/public/js/init.js
@@ -0,0 +1,58 @@
+"use strict";
+
+(function () {
+ const framexEngine = {
+ init() {
+ this.bindThemeToggle();
+ this.bindMobileMenu();
+ },
+
+ bindThemeToggle() {
+ const buttons = document.querySelectorAll("[data-theme-toggle]");
+ if (!buttons.length) {
+ return;
+ }
+
+ const applyTheme = (theme) => {
+ const isDark = theme === "dark";
+ document.documentElement.classList.toggle("dark", isDark);
+ try {
+ localStorage.setItem("framex-theme", theme);
+ } catch (error) {}
+ buttons.forEach((button) => {
+ button.setAttribute("aria-pressed", String(isDark));
+ });
+ };
+
+ buttons.forEach((button) => {
+ button.addEventListener("click", () => {
+ const nextTheme = document.documentElement.classList.contains("dark")
+ ? "light"
+ : "dark";
+ applyTheme(nextTheme);
+ });
+ });
+ },
+
+ bindMobileMenu() {
+ const button = document.querySelector("[data-mobile-menu-toggle]");
+ const menu = document.querySelector("[data-mobile-menu]");
+ if (!button || !menu) {
+ return;
+ }
+
+ button.addEventListener("click", () => {
+ const isOpen = button.getAttribute("aria-expanded") === "true";
+ button.setAttribute("aria-expanded", String(!isOpen));
+ menu.classList.toggle("hidden", isOpen);
+ });
+ },
+ };
+
+ // Initialize on DOM ready
+ if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", () => framexEngine.init());
+ } else {
+ framexEngine.init();
+ }
+})();
diff --git a/templates/clean.php b/templates/clean.php
new file mode 100644
index 0000000..6ddf564
--- /dev/null
+++ b/templates/clean.php
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ = (isset($title) ? $title : 'Framex Engine') ?>
+
+
+
+
+
+
+
+
+ = $view ?>
+
+
+
+
+
+
+
diff --git a/templates/error404.php b/templates/error404.php
new file mode 100644
index 0000000..6eefa58
--- /dev/null
+++ b/templates/error404.php
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 404
+
+
+
+ 404
+
+
+
+
+
+
+ Page not found
+
+
+ The page you are looking for does not exist. It might have been moved, renamed, or maybe it never existed in the first place.
+
+
+
+
+
+
+
+ Did you mean to create this file?
+
+ app/views= htmlspecialchars($_SERVER['REQUEST_URI']) ?>.php
+
+
+
+
diff --git a/templates/main.php b/templates/main.php
new file mode 100644
index 0000000..f766cf0
--- /dev/null
+++ b/templates/main.php
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+ = $metaTitle ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ = partial('topmenu') ?>
+ = $view ?>
+
+ = partial('footer') ?>
+
+
+
+
+
diff --git a/templates/partials/footer.php b/templates/partials/footer.php
new file mode 100644
index 0000000..3126cb5
--- /dev/null
+++ b/templates/partials/footer.php
@@ -0,0 +1,39 @@
+
+
diff --git a/templates/partials/topmenu.php b/templates/partials/topmenu.php
new file mode 100644
index 0000000..07f460b
--- /dev/null
+++ b/templates/partials/topmenu.php
@@ -0,0 +1,57 @@
+
+
+
+
+
+