diff --git a/.github/workflows/compile-typescript.yml b/.github/workflows/compile-typescript.yml
new file mode 100644
index 00000000000..101ee37b4a2
--- /dev/null
+++ b/.github/workflows/compile-typescript.yml
@@ -0,0 +1,48 @@
+name: Compile TypeScript
+
+on:
+ push:
+ paths:
+ - 'packages/**/src/**/*.ts'
+
+jobs:
+ compile:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # Needed for the git commit step
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: |
+ npm ci
+ cd packages/vite-plugin && npm ci
+ cd ../..
+
+ - name: Compile TypeScript
+ run: |
+ cd packages/vite-plugin
+ npm run build
+ cd ../..
+
+ - name: Check for changes
+ id: check_changes
+ run: |
+ git diff --exit-code --quiet packages/vite-plugin/dist || echo "changes=true" >> $GITHUB_OUTPUT
+
+ - name: Commit changes
+ if: steps.check_changes.outputs.changes == 'true'
+ run: |
+ git config --local user.email "github-actions[bot]@users.noreply.github.com"
+ git config --local user.name "github-actions[bot]"
+ git add packages/vite-plugin/dist
+ git commit -m "Compile TypeScript"
+ git push
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index 040288caea7..52be9e7164f 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -12,7 +12,7 @@ jobs:
steps:
- uses: shivammathur/setup-php@v2
with:
- php-version: "8.1"
+ php-version: "8.2"
extensions: fileinfo
- uses: actions/checkout@v4
@@ -74,7 +74,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
- php: [8.1, 8.2, 8.3]
+ php: [8.2, 8.3, 8.4]
runs-on: ${{ matrix.os }}
steps:
@@ -109,41 +109,6 @@ jobs:
run: php monorepo/scripts/tests/${{ matrix.script }}.php
- build-hydefront-assets:
-
- runs-on: ubuntu-latest
- needs: run-smoke-tests
-
- steps:
- - uses: actions/checkout@v4
-
- - name: Setup Node.js
- uses: actions/setup-node@v4
- with:
- cache: 'npm'
-
- - name: Install Node.js dependencies
- working-directory: 'packages/hydefront'
- run: npm ci
-
- - name: Build assets for production
- working-directory: 'packages/hydefront'
- run: npm run prod
-
- - name: Upload artifacts
- uses: actions/upload-artifact@v4
- with:
- name: 'hydefront'
- path: 'packages/hydefront/dist'
-
- - name: Commit changes
- uses: EndBug/add-and-commit@v9
- with:
- add: 'packages/hydefront/dist'
- message: 'Compile HydeFront assets for production'
- new_branch: compile-hydefront
-
-
build-tailwindcss:
runs-on: ubuntu-latest
@@ -164,7 +129,7 @@ jobs:
run: sed -i 's/\.\/vendor\/hyde\/framework\/resources\/views\/\*\*\/\*\.blade\.php/\.\/packages\/framework\/resources\/views\/\*\*\/\*\.blade\.php/' tailwind.config.js
- name: Build assets for production
- run: npm run prod
+ run: npm run build
- name: Copy compiled app.css file to HydeFront dist folder
run: cp _media/app.css packages/hydefront/dist/app.css
@@ -196,7 +161,7 @@ jobs:
steps:
- uses: shivammathur/setup-php@v2
with:
- php-version: "8.1"
+ php-version: "8.2"
coverage: xdebug
extensions: fileinfo
- uses: actions/checkout@v4
@@ -290,7 +255,7 @@ jobs:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
- php-version: "8.1"
+ php-version: "8.2"
- name: Cache Composer packages
id: composer-cache
@@ -332,7 +297,7 @@ jobs:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
- php-version: "8.1"
+ php-version: "8.2"
- name: Cache Composer packages
id: composer-cache
@@ -377,7 +342,7 @@ jobs:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
- php-version: "8.1"
+ php-version: "8.2"
- name: Cache Composer packages
id: composer-cache
@@ -544,7 +509,7 @@ jobs:
steps:
- uses: shivammathur/setup-php@v2
with:
- php-version: "8.1"
+ php-version: "8.2"
- uses: actions/checkout@v4
- name: Download static analysis tools
@@ -564,7 +529,7 @@ jobs:
steps:
- uses: shivammathur/setup-php@v2
with:
- php-version: "8.1"
+ php-version: "8.2"
- uses: actions/checkout@v4
- name: Install Composer Dependencies
@@ -582,7 +547,7 @@ jobs:
steps:
- uses: shivammathur/setup-php@v2
with:
- php-version: "8.1"
+ php-version: "8.2"
- uses: actions/checkout@v4
- name: Install Composer Dependencies
diff --git a/.github/workflows/coverage-tests.yml b/.github/workflows/coverage-tests.yml
index 170eba8b329..cc5e5e80564 100644
--- a/.github/workflows/coverage-tests.yml
+++ b/.github/workflows/coverage-tests.yml
@@ -9,7 +9,7 @@ jobs:
steps:
- uses: shivammathur/setup-php@v2
with:
- php-version: "8.1"
+ php-version: "8.2"
coverage: xdebug
extensions: fileinfo
- uses: actions/checkout@v4
diff --git a/.github/workflows/end-to-end-tests.yml b/.github/workflows/end-to-end-tests.yml
index bbaa4612fea..365fc37d009 100644
--- a/.github/workflows/end-to-end-tests.yml
+++ b/.github/workflows/end-to-end-tests.yml
@@ -33,7 +33,7 @@ jobs:
run: vendor/bin/pest --stop-on-failure
- name: Prepare the Environment
- run: echo -e "APP_URL=http://localhost:8080 \nDUSK_ENABLED=true\nSERVER_DASHBOARD=false" > .env
+ run: echo -e "APP_URL=http://localhost:8080 \nDUSK_ENABLED=true\nSERVER_DASHBOARD=false\nSERVER_SAVE_PREVIEW=true" > .env
- name: Upgrade Chrome Driver
run: php hyde dusk:chrome-driver `/opt/google/chrome/chrome --version | cut -d " " -f3 | cut -d "." -f1`
diff --git a/.github/workflows/matrix-tests.yml b/.github/workflows/matrix-tests.yml
index ff1f7cdaf14..4cb88606756 100644
--- a/.github/workflows/matrix-tests.yml
+++ b/.github/workflows/matrix-tests.yml
@@ -2,7 +2,7 @@ name: Matrix Tests
on:
pull_request:
- branches: [ "master" ]
+ branches: [ "master", "2.x-dev" ]
paths:
- 'app/**'
- 'packages/**'
@@ -19,7 +19,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
- php: [8.1, 8.2, 8.3]
+ php: [8.2, 8.3, 8.4]
runs-on: ${{ matrix.os }}
steps:
diff --git a/.github/workflows/split-monorepo.yml b/.github/workflows/split-monorepo.yml
index bf45381112b..cc605dc92de 100644
--- a/.github/workflows/split-monorepo.yml
+++ b/.github/workflows/split-monorepo.yml
@@ -390,3 +390,53 @@ jobs:
git commit --author="$COMMIT_AUTHOR_NAME <$COMMIT_AUTHOR_EMAIL>" -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}"
git push upstream master
+
+ vite-plugin:
+ runs-on: ubuntu-latest
+ continue-on-error: true
+ environment:
+ name: hydephp/vite-plugin
+ url: https://github.com/hydephp/vite-plugin/tree/master
+
+ steps:
+ - name: Checkout hydephp/develop
+ uses: actions/checkout@v4
+ with:
+ path: develop
+ persist-credentials: false
+
+ - name: Checkout hydephp/vite-plugin
+ uses: actions/checkout@v4
+ with:
+ repository: hydephp/vite-plugin
+ path: vite-plugin
+ ref: master
+ fetch-depth: 0
+ persist-credentials: false
+
+ - name: Empty the destination directory
+ run: rm -rf vite-plugin/*
+
+ - name: Copy over files
+ run: cp -rf develop/packages/vite-plugin/. vite-plugin -v
+
+ - name: Commit and push changes
+ env:
+ COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
+ COMMIT_AUTHOR_NAME: ${{ github.event.head_commit.author.name }}
+ COMMIT_AUTHOR_EMAIL: ${{ github.event.head_commit.author.email }}
+ run: |
+ cd vite-plugin
+ if ! [[ `git status --porcelain` ]]; then
+ echo "No changes to this package. Exiting gracefully.";
+ exit 0;
+ fi
+
+ git config user.name "github-actions[bot]"
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ git remote add upstream https://oauth2:${{ secrets.SPLIT_MONOREPO_TOKEN }}@github.com/hydephp/vite-plugin.git
+
+ git add .
+ git commit --author="$COMMIT_AUTHOR_NAME <$COMMIT_AUTHOR_EMAIL>" -m "$COMMIT_MESSAGE https://github.com/hydephp/develop/commit/${{ github.sha }}"
+
+ git push upstream master
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index 91eaf200989..096406ad18d 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -2,7 +2,7 @@ name: 🔎 Static Analysis
on:
pull_request:
- branches: [ "master" ]
+ branches: [ "master", "2.x-dev" ]
jobs:
diff --git a/.idea/develop.iml b/.idea/develop.iml
index e5c500c8de7..d55c9677f2f 100644
--- a/.idea/develop.iml
+++ b/.idea/develop.iml
@@ -13,6 +13,10 @@
+
+
+
+
@@ -63,6 +67,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/php.xml b/.idea/php.xml
index 59d9085e017..b8fd8b2d22b 100644
--- a/.idea/php.xml
+++ b/.idea/php.xml
@@ -150,7 +150,6 @@
-
@@ -199,9 +198,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/.idea/phpunit.xml b/.idea/phpunit.xml
index d0e69a37e22..8a06c9eef22 100644
--- a/.idea/phpunit.xml
+++ b/.idea/phpunit.xml
@@ -8,7 +8,6 @@
-
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index f5c7bf895ad..dea01c435ab 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -5,5 +5,6 @@
+
\ No newline at end of file
diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php
index e5e3acca117..db6c871a9b6 100644
--- a/.phpstorm.meta.php
+++ b/.phpstorm.meta.php
@@ -3,5 +3,7 @@
namespace PHPSTORM_META {
override(\app(0), map([
'hyde' => \Hyde\Foundation\HydeKernel::class,
+ 'navigation.main' => \Hyde\Framework\Features\Navigation\MainNavigationMenu::class,
+ 'navigation.sidebar' => \Hyde\Framework\Features\Navigation\DocumentationSidebar::class,
]));
}
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index e3d1b60364c..5e60ccdfe1c 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,4 +1,4 @@
-## [Unreleased] - YYYY-MM-DD
+## [v2-dev] - YYYY-MM-DD
### About
@@ -10,19 +10,680 @@ This serves two purposes:
2. At release time, you can move the Unreleased section changes into a new release version section.
### Added
-- for new features.
+
+- **Added a new consolidated Asset API to better handle media files.** in [#2006](https://github.com/hydephp/develop/pull/2006)
+ - Added several new fluent methods to the `MediaFile` class, like `getLink()`, `getLength()`, `getMimeType()`, etc
+ - Added new `HydeFront` facade to handle CDN links and Tailwind config injection
+ - Added method `Asset::exists()` to check if a media file exists
+ - Added a `Hyde::assets()` method to get all media file instances in the site
+- **Improved Routes facade API with more intuitive method names** in [#2179](https://github.com/hydephp/develop/pull/2179)
+ - **Breaking:** Renamed `Routes::get()` to `Routes::find()` to better indicate it may return null
+ - **Breaking:** Renamed `Routes::getOrFail()` to `Routes::get()` to make the exception-throwing behavior the default and match Laravel conventions
+ - This change requires code updates if you were using these methods - see upgrade guide below
+- **Many MediaFile related helpers have been changed or completely rewritten** to provide a simplified API for interacting with media files
+ - **Note:** For most end users, the changes will have minimal direct impact, but if you have custom code that interacts with media files, you may need to update it
+ - The `Asset` facade has been restructured to be more scoped and easier to use, splitting out a separate `HydeFront` facade and inlining the `AssetService` class
+ - All asset retrieval methods now return a `MediaFile` instance, which can be fluently interacted with, or cast to a string to get the link (which was the previous behavior)
+ - The `Hyde::asset()` method and `asset()` function now return `MediaFile` instances instead of strings, and will throw an exception if the asset does not exist
+ - Renamed method `Asset::hasMediaFile` to `Asset::exists` in [#1957](https://github.com/hydephp/develop/pull/1957)
+ - Renamed method `MediaFile::getContentLength` to `MediaFile::getLength` in [#1904](https://github.com/hydephp/develop/pull/1904)
+ - Replaced method `Hyde::mediaPath` with `MediaFile::sourcePath` in [#1911](https://github.com/hydephp/develop/pull/1911)
+ - Replaced method `Hyde::siteMediaPath` with `MediaFile::outputPath` in [#1911](https://github.com/hydephp/develop/pull/1911)
+ - An exception will now be thrown if you try to get a media file that does not exist in order to prevent missing assets from going unnoticed in [#1932](https://github.com/hydephp/develop/pull/1932)
+- **MediaFile performance improvements:**
+ - Media assets are now cached in the HydeKernel, giving a massive performance boost and making it easier to access the instances in [#1917](https://github.com/hydephp/develop/pull/1917)
+ - Media file metadata is now lazy loaded and then cached in memory, providing performance improvements for files that may not be used in a build in [#1933](https://github.com/hydephp/develop/pull/1933)
+ - We now use the much faster `CRC32` hashing algorithm instead of `MD5` for cache busting keys in [#1918](https://github.com/hydephp/develop/pull/1918)
+- **Ported the HydeSearch plugin used for the documentation search to be an Alpine.js implementation** in [#2029](https://github.com/hydephp/develop/pull/2029)
+ - Renamed Blade component `hyde::components.docs.search-widget` to `hyde::components.docs.search-modal` in [#2029](https://github.com/hydephp/develop/pull/2029)
+ - Added support for customizing the search implementation by creating a `resources/js/HydeSearch.js` file in [#2031](https://github.com/hydephp/develop/pull/2031)
+- **Replaced Laravel Mix with Vite for frontend asset compilation** in [#2010](https://github.com/hydephp/develop/pull/2010)
+ - **Breaking:** You must now use `npm run build` to compile your assets, instead of `npm run prod`
+ - Bundled assets are now compiled directly into the `_media` folder, and will not be copied to the `_site/media` folder by the NPM command in [#2011](https://github.com/hydephp/develop/pull/2011)
+- Added Vite as a build tool in [#2010](https://github.com/hydephp/develop/pull/2010)
+- Added Vite facade in [#2016](https://github.com/hydephp/develop/pull/2016)
+- Added a Vite HMR support for the realtime compiler in [#2016](https://github.com/hydephp/develop/pull/2016)
+- Added a `Feature::fromName()` enum helper in [#1895](https://github.com/hydephp/develop/pull/1895)
+- Added a custom Blade-based heading renderer for Markdown conversions in [#2047](https://github.com/hydephp/develop/pull/2047)
+- Added a new Hyde Vite plugin in [#2160](https://github.com/hydephp/develop/pull/2160)
+- Added a new `\Hyde\Framework\Actions\PreBuildTasks\TransferMediaAssets` build task to handle media assets transfers for site builds in [#1536](https://github.com/hydephp/develop/pull/1536)
+- Added a new `\Hyde\Framework\Exceptions\InvalidConfigurationException` exception class to handle invalid configuration exceptions in [#1799](https://github.com/hydephp/develop/pull/1799)
+- Added a new `\Hyde\Framework\Exceptions\ParseException` exception class to handle parsing exceptions in data collection files in [#1732](https://github.com/hydephp/develop/pull/1732)
+- Added a new simplified blog post image front matter schema using a new "caption" field in [#2175](https://github.com/hydephp/develop/pull/2175)
+- Added environment variable support for saving previews in [#1996](https://github.com/hydephp/develop/pull/1996)
+- Added new `npm run build` command for compiling frontend assets with Vite in [#2010](https://github.com/hydephp/develop/pull/2010)
+- Added support for PHP 8.4 in [#2141](https://github.com/hydephp/develop/pull/2141)
+- Added support for resolving dynamic links to source files in Markdown documents in [#1590](https://github.com/hydephp/develop/pull/1590)
+- Added support for setting `booting()` and `booted()` callbacks in `HydeExtension` classes, allowing extension developers to hook into the kernel boot process more easily in [#1847](https://github.com/hydephp/develop/pull/1847)
+- Added support for setting custom navigation items in the YAML configuration in [#1818](https://github.com/hydephp/develop/pull/1818)
+- Added support for setting extra attributes for navigation items in [#1824](https://github.com/hydephp/develop/pull/1824)
+- Added support for setting the blog post publishing date as a prefix in the source file name in [#2000](https://github.com/hydephp/develop/pull/2000)
+- Added support for specifying features in the YAML configuration in [#1896](https://github.com/hydephp/develop/pull/1896)
+- Introduced a new navigation config builder class to simplify navigation configuration in [#1827](https://github.com/hydephp/develop/pull/1827)
+- Markdown headings are now compiled using our custom Blade-based heading renderer in [#2047](https://github.com/hydephp/develop/pull/2047) - The `id` attributes for heading permalinks have been moved from the anchor to the heading element in [#2052](https://github.com/hydephp/develop/pull/2052)
+- The `\Hyde\Facades\Features` class is no longer marked as internal, and is now thus part of the public API in [#1647](https://github.com/hydephp/develop/pull/1647)
+- The `publish:views` command is now interactive on Unix-like systems in [#2062](https://github.com/hydephp/develop/pull/2062)
+- You can now add custom posts to the blog post feed component when including it directly in [#1893](https://github.com/hydephp/develop/pull/1893)
+- You can now specify sidebar item priorities by adding a numeric prefix to documentation page source file names in [#1709](https://github.com/hydephp/develop/pull/1709)
### Changed
-- for changes in existing functionality.
-### Deprecated
-- for soon-to-be removed features.
+- **Breaking:** Renamed class `DataCollections` to `DataCollection` in [#1732](https://github.com/hydephp/develop/pull/1732) For more information, see below.
+- **Breaking:** Renamed the `hyde.enable_cache_busting` configuration option to `hyde.cache_busting` in [#1980](https://github.com/hydephp/develop/pull/1980)
+- **Breaking:** Renamed the `hyde.navigation.subdirectories` configuration option to `hyde.navigation.subdirectory_display` in [#1818](https://github.com/hydephp/develop/pull/1818)
+- **Breaking:** Replaced `--run-dev` and `--run-prod` build command flags with a single `--run-vite` flag that uses Vite to build assets in [#2013](https://github.com/hydephp/develop/pull/2013)
+- **Breaking:** The `Author::create()` method now returns an array instead of a `PostAuthor` instance in [#1798](https://github.com/hydephp/develop/pull/1798) For more information, see below.
+- **Breaking:** The `Author::get()` method now returns `null` if an author is not found, rather than creating a new instance in [#1798](https://github.com/hydephp/develop/pull/1798) For more information, see below.
+- **Breaking:** The `hyde.authors` config setting should now be keyed by the usernames in [#1782](https://github.com/hydephp/develop/pull/1782) For more information, see below.
+- **Breaking:** The `hyde.features` configuration format has changed to use Enums instead of static method calls in [#1649](https://github.com/hydephp/develop/pull/1649) For more information, see below.
+- **Breaking:** The custom navigation item configuration now uses array inputs instead of the previous format in [#1818](https://github.com/hydephp/develop/pull/1818) For more information, see the upgrade guide below.
+- **Breaking:** The navigation system internals have been rewritten into a new Navigation API in [#1568](https://github.com/hydephp/develop/pull/1568) This change is breaking for custom navigation implementations. For more information, see below.
+- **Breaking:** We now support PHP 8.2–8.4 instead of 8.1–8.3 in [#2141](https://github.com/hydephp/develop/pull/2141)
+- **Breaking:** We switched from using CJS to ESM in the frontend tool scaffolding. If you have custom script includes you need to migrate them. See below and the pull request for details in [#2159](https://github.com/hydephp/develop/pull/2159)
+- **Breaking:** We upgraded from the TailwindCSS version from v3 to v4 in [#2146](https://github.com/hydephp/develop/pull/2146) You may want to run `npx @tailwindcss/upgrade` in your project if you have custom Tailwind classes in your project. See the information below for details.
+- **Dependency:** Switched to forked version of the Torchlight client in [#2141](https://github.com/hydephp/develop/pull/2141)
+- **Dependency:** Updated Symfony/yaml to ^7.0 in [#2141](https://github.com/hydephp/develop/pull/2141)
+- **Dependency:** Updated illuminate/support and illuminate/view to ^11.0 in [#2141](https://github.com/hydephp/develop/pull/2141)
+- **Dependency:** Updated minimum PHP requirement to 8.2 in [#2141](https://github.com/hydephp/develop/pull/2141)
+- **Dependency:** Upgraded from Laravel 10 to Laravel 11 in [#2141](https://github.com/hydephp/develop/pull/2141)
+- **Medium:** The `route` function will now throw a `RouteNotFoundException` if the route does not exist in [#1741](https://github.com/hydephp/develop/pull/1741)
+- **Minor:** Changed the default build task message to make it more concise in [#1659](https://github.com/hydephp/develop/pull/1659)
+- **Minor:** Data collection files are now validated for syntax errors during discovery in [#1732](https://github.com/hydephp/develop/pull/1732)
+- **Minor:** Due to changes in the navigation system, it is possible that existing configuration files will need to be adjusted in order for menus to look the same (in terms of ordering etc.)
+- **Minor:** Methods in the `Includes` facade now return `HtmlString` objects instead of `string` in [#1738](https://github.com/hydephp/develop/pull/1738) For more information, see below.
+- **Minor:** Navigation menu items are now no longer filtered by duplicates (meaning two items with the same label can now exist in the same menu) in [#1573](https://github.com/hydephp/develop/pull/1573)
+- **Minor:** The `processing_time_ms` attribute in the `sitemap.xml` file has now been removed in [#1744](https://github.com/hydephp/develop/pull/1744)
+- **Minor:** The documentation article component now supports disabling the semantic rendering using a falsy value in [#1566](https://github.com/hydephp/develop/pull/1566)
+- **Minor:** Updated the `Hyde::url()` helper throw a `BadMethodCallException` instead `BaseUrlNotSetException` when no site URL is set and no path was provided to the method in [#1890](https://github.com/hydephp/develop/pull/1890)
+- **Minor:** Updated the blog post layout and post feed component to use the `BlogPosting` Schema.org type instead of `Article` in [#1887](https://github.com/hydephp/develop/pull/1887)
+- **Minor:** `Includes::path()` and `Includes::get()` methods now normalize paths to be basenames to match the behavior of the other include methods in [#1738](https://github.com/hydephp/develop/pull/1738) This means that nested directories are no longer supported, as you should use a data collection for these
+- Added more rich markup data to blog post components in [#1888](https://github.com/hydephp/develop/pull/1888) (Note that this inevitably changes the HTML output of the blog post components, and that any customized templates will need to be republished to reflect these changes)
+- Calling the `DataCollection` methods will no longer create the data collections directory in [#1732](https://github.com/hydephp/develop/pull/1732)
+- Calling the `Include::path()` method will no longer create the includes directory in [#1707](https://github.com/hydephp/develop/pull/1707)
+- Changed how the documentation search is generated, to be an `InMemoryPage` instead of a post-build task in [#1498](https://github.com/hydephp/develop/pull/1498)
+- Colored Markdown blockquotes are now rendered using Blade and TailwindCSS in [#2056](https://github.com/hydephp/develop/pull/2056) This change is not visible in the rendered result, but the HTML output has changed
+- Extracted CSS component partials in HydeFront in [#2038](https://github.com/hydephp/develop/pull/2038)
+- Improved how the `MarkdownService` class is accessed by binding it into the service container in [#1922](https://github.com/hydephp/develop/pull/1922)
+- Improved the media asset transfer build task to have better output in [#1904](https://github.com/hydephp/develop/pull/1904)
+- Improved the sitemap data generation to be smarter and more dynamic in [#1744](https://github.com/hydephp/develop/pull/1744)
+- Markdown includes are now converted to HTML using the custom HydePHP Markdown service, meaning they now support full GFM spec and custom Hyde features like colored blockquotes and code block filepath labels in [#1738](https://github.com/hydephp/develop/pull/1738)
+- Markdown returned from includes are now trimmed of trailing whitespace and newlines in [#1738](https://github.com/hydephp/develop/pull/1738)
+- Media asset files are now copied using the new build task instead of the deprecated `BuildService::transferMediaAssets()` method in [#2024](https://github.com/hydephp/develop/pull/2024)
+- Moved Blade view `hyde::pages.documentation-search` to `hyde::pages.docs.search` in [#2033](https://github.com/hydephp/develop/pull/2033)
+- Moved the Vite build step to run before the site build to prevent duplicate media asset transfers in [#2013](https://github.com/hydephp/develop/pull/2013)
+- Moved the sidebar documentation to the documentation pages section for better organization
+- Normalized default Tailwind Typography Prose code block styles to match Torchlight's theme, ensuring consistent styling across Markdown and Torchlight code blocks in [#2036](https://github.com/hydephp/develop/pull/2036)
+- Overhauled the blog post author feature in [#1782](https://github.com/hydephp/develop/pull/1782)
+- Renamed the parameter `category` to `group` in the `publish:views` command in [#2166](https://github.com/hydephp/develop/pull/2166)
+- Reorganized and cleaned up the navigation and sidebar documentation for improved clarity
+- Replaced HydeFront styles with Tailwind in [#2024](https://github.com/hydephp/develop/pull/2024)
+- Skipped build tasks will now exit with an exit code of 3 instead of 0 in [#1749](https://github.com/hydephp/develop/pull/1749)
+- The `Markdown::render()` method will now always render Markdown using the custom HydePHP Markdown service (thus getting smart features like our Markdown processors) in [#1900](https://github.com/hydephp/develop/pull/1900)
+- The `hasFeature` method on the Hyde facade and HydeKernel now only accepts a Feature enum value instead of a string for its parameter in [#1650](https://github.com/hydephp/develop/pull/1650)
+- The build command now groups together all `InMemoryPage` instances under one progress bar group in [#1897](https://github.com/hydephp/develop/pull/1897)
+- The full page documentation search now generates its heading using smarter natural language processing based on the configured sidebar header in [#2032](https://github.com/hydephp/develop/pull/2032)
+- The realtime compiler now only serves assets from the media source directory (`_media`), and no longer checks the site output directory (`_site/media`) in [#2012](https://github.com/hydephp/develop/pull/2012)
+- Updated default configuration to no longer save previewed pages in [#1995](https://github.com/hydephp/develop/pull/1995)
+
+### Fixed
+
+- Added missing collection key types in Hyde facade method annotations in [#1784](https://github.com/hydephp/develop/pull/1784)
+- The `app.css` file will no longer be copied to the media output directory when app styles are configured to be loaded from a CDN in [#2180](https://github.com/hydephp/develop/pull/2180)
+- The `app.js` file will now only be compiled if it has scripts in [#2028](https://github.com/hydephp/develop/pull/2028)
### Removed
-- for now removed features.
-### Fixed
-- for any bug fixes.
+- Added missing collection key types in Hyde facade method annotations in [#1784](https://github.com/hydephp/develop/pull/1784)
+- The `app.css` file will no longer be copied to the media output directory when app styles are configured to be loaded from a CDN in [#2180](https://github.com/hydephp/develop/pull/2180)
+- The `app.js` file will now only be compiled if it has scripts in [#2028](https://github.com/hydephp/develop/pull/2028)
+
+### Package updates
+
+#### Realtime Compiler
+
+- Simplified the asset file locator to only serve files from the media source directory in https://github.com/hydephp/develop/pull/2012
+- Added Vite HMR support in https://github.com/hydephp/develop/pull/2016
+
+#### HydeFront
+
+- Removed all Sass styles after porting everything to Tailwind in https://github.com/hydephp/develop/pull/2024
+- Removed the `hyde.css` file in https://github.com/hydephp/develop/pull/2037 as all its styles were refactored to Tailwind in https://github.com/hydephp/develop/pull/2024
+- Extracted CSS component partials in https://github.com/hydephp/develop/pull/2038
+
+### Upgrade Guide
+
+Please see the "Breaking changes & upgrade guide" section below for more information.
+
+## Breaking changes & upgrade guide
+
+
+
+Please read through this section to ensure your site upgrades smoothly.
+
+## Before you start
+
+Before you start, please upgrade your application to at least HydePHP v1.6 as that version contains helpers to make the upgrade process easier.
+
+## TailwindCSS v4
+
+We upgraded the TailwindCSS version from v3 to v4. If you have written custom markup with Tailwind classes you should read the Tailwind v4 [Upgrade Guide](https://tailwindcss.com/docs/upgrade-guide#changes-from-v3) so you know which breaking changes were introduced. Thankfully, the team behind Tailwind provide an automated [Upgrade Tool](https://tailwindcss.com/docs/upgrade-guide#using-the-upgrade-tool). Run it with the following command:
+
+```bash
+$ npx @tailwindcss/upgrade
+```
+
+## High impact
+
+### Switch frontend tooling to full ESM support
+
+The frontend tooling has been switched from CommonJS to ESM. This means that all JavaScript files are now ESM modules, and you will need to update your custom scripts to use ESM syntax.
+
+If you only used the default HydePHP frontend (without custom JavaScript), no action is needed. Otherwise, please read the upgrade guide here: https://github.com/hydephp/develop/pull/2159
+
+### Navigation system rewrite
+
+The navigation system has been rewritten into a new Navigation API. This change is breaking for custom navigation implementations, see more down below.
+
+For most users, the only impact will be that configuration files need to be updated to use the new configuration format. Due to the internal changes,
+it's also possible that menu items will be in a slightly different order than before, depending on your setup. Please verify that your site's menus
+look as expected after upgrading, and adjust the configuration files if necessary, before deploying to production.
+
+### Navigation and sidebar configuration changes
+
+The navigation and sidebar configuration files have been updated to use the new Navigation API.
+This means that you will need to update your configuration files to use the new format.
+
+The easiest way to upgrade is to publish updated configuration files (`hyde.php` and `docs.php`) and copy over your customizations.
+
+The following configuration entries have been updated:
+
+- Changed configuration option `docs.sidebar_order` to `docs.sidebar.order` in https://github.com/hydephp/develop/pull/1583
+- Upgrade path: Move the `sidebar_order` option's array in the `config/docs.php` file into the `sidebar` array in the same file.
+
+- Changed configuration option `docs.table_of_contents` to `docs.sidebar.table_of_contents` in https://github.com/hydephp/develop/pull/1584
+- Upgrade path: Move the `table_of_contents` option's array in the `config/docs.php` file into the `sidebar` array in the same file.
+
+### Features configuration changes
+
+The `hyde.features` configuration format has changed to use Enums instead of static method calls. This change is breaking as it will require you to update your `config/hyde.php` file.
+
+#### Instead of
+
+```php
+// filepath: config/hyde.php
+
+'features' => [
+ // Page Modules
+ Features::htmlPages(),
+ Features::markdownPosts(),
+ Features::bladePages(),
+ Features::markdownPages(),
+ Features::documentationPages(),
+
+ // Frontend Features
+ Features::darkmode(),
+ Features::documentationSearch(),
+
+ // Integrations
+ Features::torchlight(),
+],
+```
+
+#### Use instead
+
+```php
+// filepath: config/hyde.php
+
+'features' => [
+ // Page Modules
+ Feature::HtmlPages,
+ Feature::MarkdownPosts,
+ Feature::BladePages,
+ Feature::MarkdownPages,
+ Feature::DocumentationPages,
+
+ // Frontend Features
+ Feature::Darkmode,
+ Feature::DocumentationSearch,
+
+ // Integrations
+ Feature::Torchlight,
+],
+```
+
+Of course, if you have disabled any of the features, do not include them in the new array.
+
+## General impact
+
+### Post Author changes
+
+This release makes major improvements to the usability and design of the blog post author feature.
+
+Here is the full list of changes:
+
+- Breaking: The `hyde.authors` config setting must now be keyed by the usernames, instead of providing the username in the author facade constructor.
+- Breaking: The `Author::create()` method now returns an array instead of a `PostAuthor` instance. This only affects custom code that uses the `Author` facade.
+- Breaking: The `Author::get()` method now returns `null` if an author is not found, rather than creating a new instance. This only affects custom code that uses the `Author` facade.
+- Removed: The deprecated `PostAuthor::getName()` method has been removed (use `$author->name` instead).
+- Changed: Author usernames are now automatically normalized (converted to lowercase and spaces replaced with underscores in order to ensure URL routability).
+- Changed: If an author display name is not provided, it is now intelligently generated from the username.
+- Feature: Authors can now be set in the YAML configuration.
+- Feature: Added a `$author->getPosts()` method to get all of an author's posts.
+- Feature: Authors now support custom biographies, avatars, and social media links. Note that these are not currently used in any of the default templates, but you can use them in your custom views.
+- The collection of site authors is now stored in the HydeKernel, meaning authors can be accessed through `Hyde::authors()`.
+- The `PostAuthor` class is now Arrayable and JsonSerializable.
+
+#### Upgrade guide:
+
+1. Update your `config/hyde.php` file to use the new author configuration format:
+
+ ```php
+ 'authors' => [
+ 'username' => Author::create(
+ name: 'Display Name',
+ website: 'https://example.com',
+ bio: 'Author bio',
+ avatar: 'avatar.png',
+ socials: ['twitter' => '@username']
+ ),
+ ],
+ ```
+
+2. Review and update any code that uses the `Author` facade:
+
+- The `create()` method now returns an array instead of a `PostAuthor` instance.
+- The `get()` method may return `null`, so handle this case in your code.
+
+3. Check your blog post front matter and ensure that `author` fields match the new username keys in your configuration.
+
+4. If you have custom templates that use author data, update them to:
+
+- Optional: Feel free to use the new available fields: `bio`, `avatar`, and `socials`.
+- Account for usernames now being lowercase with underscores which may lead to changed HTML or URL paths.
+
+5. If you were relying on `Author::get()` to create new authors on the fly, update your code to handle `null` returns or create authors explicitly.
+
+For more information, see https://github.com/hydephp/develop/pull/1782 and https://github.com/hydephp/develop/pull/1798
+
+### Documentation search page changes
+
+The documentation search page and search index have been changed to be generated as `InMemoryPages` instead of a post-build task.
+
+The main impact noticeable to most users by this is the implicit changes, like the pages showing up in the dashboard and route list command.
+
+In case you have customized the `GenerateSearch` post-build task you may, depending on what you were trying to do,
+want to adapt your code to interact with the new `InMemoryPage`, which is generated in the `HydeCoreExtension` class.
+
+For more information, see https://github.com/hydephp/develop/pull/1498.
+
+## Medium impact
+
+### Features class method renames
+
+The following methods in the `Features` class have been renamed to follow a more consistent naming convention:
+
+- `Features::enabled()` has been renamed to `Features::has()`
+- `Features::sitemap()` has been renamed to `Features::hasSitemap()`
+- `Features::rss()` has been renamed to `Features::hasRss()`
+
+Note that this class was previously marked as internal in v1, but the change is logged here in case it was used in configuration files or custom code.
+
+### Asset API Changes
+
+#### Overview
+
+For most end users, the changes to the Asset API in HydePHP 2.x will have minimal direct impact. However, if you have custom code that interacts with media files, you may need to update it.
+
+The most important thing to note is that all asset retrieval methods now return a `MediaFile` instance, which can be fluently interacted with, or cast to a string to get the link (which was the previous behavior).
+
+#### Side effects to consider
+
+Regardless of if you need to make changes to your code, there are a few side effects to consider:
+
+- All cache busting keys will have changed since we changed the hashing algorithm from `MD5` to `CRC32`.
+- Media file getters now return MediaFile instances instead of strings. But these can still be used the same way in Blade `{{ }}` tags, as they can be cast to strings.
+- Due to the internal normalizations, we will consistently use cache busting keys and use qualified paths when site URLs are set.
+- An exception will be thrown if you try to get a media file that does not exist in order to prevent missing assets from going unnoticed.
+
+These side effects should not have any negative impact on your site, but may cause the generated HTML to look slightly different.
+
+#### Impact on Your Code
+
+If you are using strict type declarations, you may need to update your code to expect a `MediaFile` instance instead of a string path; or you should cast the `MediaFile` instance to a string when needed.
+
+Most changes were made in https://github.com/hydephp/develop/pull/1904 which contains extra information and the reasoning behind the changes.
+
+#### Updating Your Code
+
+Once you have determined that you need to update your code, here are the steps you should take:
+
+1. Update calls to renamed methods:
+
+ ```php
+ // Replace this: With this:
+ Hyde::mediaLink('image.png') => Hyde::asset('image.png');
+ Asset::mediaLink('image.png') => Asset::get('image.png');
+ Asset::hasMediaFile('image.png') => Asset::exists('image.png');
+ Asset::cdnLink('app.css') => HydeFront::cdnLink('app.css');
+ Asset::injectTailwindConfig() => HydeFront::injectTailwindConfig();
+ FeaturedImage::isRemote($source) => Hyperlinks::isRemote($source);
+ ```
+
+2. Rename the option `hyde.enable_cache_busting` to `hyde.cache_busting` in your configuration file.
+
+3. Remove any references to `hyde.hydefront_version` and `hyde.hydefront_cdn_url` in your config files as these options have been removed.
+
+4. If you were using `AssetService` directly, refactor your code to use the new `Asset` facade, `MediaFile` class, or `HydeFront` facade as appropriate.
+
+These changes simplify the Asset API and provide more robust handling of media files. The new `MediaFile` class offers additional functionality for working with assets.
+
+## Low impact
+
+### Navigation internal changes
+
+The navigation system has been rewritten into a new Navigation API. This change is breaking for custom navigation implementations.
+
+If you have previously in your custom code done any of the following, or similar, you will need to adapt your code to use the new Navigation API:
+
+- Created custom navigation menus or Blade components
+- Extended or called the navigation related classes directly
+- Customized the navigation system in any way beyond the standard configuration
+
+#### Upgrade guide
+
+Due to the scope of the rewrite, the easiest and fastest way to upgrade your code is to recreate it using the new Navigation API.
+
+- For a full comparison of the changes, you may see the PR that introduced the new API: https://github.com/hydephp/develop/pull/1568/files
+- For information on how to use the new Navigation API, see the documentation: https://hydephp.com/docs/2.x/navigation-api
+- If you use DataCollections, you should read the upgrade path below as there are breaking changes to the DataCollection API.
+
+### HTML ID changes
+
+Some HTML IDs have been renamed to follow a more consistent naming convention.
+
+If you have used any of the following selectors in custom code you wrote yourself, you will need to update to use the new changed IDs.
+
+#### https://github.com/hydephp/develop/pull/1622
+
+- Rename HTML ID `#searchMenu` to `#search-menu`
+- Rename HTML ID `#searchMenuButton` to `#search-menu-button`
+- Rename HTML ID `#searchMenuButtonMobile` to `#search-menu-button-mobile`
+
+### New documentation search implementation
+
+As the new documentation search implementation brings changes to their code API you may need to adapt your code
+according to the information below in case you wrote custom code that interacted with these parts of the codebase.
+
+- The `GenerateSearch` post-build task has been removed. If you have previously extended or customized this class,
+ you will need to adapt your code, as the search index files are now handled implicitly during the standard build process,
+ as the search pages are now added to the kernel page and route collection. (https://github.com/hydephp/develop/pull/1498)
+
+- If your site has a custom documentation search page, for example `_docs/search.md` or `_pages/docs/search.blade.php`,
+ that page will no longer be built when using the specific `build:search` command. It will, of course,
+ be built using the standard `build` command. https://github.com/hydephp/develop/commit/82dc71f4a0e7b6be7a9f8d822fbebe39d2289ced
+
+- In the highly unlikely event your site customizes any of the search pages by replacing them in the kernel route collection,
+ you would now need to do that in the kernel page collection due to the search pages being generated earlier in the lifecycle.
+ https://github.com/hydephp/develop/commit/82dc71f4a0e7b6be7a9f8d822fbebe39d2289ced
+
+### Media asset transfer implementation changes
+
+The internals of how media asset files are copied during the build process have been changed. For most users, this change
+has no impact. However, if you have previously extended this method, or called it directly from your custom code,
+you will need to adapt your code to use the new `TransferMediaAssets` build task.
+
+For example, if you triggered the media transfer with a build service method call, use the new build task instead:
+
+```php
+(new BuildService)->transferMediaAssets();
+
+(new TransferMediaAssets())->run();
+```
+
+### Includes facade changes
+
+The following methods in the `Includes` facade now return `HtmlString` objects instead of `string`:
+
+- `Includes::html()`
+- `Includes::blade()`
+- `Includes::markdown()`
+
+- This means that you no longer need to use `{!! !!}` to render the output of these methods in Blade templates, instead just use `{{ }}`.
+- If you have used the return value of these methods in custom code, you may need to adjust your code to work with the new return type.
+
+For more information, see the RFC that proposed this change: https://github.com/hydephp/develop/issues/1734
+The RFC was implemented in https://github.com/hydephp/develop/pull/1738
+
+#### Remember to escape output if necessary
+
+**Note:** Remember that this means that includes are **no longer escaped** by default, so make sure to escape the output if necessary, for example if the content is user-generated.
+
+- (Use `{{ e(Includes::html('foo')) }}` instead of `{{ Includes::html('foo') }}` to escape the output, matching the previous behavior.)
+
+### DataCollection API changes
+
+The DataCollection feature has been reworked to improve the developer experience and make it more consistent with the rest of the API.
+
+Unfortunately, this means that existing setups may need to be adjusted to work with the new API.
+
+#### Upgrade guide
+
+- The `DataCollections` class has been renamed to `DataCollection`. If you have used the `DataCollections` class in your code, you will need to update your code to use the new class name.
+
+#### Changes
+
+- Calling the `DataCollection` methods will no longer create the data collections directory automatically.
+- The `DataCollection` class now validates the syntax of all data collection files during discovery, and throws a `ParseException` if the syntax is invalid.
+
+#### Issues that may arise
+
+If you start getting a `ParseException` when using the `DataCollection` class, it may be due to malformed data collection files.
+Starting from this version, we validate the syntax of JSON and YAML in data files during discovery, including any front matter in Markdown data files.
+We do this to help you catch errors early. See https://github.com/hydephp/develop/issues/1736 for more information.
+
+For example, an empty or malformed JSON file will now throw an exception like this:
+
+```php
+\Hyde\Framework\Exceptions\ParseException: Invalid JSON in file: 'foo/baz.json' (Syntax error)
+```
+
+In order to normalize the thrown exceptions, we now rethrow the `ParseException` from `Symfony/Yaml` as our custom `ParseException` to match the JSON and Markdown validation.
+Additionally, an exception will be thrown if a data file is empty, as this is unlikely to be intentional. Markdown files can have an empty body if front matter is present.
+
+### Removal of `FeaturedImage::isRemote()` method
+
+The `FeaturedImage::isRemote()` method has been removed in v2.0. This method was deprecated in v1.8.0 and has now been completely removed.
+
+#### Upgrade guide
+
+If you were using `FeaturedImage::isRemote()` in your code, you should replace it with `Hyperlinks::isRemote()`. Here's how to update your code:
+
+```php
+// Old code
+FeaturedImage::isRemote($source);
+
+// New code
+use Hyde\Foundation\Kernel\Hyperlinks;
+
+Hyperlinks::isRemote($source);
+```
+
+This change was implemented in https://github.com/hydephp/develop/pull/1883. Make sure to update any instances of `FeaturedImage::isRemote()` in your codebase to ensure compatibility with HydePHP v2.0.
+
+### Routes facade API changes
+
+The Routes facade API has been improved to better follow Laravel naming conventions and make the API more intuitive. This change affects code that directly uses the Routes facade methods.
+
+#### Changes
+
+- The `Routes::get()` method has been renamed to `Routes::find()` to better indicate that it may return null if a route is not found
+- The `Routes::getOrFail()` method has been renamed to `Routes::get()` to make the exception-throwing behavior the default, matching Laravel conventions
+
+#### Upgrade guide
+
+If you have used the Routes facade in your custom code, update it as follows:
+
+```php
+// Old code:
+$route = Routes::get('some-route'); // Returns null if not found
+$route = Routes::getOrFail('some-route'); // Throws exception if not found
+
+// New code:
+$route = Routes::find('some-route'); // Returns null if not found
+$route = Routes::get('some-route'); // Throws exception if not found
+```
+
+This change provides more intuitive method names and better type safety, with `find()` returning `?Route` and `get()` returning `Route`.
+
+This change was implemented in https://github.com/hydephp/develop/pull/2179.
+
+## New Asset System
+
+### Abstract
+
+The new asset system is a complete rewrite of the HydeFront asset handling system, replacing Laravel Mix with Vite, and favouring Blade-based components with Tailwind classes over CSS partials and custom stylesheets.
+
+### Enhancements
+
+- **Replaced Laravel Mix with Vite for frontend asset compilation.** ([#2010], [#2011], [#2012], [#2013], [#2016], [#2021])
+ - Bundled assets are now compiled directly into the `_media` folder.
+ - The realtime compiler now only serves assets from the media source directory (`_media`).
+ - Added a new `npm run build` command for compiling frontend assets with Vite.
+ - Added Vite facade for Blade templates.
+ - Added Vite Hot Module Replacement (HMR) support to the realtime compiler.
+ - Build command now uses Vite to compile assets when the `--run-vite` flag is passed.
+
+- **Improved HydeFront integration.** ([#2024], [#2029], [#2031], [#2036], [#2037], [#2038], [#2039])
+ - HydeFront styles are now refactored into Tailwind.
+ - HydeFront now acts as a component library with granular Tailwind styles in `app.css`.
+ - HydeSearch plugin ported to Alpine.js, improving performance and customizability.
+ - Normalized Tailwind Typography Prose code block styles to match Torchlight.
+ - Extracted CSS component partials in HydeFront.
+ - Removed `hyde.css` from HydeFront, as all styles are now included in `app.css`.
+
+- **Implemented a custom Blade-based heading renderer for Markdown.** ([#2047], [#2052])
+ - Improves permalink handling and customization options.
+ - `id` attributes for heading permalinks have been moved from the anchor to the heading element.
+- **Colored Markdown blockquotes are now rendered using Blade and Tailwind CSS.** ([#2056])
+- The `app.js` file will now only be compiled if it has scripts. ([#2028])
+
+
+### Breaking Changes
+
+- Replaced Laravel Mix with Vite. ([#2010])
+ - You must now use `npm run build` to compile your assets, instead of `npm run prod`.
+- Removed `--run-dev` and `--run-prod` build command flags, replaced by `--run-vite`. ([#2013])
+- Removed `DocumentationPage::getTableOfContents()` method. Table of contents are now generated using a Blade component. ([#2045])
+- Removed `hyde.css` from HydeFront, requiring recompilation of assets if you were extending it. ([#2037])
+- Changed how HydeFront is included in projects. Instead of separate `hyde.css` and `app.css`, all styles are now in `app.css`. ([#2024])
+
+
+### Removals
+
+- Removed Laravel Mix as a dependency. ([#2010])
+- Removed `npm run prod` command. ([#2010])
+- Removed CDN include for HydeSearch plugin. ([#2029])
+- Removed the `` and `` Blade components, replaced by ``. ([#2029])
+- Removed the `.torchlight-enabled` CSS class. ([#2036])
+- Removed the `MarkdownService::withPermalinks` and `MarkdownService::canEnablePermalinks` methods. ([#2047])
+
+
+### Blade-based table of contents generator
+
+The way we generate table of contents for documentation pages have been changed from a helper method to a Blade component.
+
+This new system is much easier to customize and style, and is up to 40 times faster than the old system.
+
+See https://github.com/hydephp/develop/pull/2045 for more information.
+
+#### Scope
+
+The likelihood of impact is low, but if any of the following are true, you may need to update your code:
+
+- If you have used the `Hyde\Framework\Actions\GeneratesTableOfContents` class in custom code, you will likely need to update that code for the rewritten class.
+- If you have published the `resources/views/components/docs/sidebar-item.blade.php` component, you will need to update it to call the new component instead of the old generator rendering.
+- If you have called the now removed `getTableOfContents` method of the `DocumentationPage` class in custom code, you will need to update that usage as to possibly call the new Blade component directly, depending on your use case.
+- If you have called the now removed `hasTableOfContents` method of the `DocumentationPage` class in custom code you will need to replace the method call with `Config::getBool('docs.sidebar.table_of_contents.enabled', true)`
+
+#### Changes
+- Adds a new `resources/views/components/docs/table-of-contents.blade.php` component containing the structure and styles for the table of contents
+- Rewrites the `GeneratesTableOfContents` class to use a custom implementation instead of using CommonMark
+- The `execute` method of the `GeneratesTableOfContents` class now returns an array of data, instead of a string of HTML. This data should be fed into the new component
+- Removed the `table-of-contents.css` file as styles are now made using Tailwind
+- Removed the `heading-permalinks.css` file as styles are now made using Tailwind
+- Removed the `blockquotes.css` file as styles are now made using Tailwind
+
+## New features
+
+
+
+### Navigation configuration changes
+
+The custom navigation item configuration format has been updated to use array inputs. This change allows for more flexibility and consistency in defining navigation items.
+
+#### Old format:
+
+```php
+'navigation' => [
+ 'custom_items' => [
+ 'Custom Item' => '/custom-page',
+ ],
+],
+```
+
+#### New format:
+
+```php
+'navigation' => [
+ 'custom_items' => [
+ ['label' => 'Custom Item', 'destination' => '/custom-page'],
+ ],
+],
+```
+
+Additionally, the `hyde.navigation.subdirectories` configuration option has been renamed to `hyde.navigation.subdirectory_display`. Update your configuration files accordingly.
+
+### YAML configuration for navigation items
+
+You can now set custom navigation items directly in your YAML configuration files. This provides an alternative to defining them in the PHP configuration files.
+
+Example:
+
+```yaml
+navigation:
+ custom_items:
+ - label: Custom Item
+ destination: /custom-page
+```
+
+### Extra attributes for navigation items
+
+Navigation items now support extra attributes, allowing you to add custom data or styling to your navigation elements. You can set these attributes in both PHP and YAML configurations.
+
+Example in PHP:
+
+```php
+'navigation' => [
+ 'custom_items' => [
+ [
+ 'label' => 'Custom Item',
+ 'destination' => '/custom-page',
+ 'attributes' => ['class' => 'special-link', 'target' => '_blank'],
+ ],
+ ],
+],
+```
+
+Example in YAML:
+
+```yaml
+navigation:
+ custom_items:
+ - label: Custom Item
+ destination: /custom-page
+ attributes:
+ class: special-link
+ target: _blank
+```
-### Security
-- in case of vulnerabilities.
+These changes provide more flexibility and control over your site's navigation structure. Make sure to update your configuration files and any custom code that interacts with navigation items to align with these new formats and features.
diff --git a/SECURITY.md b/SECURITY.md
index a155f70d1d5..5c325d806cd 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -6,7 +6,8 @@ These are the version ranges of HydePHP, and their support status. We follow [Se
| Version | Supported | Classification |
|---------|--------------------|----------------------|
-| 1.x LTS | :white_check_mark: | General Availability |
+| 2.x | :white_check_mark: | General Availability |
+| 1.x LTS | :white_check_mark: | Long Term Support |
| < 0.64 | :x: | Beta |
| < 0.8 | :x: | Alpha |
diff --git a/_ide_helper.php b/_ide_helper.php
index 7d868d7bbb5..88203364b33 100644
--- a/_ide_helper.php
+++ b/_ide_helper.php
@@ -22,20 +22,25 @@
/** @var string $routeKey The route key for the page being compiled/previewed */
$routeKey = \Hyde\Support\Facades\Render::getRouteKey();
+// Variables available only to some page types
+
+/** @var \Hyde\Framework\Features\Navigation\DocumentationSidebar $sidebar */
+$sidebar = app('navigation.sidebar');
+
// Facades (aliased in app/config.php)
/** @mixin \Hyde\Foundation\HydeKernel */
class Hyde extends \Hyde\Hyde {}
class Site extends \Hyde\Facades\Site {}
class Meta extends \Hyde\Facades\Meta {}
-/** @mixin \Hyde\Framework\Services\AssetService */
class Asset extends \Hyde\Facades\Asset {}
class Author extends \Hyde\Facades\Author {}
class Features extends \Hyde\Facades\Features {}
class Config extends \Hyde\Facades\Config {}
+class Vite extends \Hyde\Facades\Vite {}
/** @mixin \Illuminate\Filesystem\Filesystem */
class Filesystem extends \Hyde\Facades\Filesystem {}
-class DataCollections extends \Hyde\Support\DataCollections {}
+class DataCollection extends \Hyde\Support\DataCollection {}
class Includes extends \Hyde\Support\Includes {}
/** @mixin \Hyde\Foundation\Kernel\RouteCollection */
class Routes extends \Hyde\Foundation\Facades\Routes {}
diff --git a/_media/app.css b/_media/app.css
index 157650ea21f..f4bbbd9907e 100644
--- a/_media/app.css
+++ b/_media/app.css
@@ -1,4 +1 @@
-/*! HydeFront v3.4.1 | MIT License | https://hydephp.com*/.hyde-search-context{margin-bottom:10px}.hyde-search-results{margin-top:1.25em;max-height:60vh;overflow-y:auto}#search-status{margin-top:0}#sidebar-toggle{display:inline-block;height:2rem;position:relative;width:2rem}#sidebar-toggle span.icon-bar{background-color:#000;display:block;height:2.375px;left:5.5px;position:absolute;transition:all .3s ease-out;width:20px}#sidebar-toggle span.icon-bar:first-child{top:9px}#sidebar-toggle span.icon-bar:nth-child(2),#sidebar-toggle span.icon-bar:nth-child(3){top:15px;transform-origin:center}#sidebar-toggle span.icon-bar:last-child{top:21px}#sidebar-toggle.active span.icon-bar:first-child{opacity:0}#sidebar-toggle.active span.icon-bar:nth-child(2){transform:rotate(45deg)}#sidebar-toggle.active span.icon-bar:nth-child(3){transform:rotate(-45deg)}#sidebar-toggle.active span.icon-bar:last-child{opacity:0}.dark #sidebar-toggle span.icon-bar{background-color:#fff;height:2px}.table-of-contents{padding-bottom:.75rem}.table-of-contents>li{margin-bottom:.35rem;margin-top:.15rem}.table-of-contents ul{padding-left:.5rem}.table-of-contents a{display:block;margin-left:-2rem;opacity:.825;padding-left:2rem}.table-of-contents a:before{content:"#";font-size:75%;margin-right:4px;opacity:.5;transition:opacity .3s ease-in-out}.table-of-contents a:hover{background-color:hsla(0,0%,50%,.2);opacity:1;transition:opacity,background .3s ease-in-out}.table-of-contents a:hover:before{opacity:1}#hyde-docs .prose h1,#hyde-docs .prose h2,#hyde-docs .prose h3,#hyde-docs .prose h4,#hyde-docs .prose h5,#hyde-docs .prose h6{width:-moz-fit-content;width:fit-content}#hyde-docs .prose h1:focus .heading-permalink,#hyde-docs .prose h1:hover .heading-permalink,#hyde-docs .prose h2:focus .heading-permalink,#hyde-docs .prose h2:hover .heading-permalink,#hyde-docs .prose h3:focus .heading-permalink,#hyde-docs .prose h3:hover .heading-permalink,#hyde-docs .prose h4:focus .heading-permalink,#hyde-docs .prose h4:hover .heading-permalink,#hyde-docs .prose h5:focus .heading-permalink,#hyde-docs .prose h5:hover .heading-permalink,#hyde-docs .prose h6:focus .heading-permalink,#hyde-docs .prose h6:hover .heading-permalink{filter:grayscale(100%);opacity:.75;transition:opacity .1s ease-out}#hyde-docs .prose h1 .heading-permalink,#hyde-docs .prose h2 .heading-permalink,#hyde-docs .prose h3 .heading-permalink,#hyde-docs .prose h4 .heading-permalink,#hyde-docs .prose h5 .heading-permalink,#hyde-docs .prose h6 .heading-permalink{margin-left:.25rem;opacity:0;padding:0 .25rem;scroll-margin:1rem;transition:opacity .3s ease}#hyde-docs .prose h1 .heading-permalink:before,#hyde-docs .prose h2 .heading-permalink:before,#hyde-docs .prose h3 .heading-permalink:before,#hyde-docs .prose h4 .heading-permalink:before,#hyde-docs .prose h5 .heading-permalink:before,#hyde-docs .prose h6 .heading-permalink:before{content:"#"}#hyde-docs .prose h1 .heading-permalink:focus,#hyde-docs .prose h1 .heading-permalink:hover,#hyde-docs .prose h2 .heading-permalink:focus,#hyde-docs .prose h2 .heading-permalink:hover,#hyde-docs .prose h3 .heading-permalink:focus,#hyde-docs .prose h3 .heading-permalink:hover,#hyde-docs .prose h4 .heading-permalink:focus,#hyde-docs .prose h4 .heading-permalink:hover,#hyde-docs .prose h5 .heading-permalink:focus,#hyde-docs .prose h5 .heading-permalink:hover,#hyde-docs .prose h6 .heading-permalink:focus,#hyde-docs .prose h6 .heading-permalink:hover{filter:unset;opacity:1}html{scroll-behavior:smooth}.torchlight-enabled pre{border-radius:.25rem;margin-bottom:1rem;margin-top:1rem;overflow-x:auto;padding:0}.torchlight-enabled pre code.torchlight{display:block;min-width:-moz-max-content;min-width:max-content;padding-bottom:1rem;padding-top:1rem}.torchlight-enabled pre code.torchlight .line{padding-left:1rem;padding-right:1rem}.torchlight-enabled pre code.torchlight .line-number,.torchlight-enabled pre code.torchlight .summary-caret{margin-right:1rem}.prose blockquote.info{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.prose blockquote.success{--tw-border-opacity:1;border-color:rgb(34 197 94/var(--tw-border-opacity,1))}.prose blockquote.warning{--tw-border-opacity:1;border-color:rgb(245 158 11/var(--tw-border-opacity,1))}.prose blockquote.danger{--tw-border-opacity:1;border-color:rgb(220 38 38/var(--tw-border-opacity,1))}code{max-width:80vw;overflow-x:auto;vertical-align:top;word-break:break-all}pre code{display:block;max-width:unset}pre>code>.filepath{float:right;opacity:.5;position:relative;right:.25rem;top:-.25rem;transition:opacity .25s}pre>code>.filepath:hover{opacity:1}.torchlight-enabled pre>code>.filepath{right:1rem}@media screen and (max-width:767px){pre>code>.filepath{display:none}}@media screen and (min-width:768px){[x-cloak].x-uncloak-md{display:revert!important}}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}
-*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }
-
-/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}:host,html{-webkit-text-size-adjust:100%;font-feature-settings:normal;-webkit-tap-highlight-color:transparent;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-feature-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em;font-variation-settings:normal}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:96ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:#5956eb;font-weight:500;text-decoration:none}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)):hover{color:#4f46e5}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:3em;margin-top:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:#80808020;border-inline-start-color:var(--tw-prose-quote-borders);border-inline-start-width:.25rem;border-left-color:#d1d5db;color:unset;font-style:unset;font-weight:500;line-height:1.25em;margin-bottom:1em;margin-top:1em;padding-bottom:.25em;padding-inline-start:1em;padding-left:.75em;padding-top:.25em;quotes:"\201C""\201D""\2018""\2019"}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p{margin-bottom:.25em;margin-top:.25em;padding-right:.25em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p:before{content:unset}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p:after{content:unset}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-weight:800;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-weight:700;line-height:1.3333333;margin-bottom:.75em;margin-top:1.5em}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-weight:600;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-bottom:2em;margin-top:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows)/10%);color:var(--tw-prose-kbd);font-family:inherit;font-size:.875em;font-weight:500;padding-inline-end:.375em;padding-bottom:.1875em;padding-top:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:#80808033;border-radius:4px;color:var(--tw-prose-code);font-size:.875em;font-weight:600;font:unset;margin-left:-2px;margin-right:1px;padding-left:4px;padding-right:4px}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:unset}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:unset}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;color:var(--tw-prose-pre-code);font-size:.875em;font-weight:400;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;overflow-x:auto;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-top:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)) code{font-family:Fira Code Regular,Consolas,Monospace,Courier New}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-bottom:2em;margin-top:2em;table-layout:auto;width:100%}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em;vertical-align:bottom}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:17 24 39;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.5em}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-top:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.-left-64{left:-16rem}.bottom-0{bottom:0}.bottom-4{bottom:1rem}.left-0{left:0}.left-80{left:20rem}.right-0{right:0}.right-4{right:1rem}.top-0{top:0}.top-16{top:4rem}.top-4{top:1rem}.top-auto{top:auto}.z-10{z-index:10}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.float-right{float:right}.float-left{float:left}.m-2{margin:.5rem}.m-8{margin:2rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.mx-0{margin-left:0;margin-right:0}.mx-3{margin-left:.75rem;margin-right:.75rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-8{margin-left:2rem;margin-right:2rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-bottom:0;margin-top:0}.my-1{margin-bottom:.25rem;margin-top:.25rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-3{margin-bottom:.75rem;margin-top:.75rem}.my-4{margin-bottom:1rem;margin-top:1rem}.my-8{margin-bottom:2rem;margin-top:2rem}.my-auto{margin-bottom:auto;margin-top:auto}.-mb-2{margin-bottom:-.5rem}.-ml-2{margin-left:-.5rem}.-ml-4{margin-left:-1rem}.-ml-6{margin-left:-1.5rem}.-ml-8{margin-left:-2rem}.mb-0{margin-bottom:0}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-8{margin-bottom:2rem}.ml-4{margin-left:1rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-4{margin-right:1rem}.mr-auto{margin-right:auto}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.block{display:block}.inline{display:inline}.flex{display:flex}.contents{display:contents}.hidden{display:none}.h-0{height:0}.h-1{height:.25rem}.h-16{height:4rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-8{height:2rem}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[75vh\]{max-height:75vh}.min-h-\[300px\]{min-height:300px}.min-h-\[calc\(100vh_-_4rem\)\]{min-height:calc(100vh - 4rem)}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-16{width:4rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-\[70ch\]{width:70ch}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-screen{width:100vw}.max-w-3xl{max-width:48rem}.max-w-7xl{max-width:80rem}.max-w-\[1000px\]{max-width:1000px}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-sm{max-width:24rem}.max-w-xs{max-width:20rem}.flex-shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-auto{cursor:auto}.cursor-pointer{cursor:pointer}.list-none{list-style-type:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-hidden{overflow-y:hidden}.whitespace-nowrap{white-space:nowrap}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border-2{border-width:2px}.border-4{border-width:4px}.border-y{border-top-width:1px}.border-b,.border-y{border-bottom-width:1px}.border-b-4{border-bottom-width:4px}.border-l-4{border-left-width:4px}.border-l-\[0\.325rem\]{border-left-width:.325rem}.border-t{border-top-width:1px}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity,1))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.border-indigo-400{--tw-border-opacity:1;border-color:rgb(129 140 248/var(--tw-border-opacity,1))}.border-indigo-500{--tw-border-opacity:1;border-color:rgb(89 86 235/var(--tw-border-opacity,1))}.border-transparent{border-color:transparent}.border-yellow-400{--tw-border-opacity:1;border-color:rgb(250 204 21/var(--tw-border-opacity,1))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-black\/5{background-color:rgba(0,0,0,.05)}.bg-black\/50{background-color:rgba(0,0,0,.5)}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-cover{background-size:cover}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.bg-no-repeat{background-repeat:no-repeat}.fill-black{fill:#000}.fill-current{fill:currentColor}.p-12{padding:3rem}.p-2{padding:.5rem}.p-4{padding:1rem}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0{padding-bottom:0;padding-top:0}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-12{padding-bottom:3rem;padding-top:3rem}.py-16{padding-bottom:4rem;padding-top:4rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-24{padding-bottom:6rem;padding-top:6rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-32{padding-bottom:8rem;padding-top:8rem}.py-4{padding-bottom:1rem;padding-top:1rem}.py-8{padding-bottom:2rem;padding-top:2rem}.pb-12{padding-bottom:3rem}.pb-3{padding-bottom:.75rem}.pl-2{padding-left:.5rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pl-8{padding-left:2rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-5xl{font-size:3rem;line-height:1}.text-\[90\%\]{font-size:90%}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-light{font-weight:300}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-10{line-height:2.5rem}.leading-4{line-height:1rem}.leading-8{line-height:2rem}.leading-normal{line-height:1.5}.leading-relaxed{line-height:1.625}.tracking-normal{letter-spacing:0}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity,1))}.text-gray-200{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-indigo-500{--tw-text-opacity:1;color:rgb(89 86 235/var(--tw-text-opacity,1))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.text-transparent{color:transparent}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.drop-shadow-2xl{--tw-drop-shadow:drop-shadow(0 25px 25px rgba(0,0,0,.15));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)}.transition-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-300{transition-duration:.3s}.duration-75{transition-duration:75ms}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}[x-cloak]{display:none!important}.dark\:prose-invert:is(.dark *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.dark\:prose-invert:is(.dark *) :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:#818cf8}.dark\:prose-invert:is(.dark *) :where(a):not(:where([class~=not-prose],[class~=not-prose] *)):hover{color:#6366f1}.hover\:bg-black\/10:hover{background-color:rgba(0,0,0,.1)}.hover\:bg-black\/5:hover{background-color:rgba(0,0,0,.05)}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.focus\:not-sr-only:focus{clip:auto;height:auto;margin:0;overflow:visible;padding:0;position:static;white-space:normal;width:auto}.focus\:absolute:focus{position:absolute}.focus\:mx-auto:focus{margin-left:auto;margin-right:auto}.focus\:mt-2:focus{margin-top:.5rem}.focus\:w-64:focus{width:16rem}.focus\:p-2:focus{padding:.5rem}.group:hover .group-hover\:opacity-100{opacity:1}.prose-h1\:mb-3 :is(:where(h1):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:.75rem}.prose-p\:my-3 :is(:where(p):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:.75rem;margin-top:.75rem}.prose-img\:inline :is(:where(img):not(:where([class~=not-prose],[class~=not-prose] *))){display:inline}.dark\:block:is(.dark *){display:block}.dark\:hidden:is(.dark *){display:none}.dark\:border-\[\#1b2533\]:is(.dark *){--tw-border-opacity:1;border-color:rgb(27 37 51/var(--tw-border-opacity,1))}.dark\:border-gray-700:is(.dark *){--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity,1))}.dark\:bg-black\/10:is(.dark *){background-color:rgba(0,0,0,.1)}.dark\:bg-gray-700:is(.dark *){--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}.dark\:bg-gray-900:is(.dark *){--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}.dark\:bg-white:is(.dark *){--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.dark\:fill-gray-200:is(.dark *){fill:#e5e7eb}.dark\:fill-white:is(.dark *){fill:#fff}.dark\:font-medium:is(.dark *){font-weight:500}.dark\:text-gray-100:is(.dark *){--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity,1))}.dark\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity,1))}.dark\:text-indigo-400:is(.dark *){--tw-text-opacity:1;color:rgb(129 140 248/var(--tw-text-opacity,1))}.dark\:text-white:is(.dark *){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.dark\:hover\:bg-black\/10:hover:is(.dark *){background-color:rgba(0,0,0,.1)}.dark\:hover\:text-white:hover:is(.dark *){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.group:hover .dark\:group-hover\:text-white:is(.dark *){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:mb-0{margin-bottom:0}.sm\:mt-4{margin-top:1rem}.sm\:flex{display:flex}.sm\:leading-none{line-height:1}.sm\:shadow-xl{--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}}@media (min-width:768px){.md\:visible{visibility:visible}.md\:left-0{left:0}.md\:left-64{left:16rem}.md\:top-0{top:0}.md\:mx-2{margin-left:.5rem;margin-right:.5rem}.md\:my-0{margin-bottom:0;margin-top:0}.md\:my-6{margin-bottom:1.5rem;margin-top:1.5rem}.md\:mb-12{margin-bottom:3rem}.md\:ml-0{margin-left:0}.md\:mt-0{margin-top:0}.md\:mt-8{margin-top:2rem}.md\:block{display:block}.md\:inline-block{display:inline-block}.md\:flex{display:flex}.md\:hidden{display:none}.md\:min-h-screen{min-height:100vh}.md\:w-1\/2{width:50%}.md\:w-\[calc\(100vw_-_16rem\)\]{width:calc(100vw - 16rem)}.md\:w-auto{width:auto}.md\:max-w-2xl{max-width:42rem}.md\:max-w-none{max-width:none}.md\:flex-grow{flex-grow:1}.md\:flex-grow-0{flex-grow:0}.md\:items-center{align-items:center}.md\:border-none{border-style:none}.md\:bg-transparent{background-color:transparent}.md\:bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.md\:bg-left{background-position:0}.md\:px-16{padding-left:4rem;padding-right:4rem}.md\:py-0{padding-bottom:0;padding-top:0}.md\:py-16{padding-bottom:4rem;padding-top:4rem}.md\:pb-0{padding-bottom:0}.md\:pl-0{padding-left:0}.md\:text-center{text-align:center}.md\:text-3xl{font-size:1.875rem;line-height:2.25rem}.md\:text-4xl{font-size:2.25rem;line-height:2.5rem}.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-6xl{font-size:3.75rem;line-height:1}.md\:shadow-none{--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.dark\:md\:bg-transparent:is(.dark *){background-color:transparent}}@media (min-width:1024px){.lg\:mb-12{margin-bottom:3rem}.lg\:ml-8{margin-left:2rem}.lg\:bg-center{background-position:50%}.lg\:text-5xl{font-size:3rem;line-height:1}.lg\:text-7xl{font-size:4.5rem;line-height:1}.lg\:text-lg{font-size:1.125rem;line-height:1.75rem}}@media (min-width:1280px){.xl\:mb-16{margin-bottom:4rem}}@media print{.print\:top-0{top:0}.print\:hidden{display:none}}
+/*! tailwindcss v4.1.4 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--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-duration:initial;--tw-ease:initial}}}@layer base{pre code.torchlight .line-number,pre code.torchlight .summary-caret{margin-right:calc(var(--spacing)*4)}.prose .torchlight-link,.torchlight-link{text-decoration-line:underline}.torchlight.has-focus-lines .line:not(.line-focus){filter:blur(.095rem);opacity:.65;transition:filter .35s,opacity .35s}.torchlight.has-focus-lines:hover .line:not(.line-focus){filter:blur();opacity:1}.torchlight summary:focus{--tw-outline-style:none;outline-style:none}.torchlight details>summary::marker{display:none}.torchlight details>summary::-webkit-details-marker{display:none}.torchlight details .summary-caret:after{pointer-events:none}.torchlight .summary-caret-empty:after,.torchlight details .summary-caret-middle:after,.torchlight details .summary-caret-end:after{content:" "}.torchlight details[open] .summary-caret-start:after{content:"-"}.torchlight details:not([open]) .summary-caret-start:after{content:"+"}.torchlight details[open] .summary-hide-when-open{display:none}.torchlight details:not([open]) .summary-hide-when-open{display:block}*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-amber-500:oklch(76.9% .188 70.08);--color-yellow-300:oklch(90.5% .182 98.111);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-green-500:oklch(72.3% .219 149.579);--color-blue-500:oklch(62.3% .214 259.815);--color-indigo-400:oklch(67.3% .182 276.935);--color-indigo-600:oklch(51.1% .262 276.966);--color-indigo-700:oklch(45.7% .24 277.023);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-800:oklch(27.9% .041 260.031);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-lg:32rem;--container-xl:36rem;--container-2xl:42rem;--container-3xl:48rem;--container-7xl:80rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--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: 1.2 ;--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;--font-weight-light:300;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--font-weight-extrabold:800;--font-weight-black:900;--tracking-tight:-.025em;--tracking-normal:0em;--tracking-wide:.025em;--leading-normal:1.5;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--drop-shadow-2xl:0 25px 25px #00000026;--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer components;@layer utilities{.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip:rect(0,0,0,0);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing)*0)}.end-0{inset-inline-end:calc(var(--spacing)*0)}.-top-1{top:calc(var(--spacing)*-1)}.top-0{top:calc(var(--spacing)*0)}.top-2\.5{top:calc(var(--spacing)*2.5)}.top-4{top:calc(var(--spacing)*4)}.top-16{top:calc(var(--spacing)*16)}.top-auto{top:auto}.right-0{right:calc(var(--spacing)*0)}.right-1{right:calc(var(--spacing)*1)}.right-3{right:calc(var(--spacing)*3)}.right-4{right:calc(var(--spacing)*4)}.bottom-0{bottom:calc(var(--spacing)*0)}.bottom-4{bottom:calc(var(--spacing)*4)}.-left-64{left:calc(var(--spacing)*-64)}.left-0{left:calc(var(--spacing)*0)}.z-10{z-index:10}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.col-12{grid-column:12}.col-auto{grid-column:auto}.float-end{float:inline-end}.float-left{float:left}.float-right{float:right}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.m-1{margin:calc(var(--spacing)*1)}.m-2{margin:calc(var(--spacing)*2)}.m-8{margin:calc(var(--spacing)*8)}.-mx-4{margin-inline:calc(var(--spacing)*-4)}.mx-0{margin-inline:calc(var(--spacing)*0)}.mx-0\.5{margin-inline:calc(var(--spacing)*.5)}.mx-3{margin-inline:calc(var(--spacing)*3)}.mx-4{margin-inline:calc(var(--spacing)*4)}.mx-8{margin-inline:calc(var(--spacing)*8)}.mx-auto{margin-inline:auto}.my-0{margin-block:calc(var(--spacing)*0)}.my-0\.5{margin-block:calc(var(--spacing)*.5)}.my-1{margin-block:calc(var(--spacing)*1)}.my-2{margin-block:calc(var(--spacing)*2)}.my-3{margin-block:calc(var(--spacing)*3)}.my-4{margin-block:calc(var(--spacing)*4)}.my-8{margin-block:calc(var(--spacing)*8)}.my-auto{margin-block:auto}.me-0{margin-inline-end:calc(var(--spacing)*0)}.me-2{margin-inline-end:calc(var(--spacing)*2)}.me-auto{margin-inline-end:auto}.prose{color:var(--tw-prose-body);--tw-prose-body:oklch(37.3% .034 259.733);--tw-prose-headings:oklch(21% .034 264.665);--tw-prose-lead:oklch(44.6% .03 256.802);--tw-prose-links:oklch(21% .034 264.665);--tw-prose-bold:oklch(21% .034 264.665);--tw-prose-counters:oklch(55.1% .027 264.364);--tw-prose-bullets:oklch(87.2% .01 258.338);--tw-prose-hr:oklch(92.8% .006 264.531);--tw-prose-quotes:oklch(21% .034 264.665);--tw-prose-quote-borders:oklch(92.8% .006 264.531);--tw-prose-captions:oklch(55.1% .027 264.364);--tw-prose-kbd:oklch(21% .034 264.665);--tw-prose-kbd-shadows:NaN NaN NaN;--tw-prose-code:oklch(21% .034 264.665);--tw-prose-pre-code:oklch(92.8% .006 264.531);--tw-prose-pre-bg:oklch(27.8% .033 256.848);--tw-prose-th-borders:oklch(87.2% .01 258.338);--tw-prose-td-borders:oklch(92.8% .006 264.531);--tw-prose-invert-body:oklch(87.2% .01 258.338);--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:oklch(70.7% .022 261.325);--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:oklch(70.7% .022 261.325);--tw-prose-invert-bullets:oklch(44.6% .03 256.802);--tw-prose-invert-hr:oklch(37.3% .034 259.733);--tw-prose-invert-quotes:oklch(96.7% .003 264.542);--tw-prose-invert-quote-borders:oklch(37.3% .034 259.733);--tw-prose-invert-captions:oklch(70.7% .022 261.325);--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:oklch(87.2% .01 258.338);--tw-prose-invert-pre-bg:#00000080;--tw-prose-invert-th-borders:oklch(44.6% .03 256.802);--tw-prose-invert-td-borders:oklch(37.3% .034 259.733);max-width:96ch;font-size:1rem;line-height:1.5em}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);margin-top:1.2em;margin-bottom:1.2em;font-size:1.25em;line-height:1.6}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:#5956eb;font-weight:500;text-decoration:none}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)):hover{color:#4f46e5}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em;list-style-type:decimal}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em;list-style-type:disc}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.25em;font-weight:600}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:unset;color:unset;border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"“""”""‘""’";padding-inline-start:1em;background-color:#80808020;border-left-color:#d1d5db;margin-top:1em;margin-bottom:1em;padding-top:.25em;padding-bottom:.25em;padding-left:.75em;line-height:1.25em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p{margin-top:.25em;margin-bottom:.25em;padding-right:.25em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p:before,.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) p:after{content:unset}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:0;margin-bottom:.888889em;font-size:2.25em;font-weight:800;line-height:1.11111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.5em;margin-bottom:.75em;font-size:1.5em;font-weight:700;line-height:1.33333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.6em;margin-bottom:.6em;font-size:1.25em;font-weight:600;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);margin-top:1.5em;margin-bottom:.5em;font-weight:600;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em;display:block}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px rgb(var(--tw-prose-kbd-shadows)/10%);padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;border-radius:.3125rem;padding-inline-start:.375em;font-family:inherit;font-size:.875em;font-weight:500}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before,.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:unset}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);padding-top:.857143em;padding-inline-end:1.14286em;padding-bottom:.857143em;background-color:#292d3e;border-radius:.25rem;margin-top:1rem;margin-bottom:1rem;padding-inline-start:1.14286em;font-size:.875em;font-weight:400;line-height:1.71429;overflow-x:auto}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)) code{font-family:Fira Code Regular,Consolas,monospace,Courier New}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit;background-color:#0000;border-width:0;border-radius:0;padding:0}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before,.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){table-layout:auto;width:100%;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.71429}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);vertical-align:bottom;padding-inline-end:.571429em;padding-bottom:.571429em;padding-inline-start:.571429em;font-weight:600}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);margin-top:.857143em;font-size:.875em;line-height:1.42857}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.571429em;padding-inline-end:.571429em;padding-bottom:.571429em;padding-inline-start:.571429em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose :where(code:not(pre code)):not(:where([class~=not-prose],[class~=not-prose] *)){font:unset;vertical-align:top;word-break:break-all;background-color:#80808033;border-radius:4px;max-width:80vw;margin-left:-2px;margin-right:1px;padding-left:4px;padding-right:4px;overflow-x:auto}.-mt-4{margin-top:calc(var(--spacing)*-4)}.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-6{margin-top:calc(var(--spacing)*6)}.mt-8{margin-top:calc(var(--spacing)*8)}.mt-12{margin-top:calc(var(--spacing)*12)}.mt-auto{margin-top:auto}.mr-1{margin-right:calc(var(--spacing)*1)}.mr-3{margin-right:calc(var(--spacing)*3)}.mr-4{margin-right:calc(var(--spacing)*4)}.mr-auto{margin-right:auto}.mb-0{margin-bottom:calc(var(--spacing)*0)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.mb-12{margin-bottom:calc(var(--spacing)*12)}.mb-auto{margin-bottom:auto}.-ml-2{margin-left:calc(var(--spacing)*-2)}.-ml-4{margin-left:calc(var(--spacing)*-4)}.-ml-6{margin-left:calc(var(--spacing)*-6)}.-ml-8{margin-left:calc(var(--spacing)*-8)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-3{margin-left:calc(var(--spacing)*3)}.ml-4{margin-left:calc(var(--spacing)*4)}.ml-auto{margin-left:auto}.block{display:block}.block\!{display:block!important}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.h-0\.5{height:calc(var(--spacing)*.5)}.h-1{height:calc(var(--spacing)*1)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-8{height:calc(var(--spacing)*8)}.h-16{height:calc(var(--spacing)*16)}.h-24{height:calc(var(--spacing)*24)}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[60vh\]{max-height:60vh}.max-h-\[75vh\]{max-height:75vh}.min-h-\[300px\]{min-height:300px}.min-h-\[calc\(100vh_-_4rem\)\]{min-height:calc(100vh - 4rem)}.min-h-screen{min-height:100vh}.w-5{width:calc(var(--spacing)*5)}.w-6{width:calc(var(--spacing)*6)}.w-8{width:calc(var(--spacing)*8)}.w-16{width:calc(var(--spacing)*16)}.w-64{width:calc(var(--spacing)*64)}.w-80{width:calc(var(--spacing)*80)}.w-96{width:calc(var(--spacing)*96)}.w-100{width:calc(var(--spacing)*100)}.w-\[70ch\]{width:70ch}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.w-screen{width:100vw}.max-w-3xl{max-width:var(--container-3xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-\[1000px\]{max-width:1000px}.max-w-full{max-width:100%}.max-w-lg{max-width:var(--container-lg)}.max-w-sm{max-width:var(--container-sm)}.min-w-screen{min-width:100vw}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow,.flex-grow-1,.grow{flex-grow:1}.table-auto{table-layout:auto}.table-fixed{table-layout:fixed}.border-collapse{border-collapse:collapse}.border-separate{border-collapse:separate}.origin-center{transform-origin:50%}.-rotate-45{rotate:-45deg}.rotate-45{rotate:45deg}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.cursor-auto{cursor:auto}.cursor-pointer{cursor:pointer}.scroll-mt-2{scroll-margin-top:calc(var(--spacing)*2)}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-nowrap{flex-wrap:nowrap}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-4{gap:calc(var(--spacing)*4)}:where(.space-y-4>: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)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px*var(--tw-divide-y-reverse));border-bottom-width:calc(1px*calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-300>:not(:last-child)){border-color:var(--color-gray-300)}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.scroll-smooth{scroll-behavior:smooth}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-l{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.rounded-tl{border-top-left-radius:.25rem}.rounded-r{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.rounded-tr{border-top-right-radius:.25rem}.rounded-b{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.rounded-br{border-bottom-right-radius:.25rem}.rounded-bl{border-bottom-left-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-4{border-style:var(--tw-border-style);border-width:4px}.border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.border-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-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-l-\[0\.325rem\]{border-left-style:var(--tw-border-style);border-left-width:.325rem}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-dotted{--tw-border-style:dotted;border-style:dotted}.border-double{--tw-border-style:double;border-style:double}.border-none{--tw-border-style:none;border-style:none}.border-solid{--tw-border-style:solid;border-style:solid}.border-amber-500{border-color:var(--color-amber-500)}.border-blue-500{border-color:var(--color-blue-500)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.border-gray-500{border-color:var(--color-gray-500)}.border-gray-900{border-color:var(--color-gray-900)}.border-green-500{border-color:var(--color-green-500)}.border-indigo-500{border-color:#5956eb}.border-red-600{border-color:var(--color-red-600)}.border-transparent{border-color:#0000}.border-yellow-400{border-color:var(--color-yellow-400)}.border-t-transparent{border-top-color:#0000}.border-r-gray-900{border-right-color:var(--color-gray-900)}.bg-black{background-color:var(--color-black)}.bg-black\/5{background-color:#0000000d}@supports (color:color-mix(in lab,red,red)){.bg-black\/5{background-color:color-mix(in oklab,var(--color-black)5%,transparent)}}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab,red,red)){.bg-black\/50{background-color:color-mix(in oklab,var(--color-black)50%,transparent)}}.bg-current{background-color:currentColor}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-gray-500{background-color:var(--color-gray-500)}.bg-indigo-600{background-color:var(--color-indigo-600)}.bg-slate-100{background-color:var(--color-slate-100)}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-yellow-400{background-color:var(--color-yellow-400)}.bg-linear-to-br{--tw-gradient-position:to bottom right;background-image:linear-gradient(var(--tw-gradient-stops))}@supports (background-image:linear-gradient(in lab,red,red)){.bg-linear-to-br{--tw-gradient-position:to bottom right in oklab}}.bg-cover{background-size:cover}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.bg-no-repeat{background-repeat:no-repeat}.fill-black{fill:var(--color-black)}.fill-current{fill:currentColor}.p-0{padding:calc(var(--spacing)*0)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-8{padding:calc(var(--spacing)*8)}.p-12{padding:calc(var(--spacing)*12)}.px-0{padding-inline:calc(var(--spacing)*0)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-5{padding-inline:calc(var(--spacing)*5)}.px-6{padding-inline:calc(var(--spacing)*6)}.px-8{padding-inline:calc(var(--spacing)*8)}.py-0{padding-block:calc(var(--spacing)*0)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.py-3{padding-block:calc(var(--spacing)*3)}.py-4{padding-block:calc(var(--spacing)*4)}.py-5{padding-block:calc(var(--spacing)*5)}.py-6{padding-block:calc(var(--spacing)*6)}.py-8{padding-block:calc(var(--spacing)*8)}.py-12{padding-block:calc(var(--spacing)*12)}.py-16{padding-block:calc(var(--spacing)*16)}.py-24{padding-block:calc(var(--spacing)*24)}.py-32{padding-block:calc(var(--spacing)*32)}.ps-0{padding-inline-start:calc(var(--spacing)*0)}.ps-2{padding-inline-start:calc(var(--spacing)*2)}.ps-3{padding-inline-start:calc(var(--spacing)*3)}.pe-0{padding-inline-end:calc(var(--spacing)*0)}.pe-2{padding-inline-end:calc(var(--spacing)*2)}.pe-4{padding-inline-end:calc(var(--spacing)*4)}.pt-3{padding-top:calc(var(--spacing)*3)}.pt-4{padding-top:calc(var(--spacing)*4)}.pt-8{padding-top:calc(var(--spacing)*8)}.pt-10{padding-top:calc(var(--spacing)*10)}.pb-2{padding-bottom:calc(var(--spacing)*2)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pb-4{padding-bottom:calc(var(--spacing)*4)}.pb-8{padding-bottom:calc(var(--spacing)*8)}.pb-12{padding-bottom:calc(var(--spacing)*12)}.pl-2{padding-left:calc(var(--spacing)*2)}.pl-4{padding-left:calc(var(--spacing)*4)}.pl-5{padding-left:calc(var(--spacing)*5)}.pl-8{padding-left:calc(var(--spacing)*8)}.text-center{text-align:center}.text-end{text-align:end}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.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-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-\[75\%\]{font-size:75%}.text-\[90\%\]{font-size:90%}.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-10{--tw-leading:calc(var(--spacing)*10);line-height:calc(var(--spacing)*10)}.leading-normal{--tw-leading:var(--leading-normal);line-height:var(--leading-normal)}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.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-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.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-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.text-nowrap{text-wrap:nowrap}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.text-black{color:var(--color-black)}.text-blue-500{color:var(--color-blue-500)}.text-gray-100{color:var(--color-gray-100)}.text-gray-200{color:var(--color-gray-200)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-green-500{color:var(--color-green-500)}.text-indigo-500{color:#5956eb}.text-indigo-600{color:var(--color-indigo-600)}.text-red-500{color:var(--color-red-500)}.text-transparent{color:#0000}.text-white{color:var(--color-white)}.text-yellow-500{color:var(--color-yellow-500)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.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)}.ring-gray-900\/5{--tw-ring-color:#1018280d}@supports (color:color-mix(in lab,red,red)){.ring-gray-900\/5{--tw-ring-color:color-mix(in oklab,var(--color-gray-900)5%,transparent)}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.drop-shadow-2xl{--tw-drop-shadow-size:drop-shadow(0 25px 25px var(--tw-drop-shadow-color,#00000026));--tw-drop-shadow:drop-shadow(var(--drop-shadow-2xl));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,)}.invert{--tw-invert:invert(100%);filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-75{--tw-duration:75ms;transition-duration:75ms}.duration-250{--tw-duration:.25s;transition-duration:.25s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-linear{--tw-ease:linear;transition-timing-function:linear}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}@media (hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}.group-hover\:grayscale-0:is(:where(.group):hover *){--tw-grayscale:grayscale(0%);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,)}.hover\:bg-black\/5:hover{background-color:#0000000d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-black\/5:hover{background-color:color-mix(in oklab,var(--color-black)5%,transparent)}}.hover\:bg-black\/10:hover{background-color:#0000001a}@supports (color:color-mix(in lab,red,red)){.hover\:bg-black\/10:hover{background-color:color-mix(in oklab,var(--color-black)10%,transparent)}}.hover\:bg-gray-200\/20:hover{background-color:#e5e7eb33}@supports (color:color-mix(in lab,red,red)){.hover\:bg-gray-200\/20:hover{background-color:color-mix(in oklab,var(--color-gray-200)20%,transparent)}}.hover\:bg-gray-600:hover{background-color:var(--color-gray-600)}.hover\:bg-indigo-500:hover{background-color:#5956eb}.hover\:text-gray-700:hover{color:var(--color-gray-700)}.hover\:text-gray-900:hover{color:var(--color-gray-900)}.hover\:text-indigo-600:hover{color:var(--color-indigo-600)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-xl:hover{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.focus\:not-sr-only:focus{clip:auto;white-space:normal;width:auto;height:auto;margin:0;padding:0;position:static;overflow:visible}.focus\:absolute:focus{position:absolute}.focus\:mx-auto:focus{margin-inline:auto}.focus\:mt-2:focus{margin-top:calc(var(--spacing)*2)}.focus\:w-64:focus{width:calc(var(--spacing)*64)}.focus\:bg-gray-700:focus{background-color:var(--color-gray-700)}.focus\:bg-indigo-700:focus{background-color:var(--color-indigo-700)}.focus\:p-2:focus{padding:calc(var(--spacing)*2)}.focus\:opacity-100:focus{opacity:1}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-gray-700:focus{--tw-ring-color:var(--color-gray-700)}.focus\:ring-indigo-600:focus{--tw-ring-color:var(--color-indigo-600)}.focus\:grayscale-0:focus{--tw-grayscale:grayscale(0%);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,)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}@media (min-width:40rem){.sm\:-mx-6{margin-inline:calc(var(--spacing)*-6)}.sm\:mx-auto{margin-inline:auto}.sm\:mt-4{margin-top:calc(var(--spacing)*4)}.sm\:mb-0{margin-bottom:calc(var(--spacing)*0)}.sm\:block{display:block}.sm\:max-w-xl{max-width:var(--container-xl)}.sm\:rounded-lg{border-radius:var(--radius-lg)}.sm\:px-6{padding-inline:calc(var(--spacing)*6)}.sm\:px-10{padding-inline:calc(var(--spacing)*10)}.sm\:py-12{padding-block:calc(var(--spacing)*12)}.sm\:leading-none{--tw-leading:1;line-height:1}.sm\:shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}@media (min-width:48rem){.md\:visible{visibility:visible}.md\:top-0{top:calc(var(--spacing)*0)}.md\:left-0{left:calc(var(--spacing)*0)}.md\:left-64{left:calc(var(--spacing)*64)}.md\:mx-2{margin-inline:calc(var(--spacing)*2)}.md\:my-0{margin-block:calc(var(--spacing)*0)}.md\:my-6{margin-block:calc(var(--spacing)*6)}.md\:mt-0{margin-top:calc(var(--spacing)*0)}.md\:mt-8{margin-top:calc(var(--spacing)*8)}.md\:mb-12{margin-bottom:calc(var(--spacing)*12)}.md\:ml-0{margin-left:calc(var(--spacing)*0)}.md\:block{display:block}.md\:flex{display:flex}.md\:hidden{display:none}.md\:inline-block{display:inline-block}.md\:min-h-screen{min-height:100vh}.md\:w-1\/2{width:50%}.md\:w-\[calc\(100vw_-_16rem\)\]{width:calc(100vw - 16rem)}.md\:w-auto{width:auto}.md\:max-w-2xl{max-width:var(--container-2xl)}.md\:max-w-none{max-width:none}.md\:grow{flex-grow:1}.md\:grow-0{flex-grow:0}.md\:items-center{align-items:center}.md\:border-none{--tw-border-style:none;border-style:none}.md\:bg-transparent{background-color:#0000}.md\:bg-white{background-color:var(--color-white)}.md\:bg-left{background-position:0}.md\:px-16{padding-inline:calc(var(--spacing)*16)}.md\:py-0{padding-block:calc(var(--spacing)*0)}.md\:py-16{padding-block:calc(var(--spacing)*16)}.md\:pb-0{padding-bottom:calc(var(--spacing)*0)}.md\:pl-0{padding-left:calc(var(--spacing)*0)}.md\:text-center{text-align:center}.md\:text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.md\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.md\:shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}@media (min-width:64rem){.lg\:mb-12{margin-bottom:calc(var(--spacing)*12)}.lg\:ml-8{margin-left:calc(var(--spacing)*8)}.lg\:flex{display:flex}.lg\:bg-center{background-position:50%}.lg\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.lg\:text-7xl{font-size:var(--text-7xl);line-height:var(--tw-leading,var(--text-7xl--line-height))}.lg\:text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}}@media (min-width:80rem){.xl\:mb-16{margin-bottom:calc(var(--spacing)*16)}}.dark\:block:is(.dark *){display:block}.dark\:hidden:is(.dark *){display:none}:where(.dark\:divide-gray-700:is(.dark *)>:not(:last-child)){border-color:var(--color-gray-700)}.dark\:border-\[\#1b2533\]:is(.dark *){border-color:#1b2533}.dark\:border-gray-700:is(.dark *){border-color:var(--color-gray-700)}.dark\:bg-black\/10:is(.dark *){background-color:#0000001a}@supports (color:color-mix(in lab,red,red)){.dark\:bg-black\/10:is(.dark *){background-color:color-mix(in oklab,var(--color-black)10%,transparent)}}.dark\:bg-gray-600:is(.dark *){background-color:var(--color-gray-600)}.dark\:bg-gray-700:is(.dark *){background-color:var(--color-gray-700)}.dark\:bg-gray-800:is(.dark *){background-color:var(--color-gray-800)}.dark\:bg-gray-900:is(.dark *){background-color:var(--color-gray-900)}.dark\:bg-slate-800:is(.dark *){background-color:var(--color-slate-800)}.dark\:bg-yellow-300:is(.dark *){background-color:var(--color-yellow-300)}.dark\:fill-gray-200:is(.dark *){fill:var(--color-gray-200)}.dark\:fill-white:is(.dark *){fill:var(--color-white)}.dark\:font-medium:is(.dark *){--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.dark\:prose-invert:is(.dark *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.dark\:prose-invert:is(.dark *) :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:#818cf8}.dark\:prose-invert:is(.dark *) :where(a):not(:where([class~=not-prose],[class~=not-prose] *)):hover{color:#6366f1}.dark\:text-gray-100:is(.dark *){color:var(--color-gray-100)}.dark\:text-gray-200:is(.dark *){color:var(--color-gray-200)}.dark\:text-gray-300:is(.dark *){color:var(--color-gray-300)}.dark\:text-gray-400:is(.dark *){color:var(--color-gray-400)}.dark\:text-indigo-400:is(.dark *){color:var(--color-indigo-400)}.dark\:text-white:is(.dark *){color:var(--color-white)}@media (hover:hover){.dark\:group-hover\:text-white:is(.dark *):is(:where(.group):hover *){color:var(--color-white)}.dark\:hover\:bg-black\/10:is(.dark *):hover{background-color:#0000001a}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-black\/10:is(.dark *):hover{background-color:color-mix(in oklab,var(--color-black)10%,transparent)}}.dark\:hover\:bg-gray-500:is(.dark *):hover{background-color:var(--color-gray-500)}.dark\:hover\:text-white:is(.dark *):hover{color:var(--color-white)}}.dark\:focus\:text-white:is(.dark *):focus{color:var(--color-white)}.dark\:focus\:ring-indigo-500:is(.dark *):focus{--tw-ring-color:#5956eb}@media (min-width:48rem){.dark\:md\:bg-transparent:is(.dark *){background-color:#0000}}@media print{.print\:top-0{top:calc(var(--spacing)*0)}.print\:hidden{display:none}}.prose-h1\:mb-3 :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:calc(var(--spacing)*3)}.prose-p\:my-3 :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-block:calc(var(--spacing)*3)}.prose-img\:inline :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){display:inline}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-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-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}
diff --git a/_pages/404.blade.php b/_pages/404.blade.php
index 7a4328b1fde..0360a58111d 100644
--- a/_pages/404.blade.php
+++ b/_pages/404.blade.php
@@ -31,7 +31,7 @@
Sorry, the page you are looking for could not be found.
+ HTML, $processor->run());
}
public function testStringWithoutShortcodeIsNotModified()
@@ -38,8 +54,11 @@ public function testStringWithoutShortcodeIsNotModified()
public function testProcessStaticShorthand()
{
$this->assertSame(
- '
So she was considering in her own mind, as well as she could',
]);
}
@@ -55,7 +55,7 @@ public function testCanCompilePageToRootOutputDirectory()
$this->inspectHtml([
'Adventures in Wonderland',
- '
');
+ if ($innerUlCount >= 1) {
+ // Indent each line within the remaining UL elements
+ foreach (range(1, $innerUlCount) as $item) {
+ $html = Str::replaceFirst('
+
+
diff --git a/packages/vite-plugin/src/index.ts b/packages/vite-plugin/src/index.ts
new file mode 100644
index 00000000000..c51bf900f47
--- /dev/null
+++ b/packages/vite-plugin/src/index.ts
@@ -0,0 +1,174 @@
+import { Plugin, ResolvedConfig } from 'vite';
+import fs from 'fs';
+import path from 'path';
+import { fileURLToPath } from 'url';
+
+// The interprocess communication signal file for the web server
+const HOT_FILE_PATH = 'app/storage/framework/runtime/vite.hot';
+
+export interface HydePluginOptions {
+ /**
+ * Asset entry points to process
+ *
+ * @default ['resources/assets/app.css', 'resources/assets/app.js']
+ */
+ input?: string[];
+
+ /**
+ * Enable hot reloading for content files
+ *
+ * @default true
+ */
+ refresh?: boolean;
+
+ /**
+ * Content directories to watch for changes
+ *
+ * @default ['_pages', '_posts', '_docs']
+ */
+ watch?: string[];
+}
+
+/**
+ * Resolve the path to a resource, ensuring that the path works when used as an ESM package.
+ */
+function resolveResource(resource: string): string {
+ // In ESM context, __dirname is not available, so we use fileURLToPath
+ try {
+ const __filename = fileURLToPath(import.meta.url);
+ const __dirname = path.dirname(__filename);
+
+ return path.resolve(__dirname, '../resources', resource);
+ } catch (error) {
+ // Fallback for CommonJS
+ return path.resolve(__dirname, '../resources', resource);
+ }
+}
+
+/**
+ * Check if a file exists and is a file
+ */
+function fileExists(file: string): boolean {
+ try {
+ return fs.statSync(file).isFile();
+ } catch {
+ return false;
+ }
+}
+
+/**
+ * Check if the JavaScript file has actual content to prevent empty app.js files from being compiled
+ */
+function hasJavaScriptContent(filePath: string): boolean {
+ try {
+ if (!fs.existsSync(filePath)) return false;
+ const content = fs.readFileSync(filePath, 'utf-8');
+ // Remove comments and check if there's any actual code
+ return content.replace(/\/\*[\s\S]*?\*\/|\/\/.*/g, '').trim().length > 0;
+ } catch (error) {
+ return false;
+ }
+}
+
+/**
+ * HydePHP Vite plugin for realtime compiler integration
+ */
+export default function hydePlugin(options: HydePluginOptions = {}): Plugin {
+ const {
+ input = ['resources/assets/app.css', 'resources/assets/app.js'],
+ watch = ['_pages', '_posts', '_docs'],
+ refresh = true,
+ } = options;
+
+ let config: ResolvedConfig;
+ let hotFilePath: string;
+
+ return {
+ name: 'hyde-vite-plugin',
+
+ config(config, { command }) {
+ // Only modify build configuration
+ if (command === 'build') {
+ // Process input files - only include app.js if it has content
+ const resolvedInput = [];
+
+ for (const entry of input) {
+ const resolvedPath = path.resolve(process.cwd(), entry);
+
+ // Only include app.js if it has actual content
+ if (entry.endsWith('app.js')) {
+ if (hasJavaScriptContent(resolvedPath) && fileExists(resolvedPath)) {
+ resolvedInput.push(resolvedPath);
+ }
+ } else if (fileExists(resolvedPath)) {
+ resolvedInput.push(resolvedPath);
+ }
+ }
+
+ return {
+ build: {
+ outDir: '_media',
+ emptyOutDir: false,
+ rollupOptions: {
+ input: resolvedInput,
+ output: {
+ entryFileNames: '[name].js',
+ chunkFileNames: '[name].js',
+ assetFileNames: '[name].[ext]'
+ }
+ }
+ }
+ };
+ }
+ },
+
+ configResolved(resolvedConfig) {
+ config = resolvedConfig;
+ hotFilePath = path.resolve(process.cwd(), HOT_FILE_PATH);
+ },
+
+ configureServer(server) {
+ // Create hot file when Vite server starts
+ fs.mkdirSync(path.dirname(hotFilePath), { recursive: true });
+ fs.writeFileSync(hotFilePath, '');
+
+ // Remove hot file when Vite server closes
+ ['SIGINT', 'SIGTERM'].forEach(signal => {
+ process.on(signal, () => {
+ try {
+ fs.rmSync(hotFilePath);
+ } catch (error) {
+ // Ignore errors when removing hot file
+ }
+ process.exit();
+ });
+ });
+
+ // Render the Vite index page when the root URL is requested
+ server.middlewares.use((req, res, next) => {
+ if (req.url === '/') {
+ try {
+ const indexPath = resolveResource('index.html');
+ const content = fs.readFileSync(indexPath, 'utf-8');
+ res.end(content);
+ } catch (error) {
+ next();
+ }
+ } else {
+ next();
+ }
+ });
+
+ // Add additional watch paths for content files if refresh option is enabled
+ if (refresh) {
+ watch.forEach(dir => {
+ const contentPath = path.resolve(process.cwd(), dir);
+ if (fs.existsSync(contentPath)) {
+ server.watcher.add(path.join(contentPath, '**'));
+ server.watcher.add(path.join(contentPath, '**/**'));
+ }
+ });
+ }
+ }
+ };
+}
diff --git a/packages/vite-plugin/tsconfig.json b/packages/vite-plugin/tsconfig.json
new file mode 100644
index 00000000000..975c01ca556
--- /dev/null
+++ b/packages/vite-plugin/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "module": "ES2020",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "declaration": true,
+ "outDir": "./dist",
+ "strict": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "dist"]
+}
diff --git a/resources/assets/app.css b/resources/assets/app.css
index dc762b9fd11..28818a9ac56 100644
--- a/resources/assets/app.css
+++ b/resources/assets/app.css
@@ -5,16 +5,14 @@
* The HydeFront package contains some base styles to make your site look even more amazing.
*
* The compiled result of this file is shipped with HydePHP and is found at _media/app.css,
-* so you don't need to compile this file unless you're making changes.
+* so you don't need to compile this file unless you're making changes to Tailwind styles.
*
* If you want, you can load the compiled file with minified styles for a base install from the CDN.
* See https://hydephp.com/docs/1.x/managing-assets#loading-from-cdn
*/
-@import '~hydefront/dist/hyde.css';
+@import 'hydefront/components/torchlight.css' layer(base);
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
+@import 'tailwindcss';
-[x-cloak] { display: none !important; }
+@config '../../tailwind.config.js';
diff --git a/resources/assets/app.js b/resources/assets/app.js
index 8081ae9a513..79675e67904 100644
--- a/resources/assets/app.js
+++ b/resources/assets/app.js
@@ -1,3 +1,3 @@
/*
-* This is the main JavaScript used by webpack to build the app.js file.
+* This is the main JavaScript used by Vite to build the app.js file.
*/
diff --git a/tailwind.config.js b/tailwind.config.js
index 9171b63559f..b3f3e6e5c92 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,6 +1,7 @@
-const defaultTheme = require('tailwindcss/defaultTheme');
+import defaultTheme from 'tailwindcss/defaultTheme';
+import typography from '@tailwindcss/typography';
-module.exports = {
+export default {
darkMode: 'class',
content: [
'./_pages/**/*.blade.php',
@@ -50,14 +51,18 @@ module.exports = {
content: 'unset',
},
},
- code: {
+ 'code:not(pre code)': {
font: 'unset',
backgroundColor: '#80808033',
paddingLeft: '4px',
paddingRight: '4px',
marginLeft: '-2px',
marginRight: '1px',
- borderRadius: '4px'
+ borderRadius: '4px',
+ maxWidth: '80vw',
+ overflowX: 'auto',
+ verticalAlign: 'top',
+ wordBreak: 'break-all'
},
'code::before': {
content: 'unset',
@@ -66,10 +71,15 @@ module.exports = {
content: 'unset',
},
pre: {
+ backgroundColor: '#292D3E',
+ borderRadius: '0.25rem',
+ marginTop: '1rem',
+ marginBottom: '1rem',
+ overflowX: 'auto',
code: {
fontFamily: "'Fira Code Regular', Consolas, Monospace, 'Courier New'",
- }
- }
+ },
+ },
},
},
invert: {
@@ -91,6 +101,7 @@ module.exports = {
},
},
+ // Safelist should NOT be copied to packages/hyde. It's purely for the monorepo.
safelist: [
'prose',
'dark:prose-invert',
@@ -116,6 +127,6 @@ module.exports = {
],
plugins: [
- require('@tailwindcss/typography')
+ typography
],
};
diff --git a/tests/fixtures/example-sites/ui-examples/documentation.md b/tests/fixtures/example-sites/ui-examples/documentation.md
index 41235c6c585..48b2dd3bc9d 100644
--- a/tests/fixtures/example-sites/ui-examples/documentation.md
+++ b/tests/fixtures/example-sites/ui-examples/documentation.md
@@ -2,7 +2,7 @@
The HydePHP UI Kit is a collection of minimalistic and un-opinionated TailwindCSS components for Laravel Blade,
indented to be used with HydePHP. Note that these components may require CSS classes not present in the bundled app.css
-file and that you may need to recompile the CSS file using the included Laravel Mix configuration.
+file and that you may need to recompile the CSS file using the included Tailwind and Vite configuration.
## Warning
diff --git a/tests/fixtures/markdown-features.md b/tests/fixtures/markdown-features.md
index e8314f56195..1d33e4eaaef 100644
--- a/tests/fixtures/markdown-features.md
+++ b/tests/fixtures/markdown-features.md
@@ -22,7 +22,7 @@ echo 'A file path label has been added to the top right corner.';
#### And syntax highlighting
-
1echo'Syntax highlighted by torchlight.dev.';
+
1echo'Syntax highlighted by torchlight.dev.';
---
diff --git a/vite.config.js b/vite.config.js
new file mode 100644
index 00000000000..dab5adade35
--- /dev/null
+++ b/vite.config.js
@@ -0,0 +1,18 @@
+// Using Vite is optional, as the styles you need to get started are already included.
+// However, if you customize existing or add new Tailwind classes, you can use Vite
+// to compile the assets. See https://hydephp.com/docs/1.x/managing-assets.html.
+
+import { defineConfig } from 'vite';
+import tailwindcss from "@tailwindcss/vite";
+import hyde from 'hyde-vite-plugin';
+
+export default defineConfig({
+ plugins: [
+ hyde({
+ input: ['resources/assets/app.css', 'resources/assets/app.js'],
+ watch: ['_pages', '_posts', '_docs'],
+ refresh: true,
+ }),
+ tailwindcss(),
+ ],
+});
diff --git a/webpack.mix.js b/webpack.mix.js
deleted file mode 100644
index e8d11abbc98..00000000000
--- a/webpack.mix.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// Using Laravel Mix is optional as the styles you need to get started are already included.
-// However, if you add new Tailwind classes, or any customizations, you can use Webpack to
-// compile the assets. See https://hydephp.com/docs/1.x/managing-assets.html.
-
-let mix = require('laravel-mix');
-
-mix.js('resources/assets/app.js', 'app.js')
- .postCss('resources/assets/app.css', 'app.css', [
- require('tailwindcss'),
- require('autoprefixer'),
- ]).setPublicPath('_site/media')
- .copyDirectory('_site/media', '_media')