From 31b2a9ab860c4c502bc1a91cfabba1cf38486f81 Mon Sep 17 00:00:00 2001 From: Tony Lea Date: Fri, 10 May 2024 10:22:04 -0400 Subject: [PATCH 1/5] Adding updates with fortify --- composer.json | 3 +- config/devdojo/auth/language.php | 9 + config/devdojo/auth/settings.php | 8 +- .../views/components/layouts/empty.blade.php | 10 +- .../two-factor-authentication-form.blade.php | 126 ++++++++++++ .../views/pages/auth/two-factor.blade.php | 176 +++++++++++++++++ routes/web.php | 4 + src/AuthServiceProvider.php | 7 + .../Forms/TwoFactorAuthenticationForm.php | 180 ++++++++++++++++++ src/Models/User.php | 3 +- 10 files changed, 518 insertions(+), 8 deletions(-) create mode 100644 resources/views/livewire/forms/two-factor-authentication-form.blade.php create mode 100644 resources/views/pages/auth/two-factor.blade.php create mode 100644 src/Livewire/Forms/TwoFactorAuthenticationForm.php diff --git a/composer.json b/composer.json index 93fc13b..0f4c8a9 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,8 @@ "laravel/socialite": "^5.0", "calebporzio/sushi": "^2.5", "pragmarx/google2fa": "^8.0", - "bacon/bacon-qr-code": "^2.0" + "bacon/bacon-qr-code": "^2.0", + "laravel/fortify": "^1.21" }, "require-dev": { "orchestra/testbench": "^9.0", diff --git a/config/devdojo/auth/language.php b/config/devdojo/auth/language.php index b668844..88bf008 100644 --- a/config/devdojo/auth/language.php +++ b/config/devdojo/auth/language.php @@ -21,5 +21,14 @@ 'headline' => 'Verify your email address', 'subheadline' => 'Before you can proceed you must verify your email.', 'show_subheadline' => false + ], + 'twoFactorChallenge' => [ + 'page_title' => 'Two Factor Challenge', + 'headline_auth' => 'Authentication Code', + 'subheadline_auth' => 'Enter the authentication code provided by your authenticator application.', + 'show_subheadline_auth' => false, + 'headline_recovery' => 'Recovery Code', + 'subheadline_recovery' => 'Please confirm access to your account by entering one of your emergency recovery codes.', + 'show_subheadline_recovery' => false ] ]; \ No newline at end of file diff --git a/config/devdojo/auth/settings.php b/config/devdojo/auth/settings.php index 21c579a..88d8de1 100644 --- a/config/devdojo/auth/settings.php +++ b/config/devdojo/auth/settings.php @@ -8,7 +8,7 @@ 'registration_show_password_same_screen' => true, 'registration_include_name_field' => false, 'registration_require_email_verification' => false, - 'enable_branding' => env('DEVDOJO_AUTH_BRANDING', true), - 'dev_mode' => env('DEVDOJO_AUTH_DEV', false), - 'enable_2fa' => env('DEVDOJO_AUTH_ENABLE_2FA', false), // Enable or disable 2FA functionality globally -]; + 'enable_branding' => true, + 'dev_mode' => false, + 'enable_2fa' => false, // Enable or disable 2FA functionality globally +]; \ No newline at end of file diff --git a/resources/views/components/layouts/empty.blade.php b/resources/views/components/layouts/empty.blade.php index 76b8e15..66e8511 100644 --- a/resources/views/components/layouts/empty.blade.php +++ b/resources/views/components/layouts/empty.blade.php @@ -6,8 +6,14 @@ Authentication Setup - - + + @if(config('devdojo.auth.settings.dev_mode')) + @vite(['packages/devdojo/auth/resources/css/auth.css', 'packages/devdojo/auth/resources/css/auth.js']) + @else + + + @endif + {{ $slot }} diff --git a/resources/views/livewire/forms/two-factor-authentication-form.blade.php b/resources/views/livewire/forms/two-factor-authentication-form.blade.php new file mode 100644 index 0000000..fceaac3 --- /dev/null +++ b/resources/views/livewire/forms/two-factor-authentication-form.blade.php @@ -0,0 +1,126 @@ +
+

+ {{ __('Two Factor Authentication') }} +

+ +

+ {{ __('Add additional security to your account using two factor authentication.') }} +

+ +
+

+ @if ($this->enabled) + @if ($showingConfirmation) + {{ __('Finish enabling two factor authentication.') }} + @else + {{ __('You have enabled two factor authentication.') }} + @endif + @else + {{ __('You have not enabled two factor authentication.') }} + @endif +

+ +
+

+ {{ __('When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone\'s Google Authenticator application.') }} +

+
+ + @if ($this->enabled) + @if ($showingQrCode) +
+

+ @if ($showingConfirmation) + {{ __('To finish enabling two factor authentication, scan the following QR code using your phone\'s authenticator application or enter the setup key and provide the generated OTP code.') }} + @else + {{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application or enter the setup key.') }} + @endif +

+
+ +
+ {!! $this->user->twoFactorQrCodeSvg() !!} +
+ +
+

+ {{ __('Setup Key') }}: {{ decrypt($this->user->two_factor_secret) }} +

+
+ + @if ($showingConfirmation) +
+
+ @endif + @endif + + @if ($showingRecoveryCodes) +
+

+ {{ __('Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.') }} +

+
+ +
+ @foreach (json_decode(decrypt($this->user->two_factor_recovery_codes), true) as $code) +
{{ $code }}
+ @endforeach +
+ @endif + @endif + +
+ @if (! $this->enabled) + + + + @else + @if ($showingRecoveryCodes) + + + + @elseif ($showingConfirmation) + + + + @else + + + + @endif + + @if ($showingConfirmation) + + + + @else + + + + @endif + + @endif +
+
+
diff --git a/resources/views/pages/auth/two-factor.blade.php b/resources/views/pages/auth/two-factor.blade.php new file mode 100644 index 0000000..72f4124 --- /dev/null +++ b/resources/views/pages/auth/two-factor.blade.php @@ -0,0 +1,176 @@ + + + + @volt('auth.two-factor') +
+
+

+ {{ __('Two Factor Authentication') }} +

+ +

+ {{ __('Add additional security to your account using two factor authentication.') }} +

+ +
+

+ + @if ($showingConfirmation) + {{ __('Finish enabling two factor authentication.') }} + @else + {{ __('You have enabled two factor authentication.') }} + @endif + +

+ +
+

+ {{ __('When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone\'s Google Authenticator application.') }} +

+
+ + + @if ($showingQrCode) +
+

+ @if ($showingConfirmation) + {{ __('To finish enabling two factor authentication, scan the following QR code using your phone\'s authenticator application or enter the setup key and provide the generated OTP code.') }} + @else + {{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application or enter the setup key.') }} + @endif +

+
+ +
+ {!! auth()->user()->twoFactorQrCodeSvg() !!} +
+ +
+

+ {{-- {{ __('Setup Key') }}: {{ decrypt(auth()->user()->two_factor_secret) }} --}} +

+
+ + @if ($showingConfirmation) +
+
+ @endif + @endif + + @if ($showingRecoveryCodes) +
+

+ {{ __('Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.') }} +

+
+ +
+ {{-- @foreach (json_decode(decrypt(auth()->user()->two_factor_recovery_codes), true) as $code) +
{{ $code }}
+ @endforeach --}} +
+ @endif + +
+ + @if ($showingRecoveryCodes) + + + + @elseif ($showingConfirmation) + + + + @else + + + + @endif + + @if ($showingConfirmation) + + + + @else + + + + @endif +
+
+
+
+ @endvolt + +
\ No newline at end of file diff --git a/routes/web.php b/routes/web.php index a31fc73..b42578e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -40,6 +40,10 @@ $generateCodesFor(auth()->user()); }); + Route::get('newr', function(){ + dd(auth()->user()->hasEnabledTwoFactorAuthentication()); + }); + }); diff --git a/src/AuthServiceProvider.php b/src/AuthServiceProvider.php index 2e06793..c434c89 100644 --- a/src/AuthServiceProvider.php +++ b/src/AuthServiceProvider.php @@ -9,6 +9,7 @@ use Illuminate\Support\Facades\Blade; use Illuminate\Support\ServiceProvider; use PragmaRX\Google2FA\Google2FA; +use Laravel\Fortify\Fortify; class AuthServiceProvider extends ServiceProvider { @@ -59,9 +60,15 @@ public function boot() Livewire::component('auth.setup.alignment', \Devdojo\Auth\Livewire\Setup\Alignment::class); Livewire::component('auth.setup.favicon', \Devdojo\Auth\Livewire\Setup\Favicon::class); Livewire::component('auth.setup.css', \Devdojo\Auth\Livewire\Setup\Css::class); + + Livewire::component('auth.form.two-factor-authentication-form', \Devdojo\Auth\Livewire\Forms\TwoFactorAuthenticationForm::class); } //app()->register(\October\Rain\Config\ServiceProvider::class); + + Fortify::loginView(function () { + return redirect('auth/login'); + }); } private function registerAuthFolioDirectory(){ diff --git a/src/Livewire/Forms/TwoFactorAuthenticationForm.php b/src/Livewire/Forms/TwoFactorAuthenticationForm.php new file mode 100644 index 0000000..99ede4b --- /dev/null +++ b/src/Livewire/Forms/TwoFactorAuthenticationForm.php @@ -0,0 +1,180 @@ +two_factor_confirmed_at)) { + app(DisableTwoFactorAuthentication::class)(Auth::user()); + } + } + + /** + * Enable two factor authentication for the user. + * + * @param \Laravel\Fortify\Actions\EnableTwoFactorAuthentication $enable + * @return void + */ + public function enableTwoFactorAuthentication(EnableTwoFactorAuthentication $enable) + { + // if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')) { + // $this->ensurePasswordIsConfirmed(); + // } + + $enable(Auth::user()); + + $this->showingQrCode = true; + + if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm')) { + $this->showingConfirmation = true; + } else { + $this->showingRecoveryCodes = true; + } + } + + /** + * Confirm two factor authentication for the user. + * + * @param \Laravel\Fortify\Actions\ConfirmTwoFactorAuthentication $confirm + * @return void + */ + public function confirmTwoFactorAuthentication(ConfirmTwoFactorAuthentication $confirm) + { + // if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')) { + // $this->ensurePasswordIsConfirmed(); + // } + + $confirm(Auth::user(), $this->code); + + $this->showingQrCode = false; + $this->showingConfirmation = false; + $this->showingRecoveryCodes = true; + } + + /** + * Display the user's recovery codes. + * + * @return void + */ + public function showRecoveryCodes() + { + // if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')) { + // $this->ensurePasswordIsConfirmed(); + // } + + $this->showingRecoveryCodes = true; + } + + /** + * Generate new recovery codes for the user. + * + * @param \Laravel\Fortify\Actions\GenerateNewRecoveryCodes $generate + * @return void + */ + public function regenerateRecoveryCodes(GenerateNewRecoveryCodes $generate) + { + // if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')) { + // $this->ensurePasswordIsConfirmed(); + // } + + $generate(Auth::user()); + + $this->showingRecoveryCodes = true; + } + + /** + * Disable two factor authentication for the user. + * + * @param \Laravel\Fortify\Actions\DisableTwoFactorAuthentication $disable + * @return void + */ + public function disableTwoFactorAuthentication(DisableTwoFactorAuthentication $disable) + { + // if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')) { + // $this->ensurePasswordIsConfirmed(); + // } + + $disable(Auth::user()); + + $this->showingQrCode = false; + $this->showingConfirmation = false; + $this->showingRecoveryCodes = false; + } + + /** + * Get the current user of the application. + * + * @return mixed + */ + public function getUserProperty() + { + return Auth::user(); + } + + /** + * Determine if two factor authentication is enabled. + * + * @return bool + */ + public function getEnabledProperty() + { + return ! empty($this->user->two_factor_secret); + } + + /** + * Render the component. + * + * @return \Illuminate\View\View + */ + public function render() + { + return view('auth::livewire.forms.two-factor-authentication-form'); + } +} diff --git a/src/Models/User.php b/src/Models/User.php index 49fcafa..e15c332 100644 --- a/src/Models/User.php +++ b/src/Models/User.php @@ -6,10 +6,11 @@ use Devdojo\Auth\Traits\HasSocialProviders; use Illuminate\Contracts\Auth\MustVerifyEmail; use PragmaRX\Google2FA\Google2FA; +use Laravel\Fortify\TwoFactorAuthenticatable; class User extends Authenticatable implements MustVerifyEmail { - use HasSocialProviders; + use HasSocialProviders, TwoFactorAuthenticatable; protected $fillable = [ 'name', 'email', 'password', 'two_factor_secret', 'two_factor_recovery_codes', From 151aa250917cab2ff257e4686b405cedae43e105 Mon Sep 17 00:00:00 2001 From: Tony Lea Date: Fri, 10 May 2024 18:34:30 -0400 Subject: [PATCH 2/5] Adding fortify out and designing custom 2fa --- composer.json | 3 +- resources/css/auth.css | 9 + .../components/elements/input-code.blade.php | 108 +++++++++++ .../views/components/layouts/app.blade.php | 44 +---- .../views/components/layouts/empty.blade.php | 18 +- resources/views/includes/head.blade.php | 38 ++++ .../two-factor-authentication-form.blade.php | 126 ------------ .../views/pages/auth/two-factor.blade.php | 6 - .../two-factor-authentication/index.blade.php | 142 ++++++++------ routes/web.php | 3 +- .../DisableTwoFactorAuthentication.php | 29 +++ .../GenerateQrCodeAndSecretKey.php | 4 +- src/AuthServiceProvider.php | 7 - .../TwoFactorAuthenticationDisabled.php | 8 + src/Events/TwoFactorAuthenticationEvent.php | 28 +++ .../Forms/TwoFactorAuthenticationForm.php | 180 ------------------ src/Models/User.php | 3 +- 17 files changed, 320 insertions(+), 436 deletions(-) create mode 100644 resources/views/components/elements/input-code.blade.php create mode 100644 resources/views/includes/head.blade.php delete mode 100644 resources/views/livewire/forms/two-factor-authentication-form.blade.php create mode 100644 src/Actions/TwoFactorAuth/DisableTwoFactorAuthentication.php create mode 100644 src/Events/TwoFactorAuthenticationDisabled.php create mode 100644 src/Events/TwoFactorAuthenticationEvent.php delete mode 100644 src/Livewire/Forms/TwoFactorAuthenticationForm.php diff --git a/composer.json b/composer.json index 0f4c8a9..93fc13b 100644 --- a/composer.json +++ b/composer.json @@ -26,8 +26,7 @@ "laravel/socialite": "^5.0", "calebporzio/sushi": "^2.5", "pragmarx/google2fa": "^8.0", - "bacon/bacon-qr-code": "^2.0", - "laravel/fortify": "^1.21" + "bacon/bacon-qr-code": "^2.0" }, "require-dev": { "orchestra/testbench": "^9.0", diff --git a/resources/css/auth.css b/resources/css/auth.css index 765bb73..c6c3df2 100644 --- a/resources/css/auth.css +++ b/resources/css/auth.css @@ -5,4 +5,13 @@ .CodeMirror{ border-radius: 6px; border: 1px solid #e1e1e5; +} + +input[type='number'].auth-code-input { + -moz-appearance:textfield; +} + +input.auth-code-input::-webkit-outer-spin-button, +input.auth-code-input::-webkit-inner-spin-button { + -webkit-appearance: none; } \ No newline at end of file diff --git a/resources/views/components/elements/input-code.blade.php b/resources/views/components/elements/input-code.blade.php new file mode 100644 index 0000000..52827bf --- /dev/null +++ b/resources/views/components/elements/input-code.blade.php @@ -0,0 +1,108 @@ +@props([ + // total number of boxes to display + 'digits' => 4, + + 'eventCallback' => null +]) + +
+
+
+ @for ($x = 1; $x <= $digits; $x++) + + @endfor +
+
+ whereStartsWith('id') }} type="hidden" x-ref="pin" name="pin" /> +
diff --git a/resources/views/components/layouts/app.blade.php b/resources/views/components/layouts/app.blade.php index 0aa3c74..85d19db 100644 --- a/resources/views/components/layouts/app.blade.php +++ b/resources/views/components/layouts/app.blade.php @@ -1,46 +1,8 @@ - - - - - - {{ $title ?? 'Auth' }} - @if(config('devdojo.auth.settings.dev_mode')) - @vite(['packages/devdojo/auth/resources/css/auth.css', 'packages/devdojo/auth/resources/css/auth.js']) - @else - - - @endif - - @php - $buttonRGBColor = \Devdojo\Auth\Helper::convertHexToRGBString(config('devdojo.auth.appearance.color.button')); - $inputBorderRGBColor = \Devdojo\Auth\Helper::convertHexToRGBString(config('devdojo.auth.appearance.color.input_border')); - @endphp - - - @if(file_exists(public_path('auth/app.css'))) - - @endif - - - - - + + @include('auth::includes.head') + @if(config('devdojo.auth.appearance.background.image')) diff --git a/resources/views/components/layouts/empty.blade.php b/resources/views/components/layouts/empty.blade.php index 66e8511..15fd1e6 100644 --- a/resources/views/components/layouts/empty.blade.php +++ b/resources/views/components/layouts/empty.blade.php @@ -1,20 +1,8 @@ - - - - - - Authentication Setup - - @if(config('devdojo.auth.settings.dev_mode')) - @vite(['packages/devdojo/auth/resources/css/auth.css', 'packages/devdojo/auth/resources/css/auth.js']) - @else - - - @endif - - + + @include('auth::includes.head') + {{ $slot }} diff --git a/resources/views/includes/head.blade.php b/resources/views/includes/head.blade.php new file mode 100644 index 0000000..26f0858 --- /dev/null +++ b/resources/views/includes/head.blade.php @@ -0,0 +1,38 @@ + + + + +{{ $title ?? 'Auth' }} +@if(config('devdojo.auth.settings.dev_mode')) + @vite(['packages/devdojo/auth/resources/css/auth.css', 'packages/devdojo/auth/resources/css/auth.js']) +@else + + +@endif + +@php + $buttonRGBColor = \Devdojo\Auth\Helper::convertHexToRGBString(config('devdojo.auth.appearance.color.button')); + $inputBorderRGBColor = \Devdojo\Auth\Helper::convertHexToRGBString(config('devdojo.auth.appearance.color.input_border')); +@endphp + + +@if(file_exists(public_path('auth/app.css'))) + +@endif + + + \ No newline at end of file diff --git a/resources/views/livewire/forms/two-factor-authentication-form.blade.php b/resources/views/livewire/forms/two-factor-authentication-form.blade.php deleted file mode 100644 index fceaac3..0000000 --- a/resources/views/livewire/forms/two-factor-authentication-form.blade.php +++ /dev/null @@ -1,126 +0,0 @@ -
-

- {{ __('Two Factor Authentication') }} -

- -

- {{ __('Add additional security to your account using two factor authentication.') }} -

- -
-

- @if ($this->enabled) - @if ($showingConfirmation) - {{ __('Finish enabling two factor authentication.') }} - @else - {{ __('You have enabled two factor authentication.') }} - @endif - @else - {{ __('You have not enabled two factor authentication.') }} - @endif -

- -
-

- {{ __('When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone\'s Google Authenticator application.') }} -

-
- - @if ($this->enabled) - @if ($showingQrCode) -
-

- @if ($showingConfirmation) - {{ __('To finish enabling two factor authentication, scan the following QR code using your phone\'s authenticator application or enter the setup key and provide the generated OTP code.') }} - @else - {{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application or enter the setup key.') }} - @endif -

-
- -
- {!! $this->user->twoFactorQrCodeSvg() !!} -
- -
-

- {{ __('Setup Key') }}: {{ decrypt($this->user->two_factor_secret) }} -

-
- - @if ($showingConfirmation) -
-
- @endif - @endif - - @if ($showingRecoveryCodes) -
-

- {{ __('Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.') }} -

-
- -
- @foreach (json_decode(decrypt($this->user->two_factor_recovery_codes), true) as $code) -
{{ $code }}
- @endforeach -
- @endif - @endif - -
- @if (! $this->enabled) - - - - @else - @if ($showingRecoveryCodes) - - - - @elseif ($showingConfirmation) - - - - @else - - - - @endif - - @if ($showingConfirmation) - - - - @else - - - - @endif - - @endif -
-
-
diff --git a/resources/views/pages/auth/two-factor.blade.php b/resources/views/pages/auth/two-factor.blade.php index 72f4124..71a41ef 100644 --- a/resources/views/pages/auth/two-factor.blade.php +++ b/resources/views/pages/auth/two-factor.blade.php @@ -7,12 +7,6 @@ use Livewire\Volt\Component; use Devdojo\Auth\Traits\HasConfigs; -use Laravel\Fortify\Actions\ConfirmTwoFactorAuthentication; -use Laravel\Fortify\Actions\DisableTwoFactorAuthentication; -use Laravel\Fortify\Actions\EnableTwoFactorAuthentication; -use Laravel\Fortify\Actions\GenerateNewRecoveryCodes; -use Laravel\Fortify\Features; - name('auth.two-factor'); diff --git a/resources/views/pages/user/two-factor-authentication/index.blade.php b/resources/views/pages/user/two-factor-authentication/index.blade.php index 0b89ba6..38d48dd 100644 --- a/resources/views/pages/user/two-factor-authentication/index.blade.php +++ b/resources/views/pages/user/two-factor-authentication/index.blade.php @@ -2,6 +2,11 @@ use function Laravel\Folio\{middleware, name}; use Livewire\Volt\Component; +use Livewire\Attributes\On; +use PragmaRX\Google2FA\Google2FA; +use Devdojo\Auth\Actions\TwoFactorAuth\DisableTwoFactorAuthentication; +use Devdojo\Auth\Actions\TwoFactorAuth\GenerateNewRecoveryCodes; +use Devdojo\Auth\Actions\TwoFactorAuth\GenerateQrCodeAndSecretKey; name('user.two-factor-authentication'); //middleware(['auth', 'verified', 'password.confirm']); @@ -10,10 +15,54 @@ new class extends Component { + public $enabled = false; + + // confirmed means that it has been enabled and the user has confirmed a code + public $confirmed = false; + public $showingConfirmation = false; + + public $secret = ''; + public $codes = ''; + public $qr = ''; public function mount(){ + if(is_null(auth()->user()->two_factor_confirmed_at)) { + app(DisableTwoFactorAuthentication::class)(auth()->user()); + } + } + + public function enable(){ + $QrCodeAndSecret = new GenerateQrCodeAndSecretKey(); + [$this->qr, $this->secret] = $QrCodeAndSecret(auth()->user()); + auth()->user()->forceFill([ + 'two_factor_secret' => encrypt($this->secret), + 'two_factor_recovery_codes' => encrypt($this->generateCodes()) + ])->save(); + + $this->enabled = true; + } + + private function generateCodes(){ + $generateCodesFor = new GenerateNewRecoveryCodes(); + return $generateCodesFor(auth()->user()); + } + + #[On('submitCode')] + public function submitCode($code) + { + if(empty($code) || strlen($code) < 5){ + dd('show validation error'); + return; + } + + //dd($this->secret); + + $google2fa = new Google2FA(); + $valid = $google2fa->verifyKey($this->secret, $code); + + dd($valid); } } @@ -22,62 +71,49 @@ public function mount(){ @volt('user.two-factor-authentication') -
-

- {{ __('Finish enabling two factor authentication.') }} -

- -
-

- {{ __('When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone\'s Google Authenticator application.') }} -

-
- -
-

- @if ($showingConfirmation) - {{ __('To finish enabling two factor authentication, scan the following QR code using your phone\'s authenticator application or enter the setup key and provide the generated OTP code.') }} +

+
+ + @if($confirmed) +

Two-factor auth is current enabled and active for this user.

+ @else + @if(!$enabled) +
+

You have not enabled two factor authentication.

+

When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone's Google Authenticator application.

+
+ Enable +
+
@else - {{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application or enter the setup key.') }} +
+
+

Finish enabling two factor authentication.

+

When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone's Google Authenticator application.

+

To finish enabling two factor authentication, scan the following QR code using your phone's authenticator application or enter the setup key and provide the generated OTP code.

+
+ +
+ +
+ +

+ {{ __('Setup Key') }}: {{ $secret }} +

+ + + +
+ Confirm + Cancel +
+ + +
@endif -

+ @endif
- -
- {!! auth()->user()->twoFactorQrCodeSvg() !!} -
- -
-

- {{ __('Setup Key') }}: {{ decrypt(auth()->user()->two_factor_secret) }} -

-
- - @if ($showingConfirmation) -
- - - -
- @endif - - @if ($showingRecoveryCodes ?? false) -
-

- {{ __('Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.') }} -

-
- -
- @foreach (json_decode(decrypt(auth()->user()->two_factor_recovery_codes), true) as $code) -
{{ $code }}
- @endforeach -
- @endif - -
+ @endvolt \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index b42578e..58743f1 100644 --- a/routes/web.php +++ b/routes/web.php @@ -6,8 +6,7 @@ use Illuminate\Support\Facades\Route; -use Devdojo\Auth\Actions\TwoFactorAuth\GenerateNewRecoveryCodes; -use Devdojo\Auth\Actions\TwoFactorAuth\GenerateQrCodeAndSecretKey; + // Create redirect routes for common authentication routes diff --git a/src/Actions/TwoFactorAuth/DisableTwoFactorAuthentication.php b/src/Actions/TwoFactorAuth/DisableTwoFactorAuthentication.php new file mode 100644 index 0000000..46a3198 --- /dev/null +++ b/src/Actions/TwoFactorAuth/DisableTwoFactorAuthentication.php @@ -0,0 +1,29 @@ +two_factor_secret) || + ! is_null($user->two_factor_recovery_codes) || + ! is_null($user->two_factor_confirmed_at)) { + $user->forceFill([ + 'two_factor_secret' => null, + 'two_factor_recovery_codes' => null, + 'two_factor_confirmed_at' => null + ])->save(); + + TwoFactorAuthenticationDisabled::dispatch($user); + } + } +} diff --git a/src/Actions/TwoFactorAuth/GenerateQrCodeAndSecretKey.php b/src/Actions/TwoFactorAuth/GenerateQrCodeAndSecretKey.php index b8b4434..7cb9288 100644 --- a/src/Actions/TwoFactorAuth/GenerateQrCodeAndSecretKey.php +++ b/src/Actions/TwoFactorAuth/GenerateQrCodeAndSecretKey.php @@ -16,7 +16,7 @@ class GenerateQrCodeAndSecretKey * @param mixed $user * @return void */ - public function __invoke($user) + public function __invoke($user) : array { $google2fa = new Google2FA(); @@ -28,7 +28,7 @@ public function __invoke($user) $g2faUrl = $google2fa->getQRCodeUrl( 'Auth', $user->email, - $google2fa->generateSecretKey() + $secret_key ); $writer = new Writer( diff --git a/src/AuthServiceProvider.php b/src/AuthServiceProvider.php index c434c89..2e06793 100644 --- a/src/AuthServiceProvider.php +++ b/src/AuthServiceProvider.php @@ -9,7 +9,6 @@ use Illuminate\Support\Facades\Blade; use Illuminate\Support\ServiceProvider; use PragmaRX\Google2FA\Google2FA; -use Laravel\Fortify\Fortify; class AuthServiceProvider extends ServiceProvider { @@ -60,15 +59,9 @@ public function boot() Livewire::component('auth.setup.alignment', \Devdojo\Auth\Livewire\Setup\Alignment::class); Livewire::component('auth.setup.favicon', \Devdojo\Auth\Livewire\Setup\Favicon::class); Livewire::component('auth.setup.css', \Devdojo\Auth\Livewire\Setup\Css::class); - - Livewire::component('auth.form.two-factor-authentication-form', \Devdojo\Auth\Livewire\Forms\TwoFactorAuthenticationForm::class); } //app()->register(\October\Rain\Config\ServiceProvider::class); - - Fortify::loginView(function () { - return redirect('auth/login'); - }); } private function registerAuthFolioDirectory(){ diff --git a/src/Events/TwoFactorAuthenticationDisabled.php b/src/Events/TwoFactorAuthenticationDisabled.php new file mode 100644 index 0000000..990ba26 --- /dev/null +++ b/src/Events/TwoFactorAuthenticationDisabled.php @@ -0,0 +1,8 @@ +user = $user; + } +} diff --git a/src/Livewire/Forms/TwoFactorAuthenticationForm.php b/src/Livewire/Forms/TwoFactorAuthenticationForm.php deleted file mode 100644 index 99ede4b..0000000 --- a/src/Livewire/Forms/TwoFactorAuthenticationForm.php +++ /dev/null @@ -1,180 +0,0 @@ -two_factor_confirmed_at)) { - app(DisableTwoFactorAuthentication::class)(Auth::user()); - } - } - - /** - * Enable two factor authentication for the user. - * - * @param \Laravel\Fortify\Actions\EnableTwoFactorAuthentication $enable - * @return void - */ - public function enableTwoFactorAuthentication(EnableTwoFactorAuthentication $enable) - { - // if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')) { - // $this->ensurePasswordIsConfirmed(); - // } - - $enable(Auth::user()); - - $this->showingQrCode = true; - - if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirm')) { - $this->showingConfirmation = true; - } else { - $this->showingRecoveryCodes = true; - } - } - - /** - * Confirm two factor authentication for the user. - * - * @param \Laravel\Fortify\Actions\ConfirmTwoFactorAuthentication $confirm - * @return void - */ - public function confirmTwoFactorAuthentication(ConfirmTwoFactorAuthentication $confirm) - { - // if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')) { - // $this->ensurePasswordIsConfirmed(); - // } - - $confirm(Auth::user(), $this->code); - - $this->showingQrCode = false; - $this->showingConfirmation = false; - $this->showingRecoveryCodes = true; - } - - /** - * Display the user's recovery codes. - * - * @return void - */ - public function showRecoveryCodes() - { - // if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')) { - // $this->ensurePasswordIsConfirmed(); - // } - - $this->showingRecoveryCodes = true; - } - - /** - * Generate new recovery codes for the user. - * - * @param \Laravel\Fortify\Actions\GenerateNewRecoveryCodes $generate - * @return void - */ - public function regenerateRecoveryCodes(GenerateNewRecoveryCodes $generate) - { - // if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')) { - // $this->ensurePasswordIsConfirmed(); - // } - - $generate(Auth::user()); - - $this->showingRecoveryCodes = true; - } - - /** - * Disable two factor authentication for the user. - * - * @param \Laravel\Fortify\Actions\DisableTwoFactorAuthentication $disable - * @return void - */ - public function disableTwoFactorAuthentication(DisableTwoFactorAuthentication $disable) - { - // if (Features::optionEnabled(Features::twoFactorAuthentication(), 'confirmPassword')) { - // $this->ensurePasswordIsConfirmed(); - // } - - $disable(Auth::user()); - - $this->showingQrCode = false; - $this->showingConfirmation = false; - $this->showingRecoveryCodes = false; - } - - /** - * Get the current user of the application. - * - * @return mixed - */ - public function getUserProperty() - { - return Auth::user(); - } - - /** - * Determine if two factor authentication is enabled. - * - * @return bool - */ - public function getEnabledProperty() - { - return ! empty($this->user->two_factor_secret); - } - - /** - * Render the component. - * - * @return \Illuminate\View\View - */ - public function render() - { - return view('auth::livewire.forms.two-factor-authentication-form'); - } -} diff --git a/src/Models/User.php b/src/Models/User.php index e15c332..49fcafa 100644 --- a/src/Models/User.php +++ b/src/Models/User.php @@ -6,11 +6,10 @@ use Devdojo\Auth\Traits\HasSocialProviders; use Illuminate\Contracts\Auth\MustVerifyEmail; use PragmaRX\Google2FA\Google2FA; -use Laravel\Fortify\TwoFactorAuthenticatable; class User extends Authenticatable implements MustVerifyEmail { - use HasSocialProviders, TwoFactorAuthenticatable; + use HasSocialProviders; protected $fillable = [ 'name', 'email', 'password', 'two_factor_secret', 'two_factor_recovery_codes', From 8851130ecbaf2ecf1f842fb8236b54728fca3482 Mon Sep 17 00:00:00 2001 From: Tony Lea Date: Sat, 11 May 2024 14:18:52 -0400 Subject: [PATCH 3/5] Adding a good amount more to 2FA --- resources/css/auth.css | 6 +- .../components/elements/input-code.blade.php | 2 +- resources/views/includes/head.blade.php | 2 +- resources/views/pages/auth/login.blade.php | 41 +++++++- .../pages/auth/two-factor-challenge.blade.php | 95 +++++++++++++------ .../two-factor-authentication/index.blade.php | 56 +++++++++-- .../GenerateNewRecoveryCodes.php | 8 +- .../GenerateQrCodeAndSecretKey.php | 3 +- src/AuthServiceProvider.php | 4 + src/Http/Middleware/TwoFactorChallenged.php | 23 +++++ 10 files changed, 190 insertions(+), 50 deletions(-) create mode 100644 src/Http/Middleware/TwoFactorChallenged.php diff --git a/resources/css/auth.css b/resources/css/auth.css index c6c3df2..0fdb68d 100644 --- a/resources/css/auth.css +++ b/resources/css/auth.css @@ -7,11 +7,11 @@ border: 1px solid #e1e1e5; } -input[type='number'].auth-code-input { +input[type='number'].auth-component-code-input { -moz-appearance:textfield; } -input.auth-code-input::-webkit-outer-spin-button, -input.auth-code-input::-webkit-inner-spin-button { +input.auth-component-code-input::-webkit-outer-spin-button, +input.auth-component-code-input::-webkit-inner-spin-button { -webkit-appearance: none; } \ No newline at end of file diff --git a/resources/views/components/elements/input-code.blade.php b/resources/views/components/elements/input-code.blade.php index 52827bf..12174f8 100644 --- a/resources/views/components/elements/input-code.blade.php +++ b/resources/views/components/elements/input-code.blade.php @@ -98,7 +98,7 @@ class="relative" type="number" x-on:paste="pasteValue" x-on:keydown="moveCursorNext({{ $x }}, {{ $digits }}, event)" - class="shadow-sm auth-code-input text-center appearance-none font-light text-black dark:text-dark-400 focus:!border-primary-600 w-12 h-12 border border-zinc-200 rounded-md" + class="w-12 h-12 font-light text-center text-black rounded-md border shadow-sm appearance-none auth-component-code-input dark:text-dark-400 border-zinc-200 focus:border-2" maxlength="1" /> @endfor diff --git a/resources/views/includes/head.blade.php b/resources/views/includes/head.blade.php index 26f0858..7e9b8ed 100644 --- a/resources/views/includes/head.blade.php +++ b/resources/views/includes/head.blade.php @@ -21,7 +21,7 @@ .auth-component-input{ color: {{ config('devdojo.auth.appearance.color.input_text') }} } - .auth-component-input:focus{ + .auth-component-input:focus, .auth-component-code-input:focus{ --tw-ring-color: rgb({{ $inputBorderRGBColor }} / var(--tw-ring-opacity)); border-color: rgb({{ $inputBorderRGBColor }} / var(--tw-border-opacity)); } diff --git a/resources/views/pages/auth/login.blade.php b/resources/views/pages/auth/login.blade.php index ec3cbb0..266df09 100644 --- a/resources/views/pages/auth/login.blade.php +++ b/resources/views/pages/auth/login.blade.php @@ -37,6 +37,8 @@ public $language = []; + public $twoFactorEnabled = true; + public function mount(){ $this->loadConfigs(); } @@ -57,14 +59,47 @@ public function authenticate() $this->validate(); - if (!Auth::attempt(['email' => $this->email, 'password' => $this->password])) { + $credentials = ['email' => $this->email, 'password' => $this->password]; + + + if(!\Auth::validate($credentials)){ + $this->addError('password', trans('auth.failed')); + return; + } + + $userAttemptingLogin = User::where('email', $this->email)->first(); + + if(!isset($userAttemptingLogin->id)){ $this->addError('password', trans('auth.failed')); return; } - event(new Login(auth()->guard('web'), User::where('email', $this->email)->first(), true)); + if($this->twoFactorEnabled && !is_null($userAttemptingLogin->two_factor_confirmed_at)){ + // We want this user to login via 2fa + session()->put([ + 'login.id' => $userAttemptingLogin->getKey() + ]); - return redirect()->intended('/'); + return redirect()->route('auth.two-factor-challenge'); + + } else { + if (!Auth::attempt($credentials)) { + $this->addError('password', trans('auth.failed')); + return; + } + event(new Login(auth()->guard('web'), User::where('email', $this->email)->first(), true)); + + return redirect()->intended('/'); + } + + + + /*$request->session()->put([ + 'login.id' => $user->getKey(), + 'login.remember' => $request->boolean('remember'), + ]);*/ + + } }; diff --git a/resources/views/pages/auth/two-factor-challenge.blade.php b/resources/views/pages/auth/two-factor-challenge.blade.php index 894cb26..c0dcce5 100644 --- a/resources/views/pages/auth/two-factor-challenge.blade.php +++ b/resources/views/pages/auth/two-factor-challenge.blade.php @@ -3,12 +3,15 @@ use App\Models\User; use function Laravel\Folio\{middleware, name}; use Illuminate\Support\Facades\Route; +use Illuminate\Auth\Events\Login; +use Livewire\Attributes\On; use Livewire\Volt\Component; use PragmaRX\Google2FA\Google2FA; use Devdojo\Auth\Traits\HasConfigs; use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\Auth; -//middleware(['guest']); +middleware(['two-factor-challenged', 'throttle:5,1']); name('auth.two-factor-challenge'); new class extends Component @@ -38,6 +41,32 @@ public function switchToRecovery() return; } + // TODO - Refactor the submitCode functionality into it's own trait so we can use this functionality here and user/two-factor-authenticaiton.blade.php + + #[On('submitCode')] + public function submitCode($code) + { + if(empty($code) || strlen($code) < 5){ + dd('show validation error'); + return; + } + + $google2fa = new Google2FA(); + $valid = $google2fa->verifyKey($this->secret, $code); + + + if($valid){ + $user = User::find(session()->get('login.id')); + + Auth::login($user); + event(new Login(auth()->guard('web'), User::where('email', $this->email)->first(), true)); + return redirect()->intended('/'); + } else { + + } + + } + public function submit_auth_code() { $google2fa = new Google2FA(); @@ -92,43 +121,49 @@ public function submit_recovery_code(){ @volt('auth.twofactorchallenge') - - @if(!$recovery) - - @else - - @endif - -
- +
@if(!$recovery) -
- -
+ @else -
- -
+ @endif - Continue - +
-
- or you can - @if(!$recovery) - login using a recovery code +
+ +
+ @error('auth_code') +

Incorrect Auth Code

+ @enderror + Continue @else - login using an authentication code +
+ +
+ Continue @endif -
+ + +
+ +
+ or you can + + @if(!$recovery) + login using a recovery code + @else + login using an authentication code + @endif + +
@endvolt diff --git a/resources/views/pages/user/two-factor-authentication/index.blade.php b/resources/views/pages/user/two-factor-authentication/index.blade.php index 38d48dd..0de1267 100644 --- a/resources/views/pages/user/two-factor-authentication/index.blade.php +++ b/resources/views/pages/user/two-factor-authentication/index.blade.php @@ -2,7 +2,7 @@ use function Laravel\Folio\{middleware, name}; use Livewire\Volt\Component; -use Livewire\Attributes\On; +use Livewire\Attributes\On; use PragmaRX\Google2FA\Google2FA; use Devdojo\Auth\Actions\TwoFactorAuth\DisableTwoFactorAuthentication; use Devdojo\Auth\Actions\TwoFactorAuth\GenerateNewRecoveryCodes; @@ -20,7 +20,7 @@ // confirmed means that it has been enabled and the user has confirmed a code public $confirmed = false; - public $showingConfirmation = false; + public $showRecoveryCodes = true; public $secret = ''; public $codes = ''; @@ -29,16 +29,19 @@ public function mount(){ if(is_null(auth()->user()->two_factor_confirmed_at)) { app(DisableTwoFactorAuthentication::class)(auth()->user()); + } else { + $this->confirmed = true; } } public function enable(){ + $QrCodeAndSecret = new GenerateQrCodeAndSecretKey(); [$this->qr, $this->secret] = $QrCodeAndSecret(auth()->user()); auth()->user()->forceFill([ 'two_factor_secret' => encrypt($this->secret), - 'two_factor_recovery_codes' => encrypt($this->generateCodes()) + 'two_factor_recovery_codes' => encrypt(json_encode($this->generateCodes())) ])->save(); $this->enabled = true; @@ -52,7 +55,8 @@ private function generateCodes(){ #[On('submitCode')] public function submitCode($code) { - if(empty($code) || strlen($code) < 5){ + if(empty($code) || strlen($code) < 6){ + // TODO - If the code is empty or it's less than 6 characters we want to show the user a message dd('show validation error'); return; } @@ -62,7 +66,25 @@ public function submitCode($code) $google2fa = new Google2FA(); $valid = $google2fa->verifyKey($this->secret, $code); - dd($valid); + if($valid){ + auth()->user()->forceFill([ + 'two_factor_confirmed_at' => now(), + ])->save(); + + $this->confirmed = true; + else { + // TODO - implement an invalid message when the user enters an incorrect auth code + dd('show invalide code message') + } + } + + public function disable(){ + $disable = new DisableTwoFactorAuthentication; + $disable(auth()->user()); + + $this->enabled = false; + $this->confirmed = false; + $this->showRecoveryCodes = true; } } @@ -72,10 +94,32 @@ public function submitCode($code) @volt('user.two-factor-authentication')
+ + +
@if($confirmed) -

Two-factor auth is current enabled and active for this user.

+
+

You have enabled two factor authentication.

+

When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone's Google Authenticator application.

+ @if($showRecoveryCodes) +
+

Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.

+
+ + @foreach (json_decode(decrypt(auth()->user()->two_factor_recovery_codes), true) as $code) +
{{ $code }}
+ @endforeach +
+
+ @endif +
+ Regenerate Recovery Codes + Disable +
+
+ @else @if(!$enabled)
diff --git a/src/Actions/TwoFactorAuth/GenerateNewRecoveryCodes.php b/src/Actions/TwoFactorAuth/GenerateNewRecoveryCodes.php index fd39297..c599b69 100644 --- a/src/Actions/TwoFactorAuth/GenerateNewRecoveryCodes.php +++ b/src/Actions/TwoFactorAuth/GenerateNewRecoveryCodes.php @@ -13,13 +13,11 @@ class GenerateNewRecoveryCodes * @param mixed $user * @return void */ - public function __invoke($user) + public function __invoke($user) : Collection { - $user->forceFill([ - 'two_factor_recovery_codes' => encrypt(json_encode(Collection::times(8, function () { + return Collection::times(8, function () { return $this->generate(); - })->all())), - ])->save(); + }); } public function generate(){ diff --git a/src/Actions/TwoFactorAuth/GenerateQrCodeAndSecretKey.php b/src/Actions/TwoFactorAuth/GenerateQrCodeAndSecretKey.php index 7cb9288..2e9f2c6 100644 --- a/src/Actions/TwoFactorAuth/GenerateQrCodeAndSecretKey.php +++ b/src/Actions/TwoFactorAuth/GenerateQrCodeAndSecretKey.php @@ -25,8 +25,9 @@ public function __invoke($user) : array //$secretKeyEncrypted = encrypt($secret_key); //echo $google2fa->generateSecretKey(); + // TODO - Make sure config('app.name') works below. $g2faUrl = $google2fa->getQRCodeUrl( - 'Auth', + config('app.name'), $user->email, $secret_key ); diff --git a/src/AuthServiceProvider.php b/src/AuthServiceProvider.php index 2e06793..1d82ddc 100644 --- a/src/AuthServiceProvider.php +++ b/src/AuthServiceProvider.php @@ -9,6 +9,8 @@ use Illuminate\Support\Facades\Blade; use Illuminate\Support\ServiceProvider; use PragmaRX\Google2FA\Google2FA; +use Illuminate\Support\Facades\Route; +use Devdojo\Auth\Http\Middleware\TwoFactorChallenged; class AuthServiceProvider extends ServiceProvider { @@ -18,6 +20,8 @@ class AuthServiceProvider extends ServiceProvider public function boot() { + Route::middlewareGroup('two-factor-challenged', [TwoFactorChallenged::class]); + /* * Optional methods to load your package assets */ diff --git a/src/Http/Middleware/TwoFactorChallenged.php b/src/Http/Middleware/TwoFactorChallenged.php new file mode 100644 index 0000000..e2a7637 --- /dev/null +++ b/src/Http/Middleware/TwoFactorChallenged.php @@ -0,0 +1,23 @@ +has('login.id')) { + return redirect()->route('auth.login'); + } + return $next($request); + } +} From e2157263a5f828c7f80a9a5873caf2f1d559620d Mon Sep 17 00:00:00 2001 From: Tony Lea Date: Sat, 11 May 2024 16:43:08 -0400 Subject: [PATCH 4/5] Adding updates to the latest 2fa functionality --- config/devdojo/auth/descriptions.php | 3 +- package.json | 3 +- .../components/elements/button.blade.php | 17 ++++++- .../components/elements/input-code.blade.php | 3 ++ resources/views/pages/auth/login.blade.php | 2 + .../pages/auth/two-factor-challenge.blade.php | 20 +++++--- .../two-factor-authentication/index.blade.php | 51 ++++++++++--------- routes/web.php | 18 ------- src/Http/Controllers/LogoutController.php | 18 +------ 9 files changed, 68 insertions(+), 67 deletions(-) diff --git a/config/devdojo/auth/descriptions.php b/config/devdojo/auth/descriptions.php index b13ee64..0e90cf4 100644 --- a/config/devdojo/auth/descriptions.php +++ b/config/devdojo/auth/descriptions.php @@ -10,6 +10,7 @@ 'registration_include_name_field' => 'During registration, include the Name field.', 'registration_require_email_verification' => 'During registration, require users to verify their email.', 'enable_branding' => 'This will toggle on/off the Auth branding at the bottom of each auth screen. Consider leaving on to support and help grow this project.', - 'dev_mode' => 'This is for development mode, when set in Dev Mode Assets will be loaded from Vite' + 'dev_mode' => 'This is for development mode, when set in Dev Mode Assets will be loaded from Vite', + 'enable_2fa' => 'Enable the ability for users to turn on Two Factor Authentication' ] ]; \ No newline at end of file diff --git a/package.json b/package.json index 5f14614..858f918 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@invoate/alpine-query-string": "^1.0.0", "highlightjs": "^9.16.2", "phaser": "^3.80.1", - "split.js": "^1.6.5" + "split.js": "^1.6.5", + "@tailwindcss/container-queries": "^0.1.1" } } diff --git a/resources/views/components/elements/button.blade.php b/resources/views/components/elements/button.blade.php index cf4d1fa..b7bb0f3 100644 --- a/resources/views/components/elements/button.blade.php +++ b/resources/views/components/elements/button.blade.php @@ -17,6 +17,19 @@ }; @endphp +@php + $typeClasses = match ($type) { + 'primary' => '', + 'secondary' => 'bg-zinc-100 border text-gray-500 hover:text-gray-700 border-zinc-100 dark:focus:ring-offset-gray-900 dark:border-gray-400/10 active:bg-white dark:focus:ring-gray-700 focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-200/60 dark:bg-gray-800/50 dark:hover:bg-gray-800/70 dark:text-gray-400 focus:shadow-outline', + 'success' => 'bg-green-600 text-white hover:bg-green-600/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-green-700/90 focus:ring-green-700', + 'info' => 'bg-blue-600 text-white hover:bg-blue-600/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-blue-700/90 focus:ring-blue-700', + 'warning' => 'bg-amber-500 text-white hover:bg-amber-500/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-amber-600/90 focus:ring-amber-600', + 'danger' => 'bg-red-600 text-white hover:bg-red-600/90 focus:ring-2 focus:ring-offset-2 dark:focus:ring-offset-gray-900 focus:bg-red-700/90 focus:ring-red-700', + }; + + $loadingTarget = $attributes['wire:target']; +@endphp + @php switch ($tag ?? 'button') { case 'button': @@ -35,7 +48,7 @@ } @endphp -<{!! $tagAttr !!} {!! $attributes->except(['class']) !!} class="{{ $sizeClasses }} auth-component-button opacity-[95%] hover:opacity-100 focus:ring-2 focus:ring-offset-2 cursor-pointer inline-flex items-center w-full justify-center disabled:opacity-50 font-semibold focus:outline-none" style="color:{{ config('devdojo.auth.appearance.color.button_text') }}; background-color:{{ config('devdojo.auth.appearance.color.button') }};"> - +<{!! $tagAttr !!} {!! $attributes->except(['class']) !!} class="@if($type == 'primary'){{ 'auth-component-button' }}@endif {{ $sizeClasses }} {{ $typeClasses }} opacity-[95%] hover:opacity-100 focus:ring-2 focus:ring-offset-2 cursor-pointer inline-flex items-center w-full justify-center disabled:opacity-50 font-semibold focus:outline-none" style="@if($type == 'primary') color:{{ config('devdojo.auth.appearance.color.button_text') }}; background-color:{{ config('devdojo.auth.appearance.color.button') }}; @endif"> + {{ $slot }} \ No newline at end of file diff --git a/resources/views/components/elements/input-code.blade.php b/resources/views/components/elements/input-code.blade.php index 12174f8..420cf32 100644 --- a/resources/views/components/elements/input-code.blade.php +++ b/resources/views/components/elements/input-code.blade.php @@ -31,6 +31,8 @@ this.$refs['input' + (index-1)].focus(); } } + } else { + this.$refs['input' + index].value = ''; } } else { @@ -98,6 +100,7 @@ class="relative" type="number" x-on:paste="pasteValue" x-on:keydown="moveCursorNext({{ $x }}, {{ $digits }}, event)" + x-on:focus="$el.select()" class="w-12 h-12 font-light text-center text-black rounded-md border shadow-sm appearance-none auth-component-code-input dark:text-dark-400 border-zinc-200 focus:border-2" maxlength="1" /> diff --git a/resources/views/pages/auth/login.blade.php b/resources/views/pages/auth/login.blade.php index 266df09..2fcb050 100644 --- a/resources/views/pages/auth/login.blade.php +++ b/resources/views/pages/auth/login.blade.php @@ -41,6 +41,7 @@ public function mount(){ $this->loadConfigs(); + $this->twoFactorEnabled = $this->settings->enable_2fa; } public function editIdentity(){ @@ -49,6 +50,7 @@ public function editIdentity(){ public function authenticate() { + if(!$this->showPasswordField){ $this->validateOnly('email'); $this->showPasswordField = true; diff --git a/resources/views/pages/auth/two-factor-challenge.blade.php b/resources/views/pages/auth/two-factor-challenge.blade.php index c0dcce5..9d2bfea 100644 --- a/resources/views/pages/auth/two-factor-challenge.blade.php +++ b/resources/views/pages/auth/two-factor-challenge.blade.php @@ -5,6 +5,7 @@ use Illuminate\Support\Facades\Route; use Illuminate\Auth\Events\Login; use Livewire\Attributes\On; +use Livewire\Attributes\Validate; use Livewire\Volt\Component; use PragmaRX\Google2FA\Google2FA; use Devdojo\Auth\Traits\HasConfigs; @@ -21,6 +22,7 @@ public $recovery = false; public $google2fa; + #[Validate('required|min:5')] public $auth_code; public $recovery_code; @@ -36,6 +38,7 @@ public function switchToRecovery() if($this->recovery){ $this->js("setTimeout(function(){ console.log('made'); window.dispatchEvent(new CustomEvent('focus-auth-2fa-recovery-code', {})); }, 10);"); } else { + // TODO - this we need to autofocus the first input of the auth code input $this->js("setTimeout(function(){ window.dispatchEvent(new CustomEvent('focus-auth-2fa-auth-code', {})); }, 10);"); } return; @@ -46,23 +49,28 @@ public function switchToRecovery() #[On('submitCode')] public function submitCode($code) { + $this->auth_code = $code; + + $this->validate(); + if(empty($code) || strlen($code) < 5){ dd('show validation error'); return; } - $google2fa = new Google2FA(); - $valid = $google2fa->verifyKey($this->secret, $code); + $user = User::find(session()->get('login.id')); + $secret = decrypt($user->two_factor_secret); + $google2fa = new Google2FA(); + $valid = $google2fa->verifyKey($secret, $code); if($valid){ - $user = User::find(session()->get('login.id')); Auth::login($user); - event(new Login(auth()->guard('web'), User::where('email', $this->email)->first(), true)); + event(new Login(auth()->guard('web'), $user, true)); return redirect()->intended('/'); } else { - + dd('invalid'); } } @@ -141,7 +149,7 @@ public function submit_recovery_code(){
@error('auth_code') -

Incorrect Auth Code

+

{{ $message }}

@enderror Continue @else diff --git a/resources/views/pages/user/two-factor-authentication/index.blade.php b/resources/views/pages/user/two-factor-authentication/index.blade.php index 0de1267..5b6160a 100644 --- a/resources/views/pages/user/two-factor-authentication/index.blade.php +++ b/resources/views/pages/user/two-factor-authentication/index.blade.php @@ -52,6 +52,15 @@ private function generateCodes(){ return $generateCodesFor(auth()->user()); } + public function cancelTwoFactor(){ + auth()->user()->forceFill([ + 'two_factor_secret' => null, + 'two_factor_recovery_codes' => null + ])->save(); + + $this->enabled = false; + } + #[On('submitCode')] public function submitCode($code) { @@ -72,9 +81,9 @@ public function submitCode($code) ])->save(); $this->confirmed = true; - else { + } else { // TODO - implement an invalid message when the user enters an incorrect auth code - dd('show invalide code message') + dd('show invalide code message'); } } @@ -93,19 +102,16 @@ public function disable(){ @volt('user.two-factor-authentication') -
- - - -
+
+
@if($confirmed)

You have enabled two factor authentication.

When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone's Google Authenticator application.

@if($showRecoveryCodes)
-

Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.

+

Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.

@foreach (json_decode(decrypt(auth()->user()->two_factor_recovery_codes), true) as $code) @@ -114,45 +120,44 @@ public function disable(){
@endif -
- Regenerate Recovery Codes - Disable +
+ Regenerate Codes + Disable 2FA
@else @if(!$enabled)
-

You have not enabled two factor authentication.

-

When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone's Google Authenticator application.

+

Two factor authentication disabled.

+

When you enabled 2FA, you will be prompted for a secure code during authentication. This code can be retrieved from your phone's Google Authenticator application.

- Enable + Enable
@else
-

Finish enabling two factor authentication.

-

When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone's Google Authenticator application.

-

To finish enabling two factor authentication, scan the following QR code using your phone's authenticator application or enter the setup key and provide the generated OTP code.

+

Finish enabling two factor authentication.

+

Enable two-factor authentication to receive a secure token from your phone's Google Authenticator during login.

+

To enable two-factor authentication, scan the QR code or enter the setup key using your phone's authenticator app and provide the OTP code.

-
+
-

+

{{ __('Setup Key') }}: {{ $secret }}

-
- Confirm - Cancel +
+ Cancel + Confirm
-
@endif @endif diff --git a/routes/web.php b/routes/web.php index 58743f1..19b8584 100644 --- a/routes/web.php +++ b/routes/web.php @@ -25,24 +25,6 @@ Route::get('/auth/logout', [LogoutController::class, 'getLogout'])->name('logout.get'); - - Route::get('g2fa', function(){ - $QrCodeAndSecret = new GenerateQrCodeAndSecretKey(); - [$qr, $secret] = $QrCodeAndSecret(auth()->user()); - echo ''; - // $secret should be saved to user database as two_factor_secret, but it should be encrypted like `encrypt($secret)` - - }); - - Route::get('getr', function(){ - $generateCodesFor = new GenerateNewRecoveryCodes(); - $generateCodesFor(auth()->user()); - }); - - Route::get('newr', function(){ - dd(auth()->user()->hasEnabledTwoFactorAuthentication()); - }); - }); diff --git a/src/Http/Controllers/LogoutController.php b/src/Http/Controllers/LogoutController.php index 3299349..d822c5f 100644 --- a/src/Http/Controllers/LogoutController.php +++ b/src/Http/Controllers/LogoutController.php @@ -8,24 +8,10 @@ class LogoutController { - public function __invoke() + public function __invoke(): RedirectResponse { Auth::logout(); - $this->redirectUserAfterLogout(); - } - - public function logout(Request $request) - { - Auth::logout(); - - $request->session()->invalidate(); - $request->session()->regenerateToken(); - - $this->redirectUserAfterLogout(); - } - - private function redirectUserAfterLogout() : RedirectResponse - { return redirect()->route('home'); } + } From a4b855f2ef95f1217fea0a3a0979fcd8f1e3d0bb Mon Sep 17 00:00:00 2001 From: Tony Lea Date: Sat, 11 May 2024 17:41:01 -0400 Subject: [PATCH 5/5] updating packages and removing unneccessary files --- package-lock.json | 180 +++--------------- package.json | 2 - public/build/assets/styles.css | 2 +- .../pages/auth/two-factor-challenge.blade.php | 38 +--- .../views/pages/auth/two-factor.blade.php | 170 ----------------- 5 files changed, 30 insertions(+), 362 deletions(-) delete mode 100644 resources/views/pages/auth/two-factor.blade.php diff --git a/package-lock.json b/package-lock.json index 273445a..da7be97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,9 +6,8 @@ "": { "dependencies": { "@invoate/alpine-query-string": "^1.0.0", - "highlightjs": "^9.16.2", - "phaser": "^3.80.1", - "split.js": "^1.6.5" + "@tailwindcss/container-queries": "^0.1.1", + "highlightjs": "^9.16.2" }, "devDependencies": { "@tailwindcss/forms": "^0.5.2", @@ -24,7 +23,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, "engines": { "node": ">=10" }, @@ -409,7 +407,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -426,7 +423,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -440,7 +436,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -449,7 +444,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -457,14 +451,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -474,7 +466,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -487,7 +478,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -496,7 +486,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -509,7 +498,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "optional": true, "engines": { "node": ">=14" @@ -723,6 +711,14 @@ "win32" ] }, + "node_modules/@tailwindcss/container-queries": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz", + "integrity": "sha512-p18dswChx6WnTSaJCSGx6lTmrGzNNvm2FtXmiO6AuA1V4U5REyoqwmT6kgAsIMdjo07QdAfYXHJ4hnMtfHzWgA==", + "peerDependencies": { + "tailwindcss": ">=3.2.0" + } + }, "node_modules/@tailwindcss/forms": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", @@ -745,7 +741,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -757,7 +752,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "engines": { "node": ">=12" }, @@ -768,14 +762,12 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -787,8 +779,7 @@ "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, "node_modules/asynckit": { "version": "0.4.0", @@ -847,14 +838,12 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, "engines": { "node": ">=8" }, @@ -866,7 +855,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -875,7 +863,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -919,7 +906,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, "engines": { "node": ">= 6" } @@ -948,7 +934,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -972,7 +957,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -984,7 +968,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -995,8 +978,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/combined-stream": { "version": "1.0.8", @@ -1014,7 +996,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, "engines": { "node": ">= 6" } @@ -1023,7 +1004,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1037,7 +1017,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, "bin": { "cssesc": "bin/cssesc" }, @@ -1057,20 +1036,17 @@ "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/electron-to-chromium": { "version": "1.4.738", @@ -1081,8 +1057,7 @@ "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/esbuild": { "version": "0.20.2", @@ -1131,16 +1106,10 @@ "node": ">=6" } }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" - }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -1156,7 +1125,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -1168,7 +1136,6 @@ "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -1177,7 +1144,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1209,7 +1175,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -1252,7 +1217,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -1266,7 +1230,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1275,7 +1238,6 @@ "version": "10.3.12", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", - "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.6", @@ -1297,7 +1259,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -1309,7 +1270,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -1327,7 +1287,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -1339,7 +1298,6 @@ "version": "2.13.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, "dependencies": { "hasown": "^2.0.0" }, @@ -1351,7 +1309,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -1360,7 +1317,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -1369,7 +1325,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -1381,7 +1336,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -1389,14 +1343,12 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/jackspeak": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -1414,7 +1366,6 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "dev": true, "bin": { "jiti": "bin/jiti.js" } @@ -1442,7 +1393,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, "engines": { "node": ">=10" } @@ -1450,14 +1400,12 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/lru-cache": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "dev": true, "engines": { "node": "14 || >=16.14" } @@ -1466,7 +1414,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } @@ -1475,7 +1422,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -1518,7 +1464,6 @@ "version": "9.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1533,7 +1478,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -1542,7 +1486,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -1553,7 +1496,6 @@ "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, "funding": [ { "type": "github", @@ -1577,7 +1519,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -1595,7 +1536,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -1604,7 +1544,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, "engines": { "node": ">= 6" } @@ -1613,7 +1552,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -1621,14 +1559,12 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", - "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -1640,25 +1576,15 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/phaser": { - "version": "3.80.1", - "resolved": "https://registry.npmjs.org/phaser/-/phaser-3.80.1.tgz", - "integrity": "sha512-VQGAWoDOkEpAWYkI+PUADv5Ql+SM0xpLuAMBJHz9tBcOLqjJ2wd8bUhxJgOqclQlLTg97NmMd9MhS75w16x1Cw==", - "dependencies": { - "eventemitter3": "^5.0.1" - } - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -1670,7 +1596,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -1679,7 +1604,6 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, "engines": { "node": ">= 6" } @@ -1688,7 +1612,6 @@ "version": "8.4.38", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", - "dev": true, "funding": [ { "type": "opencollective", @@ -1716,7 +1639,6 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -1733,7 +1655,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, "dependencies": { "camelcase-css": "^2.0.1" }, @@ -1752,7 +1673,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -1787,7 +1707,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", - "dev": true, "engines": { "node": ">=14" }, @@ -1799,7 +1718,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "dev": true, "dependencies": { "postcss-selector-parser": "^6.0.11" }, @@ -1818,7 +1736,6 @@ "version": "6.0.16", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", - "dev": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -1830,8 +1747,7 @@ "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/proxy-from-env": { "version": "1.1.0", @@ -1843,7 +1759,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -1863,7 +1778,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, "dependencies": { "pify": "^2.3.0" } @@ -1872,7 +1786,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -1884,7 +1797,6 @@ "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -1901,7 +1813,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -1946,7 +1857,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -1969,7 +1879,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -1981,7 +1890,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -1990,7 +1898,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -2002,21 +1909,14 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/split.js": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/split.js/-/split.js-1.6.5.tgz", - "integrity": "sha512-mPTnGCiS/RiuTNsVhCm9De9cCAUsrNFFviRbADdKiiV+Kk8HKp/0fWu7Kr8pi3/yBmsqLFHuXGT9UUZ+CNLwFw==" - }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -2034,7 +1934,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2048,7 +1947,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2056,14 +1954,12 @@ "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2075,7 +1971,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2091,7 +1986,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2103,7 +1997,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2112,7 +2005,6 @@ "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -2134,7 +2026,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -2146,7 +2037,6 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", - "dev": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -2183,7 +2073,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, "dependencies": { "any-promise": "^1.0.0" } @@ -2192,7 +2081,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -2204,7 +2092,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -2215,8 +2102,7 @@ "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/update-browserslist-db": { "version": "1.0.13", @@ -2251,8 +2137,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/vite": { "version": "5.2.9", @@ -2323,7 +2208,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -2338,7 +2222,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2356,7 +2239,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2373,7 +2255,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2382,7 +2263,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2396,14 +2276,12 @@ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2417,7 +2295,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2429,7 +2306,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", - "dev": true, "bin": { "yaml": "bin.mjs" }, diff --git a/package.json b/package.json index 858f918..05fbcee 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,6 @@ "dependencies": { "@invoate/alpine-query-string": "^1.0.0", "highlightjs": "^9.16.2", - "phaser": "^3.80.1", - "split.js": "^1.6.5", "@tailwindcss/container-queries": "^0.1.1" } } diff --git a/public/build/assets/styles.css b/public/build/assets/styles.css index f5d9c9a..ae86578 100644 --- a/public/build/assets/styles.css +++ b/public/build/assets/styles.css @@ -1 +1 @@ -*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color: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,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[type=text],input:where(:not([type])),[type=email],[type=url],[type=password],[type=number],[type=date],[type=datetime-local],[type=month],[type=search],[type=tel],[type=time],[type=week],[multiple],textarea,select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}[type=text]:focus,input:where(:not([type])):focus,[type=email]:focus,[type=url]:focus,[type=password]:focus,[type=number]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=month]:focus,[type=search]:focus,[type=tel]:focus,[type=time]:focus,[type=week]:focus,[multiple]:focus,textarea:focus,select:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow: 0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=checkbox]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=radio]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=radio]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:checked:hover,[type=checkbox]:checked:focus,[type=radio]:checked:hover,[type=radio]:checked:focus{border-color:transparent;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}@media (forced-colors: active){[type=checkbox]:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:indeterminate:hover,[type=checkbox]:indeterminate:focus{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,:before,:after{--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: rgb(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: rgb(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: }.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}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.-bottom-6{bottom:-1.5rem}.bottom-0{bottom:0}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.top-0{top:0}.top-\[16px\]{top:16px}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[98\]{z-index:98}.z-\[99\]{z-index:99}.mx-auto{margin-left:auto;margin-right:auto}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-7{margin-top:1.75rem;margin-bottom:1.75rem}.-mb-px{margin-bottom:-1px}.-ml-0{margin-left:-0px}.-ml-0\.5{margin-left:-.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-10{margin-bottom:2.5rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-2\.5{margin-left:.625rem}.ml-3{margin-left:.75rem}.ml-5{margin-left:1.25rem}.mr-1{margin-right:.25rem}.mr-1\.5{margin-right:.375rem}.mr-10{margin-right:2.5rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-2\.5{margin-top:.625rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-\[33px\]{margin-top:33px}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-20{height:5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-80{height:20rem}.h-9{height:2.25rem}.h-\[18px\]{height:18px}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.min-h-\[350px\]{min-height:350px}.min-h-screen{min-height:100vh}.w-1\/2{width:50%}.w-12{width:3rem}.w-2\/3{width:66.666667%}.w-20{width:5rem}.w-24{width:6rem}.w-28{width:7rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-40{width:10rem}.w-5{width:1.25rem}.w-5\/6{width:83.333333%}.w-6{width:1.5rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-80{width:20rem}.w-9{width:2.25rem}.w-auto{width:auto}.w-full{width:100%}.w-screen{width:100vw}.max-w-md{max-width:28rem}.max-w-screen-lg{max-width:1024px}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-shrink-0,.shrink-0{flex-shrink:0}.-translate-x-1{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\.5{--tw-translate-x: -.375rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-0{--tw-translate-y: -0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-0\.5{--tw-translate-y: -.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1{--tw-translate-y: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-3{--tw-translate-y: .75rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-4{--tw-translate-y: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-full{--tw-translate-y: 100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-rotate-45{--tw-rotate: -45deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.cursor-text{cursor:text}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.gap-1{gap:.25rem}.gap-6{gap:1.5rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.space-x-0>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(0px * var(--tw-space-x-reverse));margin-left:calc(0px * calc(1 - var(--tw-space-x-reverse)))}.space-x-0\.5>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.125rem * var(--tw-space-x-reverse));margin-left:calc(.125rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-1\.5>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.375rem * var(--tw-space-x-reverse));margin-left:calc(.375rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2\.5>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.625rem * var(--tw-space-x-reverse));margin-left:calc(.625rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.75rem * var(--tw-space-x-reverse));margin-left:calc(.75rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-5>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1.25rem * var(--tw-space-x-reverse));margin-left:calc(1.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-7>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1.75rem * var(--tw-space-x-reverse));margin-left:calc(1.75rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(2rem * var(--tw-space-x-reverse));margin-left:calc(2rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-zinc-200>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(228 228 231 / var(--tw-divide-opacity))}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.rounded-l-md{border-top-left-radius:.375rem;border-bottom-left-radius:.375rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.rounded-t-md{border-top-left-radius:.375rem;border-top-right-radius:.375rem}.rounded-tl-2xl{border-top-left-radius:1rem}.rounded-tr-md{border-top-right-radius:.375rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-l-0{border-left-width:0px}.border-r-0{border-right-width:0px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-gray-200\/60{border-color:#e5e7eb99}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.border-indigo-500{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity))}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity))}.border-red-300{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-yellow-300{--tw-border-opacity: 1;border-color:rgb(253 224 71 / var(--tw-border-opacity))}.border-zinc-100{--tw-border-opacity: 1;border-color:rgb(244 244 245 / var(--tw-border-opacity))}.border-zinc-200{--tw-border-opacity: 1;border-color:rgb(228 228 231 / var(--tw-border-opacity))}.border-zinc-300{--tw-border-opacity: 1;border-color:rgb(212 212 216 / var(--tw-border-opacity))}.border-zinc-800{--tw-border-opacity: 1;border-color:rgb(39 39 42 / var(--tw-border-opacity))}.border-b-zinc-200{--tw-border-opacity: 1;border-bottom-color:rgb(228 228 231 / var(--tw-border-opacity))}.bg-\[--btn-border\]{background-color:var(--btn-border)}.bg-black\/50{background-color:#00000080}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity: 1;background-color:rgb(220 252 231 / var(--tw-bg-opacity))}.bg-green-50{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity))}.bg-red-500\/70{background-color:#ef4444b3}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.bg-white\/50{background-color:#ffffff80}.bg-yellow-50{--tw-bg-opacity: 1;background-color:rgb(254 252 232 / var(--tw-bg-opacity))}.bg-zinc-100{--tw-bg-opacity: 1;background-color:rgb(244 244 245 / var(--tw-bg-opacity))}.bg-zinc-200{--tw-bg-opacity: 1;background-color:rgb(228 228 231 / var(--tw-bg-opacity))}.bg-zinc-200\/60{background-color:#e4e4e799}.bg-zinc-200\/70{background-color:#e4e4e7b3}.bg-zinc-300{--tw-bg-opacity: 1;background-color:rgb(212 212 216 / var(--tw-bg-opacity))}.bg-zinc-300\/40{background-color:#d4d4d866}.bg-zinc-50{--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity))}.bg-zinc-800{--tw-bg-opacity: 1;background-color:rgb(39 39 42 / var(--tw-bg-opacity))}.bg-zinc-900{--tw-bg-opacity: 1;background-color:rgb(24 24 27 / var(--tw-bg-opacity))}.fill-current{fill:currentColor}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-\[3px\]{padding:3px}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-10{padding-left:2.5rem;padding-right:2.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-7{padding-left:1.75rem;padding-right:1.75rem}.px-8{padding-left:2rem;padding-right:2rem}.px-\[calc\(theme\(spacing\[3\.5\]\)-1px\)\]{padding-left:calc(.875rem - 1px);padding-right:calc(.875rem - 1px)}.py-0{padding-top:0;padding-bottom:0}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-14{padding-top:3.5rem;padding-bottom:3.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-7{padding-top:1.75rem;padding-bottom:1.75rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-\[calc\(theme\(spacing\[2\.5\]\)-1px\)\]{padding-top:calc(.625rem - 1px);padding-bottom:calc(.625rem - 1px)}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-5{padding-bottom:1.25rem}.pb-6{padding-bottom:1.5rem}.pl-3{padding-left:.75rem}.pr-10{padding-right:2.5rem}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-5{padding-top:1.25rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[0\.6rem\]{font-size:.6rem}.text-\[15px\]{font-size:15px}.text-base,.text-base\/6{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}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-normal{line-height:1.5}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity))}.text-green-800{--tw-text-opacity: 1;color:rgb(22 101 52 / var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity))}.text-neutral-600{--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity))}.text-neutral-900{--tw-text-opacity: 1;color:rgb(23 23 23 / var(--tw-text-opacity))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity))}.text-red-900{--tw-text-opacity: 1;color:rgb(127 29 29 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.text-white\/40{color:#fff6}.text-yellow-600{--tw-text-opacity: 1;color:rgb(202 138 4 / var(--tw-text-opacity))}.text-zinc-400{--tw-text-opacity: 1;color:rgb(161 161 170 / var(--tw-text-opacity))}.text-zinc-500{--tw-text-opacity: 1;color:rgb(113 113 122 / var(--tw-text-opacity))}.text-zinc-600{--tw-text-opacity: 1;color:rgb(82 82 91 / var(--tw-text-opacity))}.text-zinc-700{--tw-text-opacity: 1;color:rgb(63 63 70 / var(--tw-text-opacity))}.text-zinc-800{--tw-text-opacity: 1;color:rgb(39 39 42 / var(--tw-text-opacity))}.text-zinc-900{--tw-text-opacity: 1;color:rgb(24 24 27 / var(--tw-text-opacity))}.underline{text-decoration-line:underline}.placeholder-red-300::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(252 165 165 / var(--tw-placeholder-opacity))}.placeholder-red-300::placeholder{--tw-placeholder-opacity: 1;color:rgb(252 165 165 / var(--tw-placeholder-opacity))}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.opacity-\[0\.98\]{opacity:.98}.opacity-\[47\%\]{opacity:47%}.opacity-\[67\%\]{opacity:67%}.opacity-\[95\%\]{opacity:95%}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(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)}.outline-none{outline:2px solid transparent;outline-offset:2px}.backdrop-blur-\[1px\]{--tw-backdrop-blur: blur(1px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.delay-500{transition-delay:.5s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[--btn-bg\:theme\(colors\.indigo\.500\)\]{--btn-bg: #6366f1}.\[--btn-border\:theme\(colors\.indigo\.600\/90\%\)\]{--btn-border: rgb(79 70 229 / 90%)}.\[--btn-hover-overlay\:theme\(colors\.white\/10\%\)\]{--btn-hover-overlay: rgb(255 255 255 / 10%)}.\[--btn-icon\:theme\(colors\.indigo\.200\)\]{--btn-icon: #c7d2fe}.CodeMirror{border-radius:6px;border:1px solid #e1e1e5}.placeholder\:text-gray-500::-moz-placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.placeholder\:text-gray-500::placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:inset-0:before{content:var(--tw-content);top:0;right:0;bottom:0;left:0}.before\:-z-10:before{content:var(--tw-content);z-index:-10}.before\:rounded-\[calc\(theme\(borderRadius\.lg\)-1px\)\]:before{content:var(--tw-content);border-radius:calc(.5rem - 1px)}.before\:bg-\[--btn-bg\]:before{content:var(--tw-content);background-color:var(--btn-bg)}.before\:shadow:before{content:var(--tw-content);--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:inset-0:after{content:var(--tw-content);top:0;right:0;bottom:0;left:0}.after\:start-\[2px\]:after{content:var(--tw-content);inset-inline-start:2px}.after\:top-\[2px\]:after{content:var(--tw-content);top:2px}.after\:-z-10:after{content:var(--tw-content);z-index:-10}.after\:h-3:after{content:var(--tw-content);height:.75rem}.after\:h-3\.5:after{content:var(--tw-content);height:.875rem}.after\:w-3:after{content:var(--tw-content);width:.75rem}.after\:w-3\.5:after{content:var(--tw-content);width:.875rem}.after\:rounded-\[calc\(theme\(borderRadius\.lg\)-1px\)\]:after{content:var(--tw-content);border-radius:calc(.5rem - 1px)}.after\:rounded-full:after{content:var(--tw-content);border-radius:9999px}.after\:border:after{content:var(--tw-content);border-width:1px}.after\:border-gray-300:after{content:var(--tw-content);--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.after\:bg-white:after{content:var(--tw-content);--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.after\:shadow-\[shadow\:inset_0_1px_theme\(colors\.white\/15\%\)\]:after{content:var(--tw-content);--tw-shadow: inset 0 1px rgb(255 255 255 / 15%);--tw-shadow-colored: inset 0 1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.after\:transition-all:after{content:var(--tw-content);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.after\:content-\[\'\'\]:after{--tw-content: "";content:var(--tw-content)}.hover\:border-blue-500:hover{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.hover\:border-gray-300:hover{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.hover\:border-zinc-200:hover{--tw-border-opacity: 1;border-color:rgb(228 228 231 / var(--tw-border-opacity))}.hover\:border-zinc-300:hover{--tw-border-opacity: 1;border-color:rgb(212 212 216 / var(--tw-border-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.hover\:bg-red-500\/90:hover{background-color:#ef4444e6}.hover\:bg-zinc-100:hover{--tw-bg-opacity: 1;background-color:rgb(244 244 245 / var(--tw-bg-opacity))}.hover\:bg-zinc-200:hover{--tw-bg-opacity: 1;background-color:rgb(228 228 231 / var(--tw-bg-opacity))}.hover\:bg-zinc-200\/70:hover{background-color:#e4e4e7b3}.hover\:bg-zinc-50:hover{--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity))}.hover\:bg-zinc-800\/70:hover{background-color:#27272ab3}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.hover\:text-white\/80:hover{color:#fffc}.hover\:text-zinc-700:hover{--tw-text-opacity: 1;color:rgb(63 63 70 / var(--tw-text-opacity))}.hover\:text-zinc-800:hover{--tw-text-opacity: 1;color:rgb(39 39 42 / var(--tw-text-opacity))}.hover\:text-zinc-900:hover{--tw-text-opacity: 1;color:rgb(24 24 27 / var(--tw-text-opacity))}.hover\:opacity-100:hover{opacity:1}.hover\:opacity-\[80\%\]:hover{opacity:80%}.hover\:shadow-md:hover{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:border-gray-300:focus{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.focus\:border-gray-900:focus{--tw-border-opacity: 1;border-color:rgb(17 24 39 / var(--tw-border-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity))}.focus\:border-red-300:focus{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity))}.focus\:underline:focus{text-decoration-line:underline}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-gray-200\/80:focus{--tw-ring-color: rgb(229 231 235 / .8)}.focus\:ring-gray-900:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(17 24 39 / var(--tw-ring-opacity))}.focus\:ring-indigo-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity))}.focus\:ring-zinc-800:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(39 39 42 / var(--tw-ring-opacity))}.focus\:ring-opacity-25:focus{--tw-ring-opacity: .25}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:-translate-x-0{--tw-translate-x: -0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:-translate-x-0\.5{--tw-translate-x: -.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:-translate-y-px{--tw-translate-y: -1px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:translate-x-px{--tw-translate-x: 1px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:scale-\[1\.03\]{--tw-scale-x: 1.03;--tw-scale-y: 1.03;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-zinc-600{--tw-text-opacity: 1;color:rgb(82 82 91 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.peer:checked~.peer-checked\:from-blue-600{--tw-gradient-from: #2563eb var(--tw-gradient-from-position);--tw-gradient-to: rgb(37 99 235 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.peer:checked~.peer-checked\:to-indigo-600{--tw-gradient-to: #4f46e5 var(--tw-gradient-to-position)}.peer:checked~.peer-checked\:text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:after\:translate-x-full:after{content:var(--tw-content);--tw-translate-x: 100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.peer:checked~.peer-checked\:after\:border-white:after{content:var(--tw-content);--tw-border-opacity: 1;border-color:rgb(255 255 255 / var(--tw-border-opacity))}.peer:focus~.peer-focus\:outline-none{outline:2px solid transparent;outline-offset:2px}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[focus\]\:outline[data-focus]{outline-style:solid}.data-\[focus\]\:outline-2[data-focus]{outline-width:2px}.data-\[focus\]\:outline-offset-2[data-focus]{outline-offset:2px}.data-\[focus\]\:outline-blue-500[data-focus]{outline-color:#3b82f6}.data-\[active\]\:\[--btn-icon\:theme\(colors\.indigo\.100\)\][data-active]{--btn-icon: #e0e7ff}.data-\[hover\]\:\[--btn-icon\:theme\(colors\.indigo\.200\)\][data-hover]{--btn-icon: #c7d2fe}.before\:data-\[disabled\]\:shadow-none[data-disabled]:before{content:var(--tw-content);--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)}.after\:data-\[active\]\:bg-\[--btn-hover-overlay\][data-active]:after{content:var(--tw-content);background-color:var(--btn-hover-overlay)}.after\:data-\[hover\]\:bg-\[--btn-hover-overlay\][data-hover]:after{content:var(--tw-content);background-color:var(--btn-hover-overlay)}.after\:data-\[disabled\]\:shadow-none[data-disabled]:after{content:var(--tw-content);--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)}@media (min-width: 640px){.sm\:top-auto{top:auto}.sm\:mx-auto{margin-left:auto;margin-right:auto}.sm\:ml-0{margin-left:0}.sm\:mr-0{margin-right:0}.sm\:block{display:block}.sm\:hidden{display:none}.sm\:h-full{height:100%}.sm\:w-full{width:100%}.sm\:max-w-md{max-width:28rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:items-center{align-items:center}.sm\:rounded-xl{border-radius:.75rem}.sm\:border{border-width:1px}.sm\:border-l{border-left-width:1px}.sm\:border-r{border-right-width:1px}.sm\:px-\[calc\(theme\(spacing\.3\)-1px\)\]{padding-left:calc(.75rem - 1px);padding-right:calc(.75rem - 1px)}.sm\:py-10{padding-top:2.5rem;padding-bottom:2.5rem}.sm\:py-\[calc\(theme\(spacing\[1\.5\]\)-1px\)\]{padding-top:calc(.375rem - 1px);padding-bottom:calc(.375rem - 1px)}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}.sm\:text-sm\/6{font-size:.875rem;line-height:1.5rem}}@media (min-width: 1024px){.lg\:p-0{padding:0}}.peer:checked~.rtl\:peer-checked\:after\:-translate-x-full:where([dir=rtl],[dir=rtl] *):after{content:var(--tw-content);--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@media (prefers-color-scheme: dark){.dark\:border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.dark\:border-gray-700{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity))}.dark\:border-white\/10{border-color:#ffffff1a}.dark\:border-white\/5{border-color:#ffffff0d}.dark\:bg-\[--btn-bg\]{background-color:var(--btn-bg)}.dark\:bg-gray-700{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity))}.dark\:bg-green-600{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity))}.dark\:bg-zinc-700{--tw-bg-opacity: 1;background-color:rgb(63 63 70 / var(--tw-bg-opacity))}.dark\:bg-zinc-950{--tw-bg-opacity: 1;background-color:rgb(9 9 11 / var(--tw-bg-opacity))}.dark\:text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.dark\:text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.dark\:text-green-200{--tw-text-opacity: 1;color:rgb(187 247 208 / var(--tw-text-opacity))}.dark\:text-neutral-400{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity))}.dark\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:\[--btn-bg\:theme\(colors\.indigo\.600\)\]{--btn-bg: #4f46e5}.dark\:\[--btn-hover-overlay\:theme\(colors\.white\/5\%\)\]{--btn-hover-overlay: rgb(255 255 255 / 5%)}.dark\:placeholder\:text-gray-400::-moz-placeholder{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:placeholder\:text-gray-400::placeholder{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:before\:hidden:before{content:var(--tw-content);display:none}.dark\:after\:-inset-px:after{content:var(--tw-content);top:-1px;right:-1px;bottom:-1px;left:-1px}.dark\:after\:rounded-lg:after{content:var(--tw-content);border-radius:.5rem}.dark\:hover\:border-gray-500:hover{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity))}.dark\:hover\:bg-gray-600:hover{--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.dark\:hover\:text-gray-300:hover{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.dark\:focus\:border-gray-700:focus{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity))}.peer:checked~.dark\:peer-checked\:text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}}@media (forced-colors: active){.forced-colors\:\[--btn-icon\:ButtonText\],.forced-colors\:data-\[hover\]\:\[--btn-icon\:ButtonText\][data-hover]{--btn-icon: ButtonText}}.\[\&\:has\(svg\)\]\:pl-11:has(svg){padding-left:2.75rem}.\[\&\>\[data-slot\=icon\]\]\:-mx-0\.5>[data-slot=icon]{margin-left:-.125rem;margin-right:-.125rem}.\[\&\>\[data-slot\=icon\]\]\:my-0\.5>[data-slot=icon]{margin-top:.125rem;margin-bottom:.125rem}.\[\&\>\[data-slot\=icon\]\]\:size-5>[data-slot=icon]{width:1.25rem;height:1.25rem}.\[\&\>\[data-slot\=icon\]\]\:shrink-0>[data-slot=icon]{flex-shrink:0}.\[\&\>\[data-slot\=icon\]\]\:text-\[--btn-icon\]>[data-slot=icon]{color:var(--btn-icon)}@media (min-width: 640px){.\[\&\>\[data-slot\=icon\]\]\:sm\:my-1>[data-slot=icon]{margin-top:.25rem;margin-bottom:.25rem}.\[\&\>\[data-slot\=icon\]\]\:sm\:size-4>[data-slot=icon]{width:1rem;height:1rem}}.\[\&\>button\:hover\]\:bg-zinc-100>button:hover{--tw-bg-opacity: 1;background-color:rgb(244 244 245 / var(--tw-bg-opacity))}.\[\&\>button\]\:block>button{display:block}.\[\&\>button\]\:w-full>button{width:100%}.\[\&\>button\]\:rounded-md>button{border-radius:.375rem}.\[\&\>button\]\:px-3>button{padding-left:.75rem;padding-right:.75rem}.\[\&\>button\]\:py-1\.5>button{padding-top:.375rem;padding-bottom:.375rem}.\[\&\>button\]\:text-left>button{text-align:left}.\[\&\>button\]\:text-sm>button{font-size:.875rem;line-height:1.25rem}.\[\&\>svg\+div\]\:translate-y-\[-3px\]>svg+div{--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>svg\]\:absolute>svg{position:absolute}.\[\&\>svg\]\:left-4>svg{left:1rem}.\[\&\>svg\]\:top-4>svg{top:1rem}.peer:checked~.peer-checked\:\[\&_\.custom-checkbox\]\:border-gray-800 .custom-checkbox{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity))}.peer:checked~.peer-checked\:\[\&_\.custom-checkbox\]\:bg-gray-800 .custom-checkbox{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}@media (prefers-color-scheme: dark){.peer:checked~.dark\:peer-checked\:\[\&_\.custom-checkbox\]\:bg-white .custom-checkbox{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}}.\[\&_svg\]\:scale-0 svg{--tw-scale-x: 0;--tw-scale-y: 0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.peer:checked~.peer-checked\:\[\&_svg\]\:scale-100 svg{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))} +*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}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;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color: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,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[type=text],input:where(:not([type])),[type=email],[type=url],[type=password],[type=number],[type=date],[type=datetime-local],[type=month],[type=search],[type=tel],[type=time],[type=week],[multiple],textarea,select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}[type=text]:focus,input:where(:not([type])):focus,[type=email]:focus,[type=url]:focus,[type=password]:focus,[type=number]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=month]:focus,[type=search]:focus,[type=tel]:focus,[type=time]:focus,[type=week]:focus,[multiple]:focus,textarea:focus,select:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow: 0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=checkbox]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=radio]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}@media (forced-colors: active){[type=radio]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:checked:hover,[type=checkbox]:checked:focus,[type=radio]:checked:hover,[type=radio]:checked:focus{border-color:transparent;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}@media (forced-colors: active){[type=checkbox]:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:indeterminate:hover,[type=checkbox]:indeterminate:focus{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,:before,:after{--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: rgb(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: rgb(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: }.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}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.-bottom-6{bottom:-1.5rem}.bottom-0{bottom:0}.left-0{left:0}.left-1\/2{left:50%}.right-0{right:0}.top-0{top:0}.top-\[16px\]{top:16px}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[98\]{z-index:98}.z-\[99\]{z-index:99}.mx-auto{margin-left:auto;margin-right:auto}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-7{margin-top:1.75rem;margin-bottom:1.75rem}.-mb-px{margin-bottom:-1px}.-ml-0{margin-left:-0px}.-ml-0\.5{margin-left:-.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-10{margin-bottom:2.5rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.me-3{margin-inline-end:.75rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-2\.5{margin-left:.625rem}.ml-3{margin-left:.75rem}.ml-5{margin-left:1.25rem}.mr-1{margin-right:.25rem}.mr-1\.5{margin-right:.375rem}.mr-10{margin-right:2.5rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-2\.5{margin-top:.625rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-\[33px\]{margin-top:33px}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-20{height:5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-80{height:20rem}.h-9{height:2.25rem}.h-\[18px\]{height:18px}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.min-h-\[350px\]{min-height:350px}.min-h-screen{min-height:100vh}.w-1\/2{width:50%}.w-12{width:3rem}.w-2\/3{width:66.666667%}.w-20{width:5rem}.w-24{width:6rem}.w-28{width:7rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-40{width:10rem}.w-5{width:1.25rem}.w-5\/6{width:83.333333%}.w-6{width:1.5rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-80{width:20rem}.w-9{width:2.25rem}.w-auto{width:auto}.w-full{width:100%}.w-screen{width:100vw}.max-w-full{max-width:100%}.max-w-md{max-width:28rem}.max-w-screen-lg{max-width:1024px}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-shrink-0,.shrink-0{flex-shrink:0}.-translate-x-1{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\.5{--tw-translate-x: -.375rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-0{--tw-translate-y: -0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-0\.5{--tw-translate-y: -.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1{--tw-translate-y: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-full{--tw-translate-y: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-3{--tw-translate-y: .75rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-4{--tw-translate-y: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-full{--tw-translate-y: 100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-rotate-45{--tw-rotate: -45deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.cursor-text{cursor:text}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-stretch{justify-content:stretch}.gap-1{gap:.25rem}.gap-6{gap:1.5rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.space-x-0>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(0px * var(--tw-space-x-reverse));margin-left:calc(0px * calc(1 - var(--tw-space-x-reverse)))}.space-x-0\.5>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.125rem * var(--tw-space-x-reverse));margin-left:calc(.125rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.25rem * var(--tw-space-x-reverse));margin-left:calc(.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-1\.5>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.375rem * var(--tw-space-x-reverse));margin-left:calc(.375rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-2\.5>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.625rem * var(--tw-space-x-reverse));margin-left:calc(.625rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.75rem * var(--tw-space-x-reverse));margin-left:calc(.75rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-5>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1.25rem * var(--tw-space-x-reverse));margin-left:calc(1.25rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-7>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(1.75rem * var(--tw-space-x-reverse));margin-left:calc(1.75rem * calc(1 - var(--tw-space-x-reverse)))}.space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(2rem * var(--tw-space-x-reverse));margin-left:calc(2rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-zinc-200>:not([hidden])~:not([hidden]){--tw-divide-opacity: 1;border-color:rgb(228 228 231 / var(--tw-divide-opacity))}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.rounded-l-md{border-top-left-radius:.375rem;border-bottom-left-radius:.375rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.rounded-t-md{border-top-left-radius:.375rem;border-top-right-radius:.375rem}.rounded-tl-2xl{border-top-left-radius:1rem}.rounded-tr-md{border-top-right-radius:.375rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-l-0{border-left-width:0px}.border-r-0{border-right-width:0px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity))}.border-gray-200\/60{border-color:#e5e7eb99}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.border-indigo-500{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity))}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity))}.border-red-300{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-yellow-300{--tw-border-opacity: 1;border-color:rgb(253 224 71 / var(--tw-border-opacity))}.border-zinc-100{--tw-border-opacity: 1;border-color:rgb(244 244 245 / var(--tw-border-opacity))}.border-zinc-200{--tw-border-opacity: 1;border-color:rgb(228 228 231 / var(--tw-border-opacity))}.border-zinc-300{--tw-border-opacity: 1;border-color:rgb(212 212 216 / var(--tw-border-opacity))}.border-zinc-800{--tw-border-opacity: 1;border-color:rgb(39 39 42 / var(--tw-border-opacity))}.border-b-zinc-200{--tw-border-opacity: 1;border-bottom-color:rgb(228 228 231 / var(--tw-border-opacity))}.bg-\[--btn-border\]{background-color:var(--btn-border)}.bg-amber-500{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity))}.bg-black\/50{background-color:#00000080}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity))}.bg-green-100{--tw-bg-opacity: 1;background-color:rgb(220 252 231 / var(--tw-bg-opacity))}.bg-green-50{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity))}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity))}.bg-green-600{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity: 1;background-color:rgb(254 226 226 / var(--tw-bg-opacity))}.bg-red-500\/70{background-color:#ef4444b3}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.bg-white\/50{background-color:#ffffff80}.bg-yellow-50{--tw-bg-opacity: 1;background-color:rgb(254 252 232 / var(--tw-bg-opacity))}.bg-zinc-100{--tw-bg-opacity: 1;background-color:rgb(244 244 245 / var(--tw-bg-opacity))}.bg-zinc-200{--tw-bg-opacity: 1;background-color:rgb(228 228 231 / var(--tw-bg-opacity))}.bg-zinc-200\/60{background-color:#e4e4e799}.bg-zinc-200\/70{background-color:#e4e4e7b3}.bg-zinc-300{--tw-bg-opacity: 1;background-color:rgb(212 212 216 / var(--tw-bg-opacity))}.bg-zinc-300\/40{background-color:#d4d4d866}.bg-zinc-50{--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity))}.bg-zinc-800{--tw-bg-opacity: 1;background-color:rgb(39 39 42 / var(--tw-bg-opacity))}.bg-zinc-900{--tw-bg-opacity: 1;background-color:rgb(24 24 27 / var(--tw-bg-opacity))}.fill-current{fill:currentColor}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-\[3px\]{padding:3px}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-10{padding-left:2.5rem;padding-right:2.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-7{padding-left:1.75rem;padding-right:1.75rem}.px-8{padding-left:2rem;padding-right:2rem}.px-\[calc\(theme\(spacing\[3\.5\]\)-1px\)\]{padding-left:calc(.875rem - 1px);padding-right:calc(.875rem - 1px)}.py-0{padding-top:0;padding-bottom:0}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-14{padding-top:3.5rem;padding-bottom:3.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-7{padding-top:1.75rem;padding-bottom:1.75rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-\[calc\(theme\(spacing\[2\.5\]\)-1px\)\]{padding-top:calc(.625rem - 1px);padding-bottom:calc(.625rem - 1px)}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-5{padding-bottom:1.25rem}.pb-6{padding-bottom:1.5rem}.pl-3{padding-left:.75rem}.pr-10{padding-right:2.5rem}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-5{padding-top:1.25rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[0\.6rem\]{font-size:.6rem}.text-\[15px\]{font-size:15px}.text-base,.text-base\/6{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}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-9{line-height:2.25rem}.leading-none{line-height:1}.leading-normal{line-height:1.5}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity))}.text-green-800{--tw-text-opacity: 1;color:rgb(22 101 52 / var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity))}.text-neutral-600{--tw-text-opacity: 1;color:rgb(82 82 82 / var(--tw-text-opacity))}.text-neutral-900{--tw-text-opacity: 1;color:rgb(23 23 23 / var(--tw-text-opacity))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity))}.text-red-900{--tw-text-opacity: 1;color:rgb(127 29 29 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.text-white\/40{color:#fff6}.text-yellow-600{--tw-text-opacity: 1;color:rgb(202 138 4 / var(--tw-text-opacity))}.text-zinc-400{--tw-text-opacity: 1;color:rgb(161 161 170 / var(--tw-text-opacity))}.text-zinc-500{--tw-text-opacity: 1;color:rgb(113 113 122 / var(--tw-text-opacity))}.text-zinc-600{--tw-text-opacity: 1;color:rgb(82 82 91 / var(--tw-text-opacity))}.text-zinc-700{--tw-text-opacity: 1;color:rgb(63 63 70 / var(--tw-text-opacity))}.text-zinc-800{--tw-text-opacity: 1;color:rgb(39 39 42 / var(--tw-text-opacity))}.text-zinc-900{--tw-text-opacity: 1;color:rgb(24 24 27 / var(--tw-text-opacity))}.underline{text-decoration-line:underline}.placeholder-red-300::-moz-placeholder{--tw-placeholder-opacity: 1;color:rgb(252 165 165 / var(--tw-placeholder-opacity))}.placeholder-red-300::placeholder{--tw-placeholder-opacity: 1;color:rgb(252 165 165 / var(--tw-placeholder-opacity))}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-60{opacity:.6}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.opacity-\[0\.98\]{opacity:.98}.opacity-\[47\%\]{opacity:47%}.opacity-\[67\%\]{opacity:67%}.opacity-\[95\%\]{opacity:95%}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(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)}.outline-none{outline:2px solid transparent;outline-offset:2px}.backdrop-blur-\[1px\]{--tw-backdrop-blur: blur(1px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.delay-500{transition-delay:.5s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[--btn-bg\:theme\(colors\.indigo\.500\)\]{--btn-bg: #6366f1}.\[--btn-border\:theme\(colors\.indigo\.600\/90\%\)\]{--btn-border: rgb(79 70 229 / 90%)}.\[--btn-hover-overlay\:theme\(colors\.white\/10\%\)\]{--btn-hover-overlay: rgb(255 255 255 / 10%)}.\[--btn-icon\:theme\(colors\.indigo\.200\)\]{--btn-icon: #c7d2fe}.CodeMirror{border-radius:6px;border:1px solid #e1e1e5}input[type=number].auth-component-code-input{-moz-appearance:textfield}input.auth-component-code-input::-webkit-outer-spin-button,input.auth-component-code-input::-webkit-inner-spin-button{-webkit-appearance:none}.placeholder\:text-gray-500::-moz-placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.placeholder\:text-gray-500::placeholder{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity))}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:inset-0:before{content:var(--tw-content);top:0;right:0;bottom:0;left:0}.before\:-z-10:before{content:var(--tw-content);z-index:-10}.before\:rounded-\[calc\(theme\(borderRadius\.lg\)-1px\)\]:before{content:var(--tw-content);border-radius:calc(.5rem - 1px)}.before\:bg-\[--btn-bg\]:before{content:var(--tw-content);background-color:var(--btn-bg)}.before\:shadow:before{content:var(--tw-content);--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:inset-0:after{content:var(--tw-content);top:0;right:0;bottom:0;left:0}.after\:start-\[2px\]:after{content:var(--tw-content);inset-inline-start:2px}.after\:top-\[2px\]:after{content:var(--tw-content);top:2px}.after\:-z-10:after{content:var(--tw-content);z-index:-10}.after\:h-3:after{content:var(--tw-content);height:.75rem}.after\:h-3\.5:after{content:var(--tw-content);height:.875rem}.after\:w-3:after{content:var(--tw-content);width:.75rem}.after\:w-3\.5:after{content:var(--tw-content);width:.875rem}.after\:rounded-\[calc\(theme\(borderRadius\.lg\)-1px\)\]:after{content:var(--tw-content);border-radius:calc(.5rem - 1px)}.after\:rounded-full:after{content:var(--tw-content);border-radius:9999px}.after\:border:after{content:var(--tw-content);border-width:1px}.after\:border-gray-300:after{content:var(--tw-content);--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.after\:bg-white:after{content:var(--tw-content);--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.after\:shadow-\[shadow\:inset_0_1px_theme\(colors\.white\/15\%\)\]:after{content:var(--tw-content);--tw-shadow: inset 0 1px rgb(255 255 255 / 15%);--tw-shadow-colored: inset 0 1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.after\:transition-all:after{content:var(--tw-content);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.after\:content-\[\'\'\]:after{--tw-content: "";content:var(--tw-content)}.hover\:border-blue-500:hover{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity))}.hover\:border-gray-300:hover{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.hover\:border-zinc-200:hover{--tw-border-opacity: 1;border-color:rgb(228 228 231 / var(--tw-border-opacity))}.hover\:border-zinc-300:hover{--tw-border-opacity: 1;border-color:rgb(212 212 216 / var(--tw-border-opacity))}.hover\:bg-amber-500\/90:hover{background-color:#f59e0be6}.hover\:bg-blue-600\/90:hover{background-color:#2563ebe6}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity))}.hover\:bg-green-600\/90:hover{background-color:#16a34ae6}.hover\:bg-red-500\/90:hover{background-color:#ef4444e6}.hover\:bg-red-600\/90:hover{background-color:#dc2626e6}.hover\:bg-zinc-100:hover{--tw-bg-opacity: 1;background-color:rgb(244 244 245 / var(--tw-bg-opacity))}.hover\:bg-zinc-200:hover{--tw-bg-opacity: 1;background-color:rgb(228 228 231 / var(--tw-bg-opacity))}.hover\:bg-zinc-200\/70:hover{background-color:#e4e4e7b3}.hover\:bg-zinc-50:hover{--tw-bg-opacity: 1;background-color:rgb(250 250 250 / var(--tw-bg-opacity))}.hover\:bg-zinc-800\/70:hover{background-color:#27272ab3}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.hover\:text-white\/80:hover{color:#fffc}.hover\:text-zinc-700:hover{--tw-text-opacity: 1;color:rgb(63 63 70 / var(--tw-text-opacity))}.hover\:text-zinc-800:hover{--tw-text-opacity: 1;color:rgb(39 39 42 / var(--tw-text-opacity))}.hover\:text-zinc-900:hover{--tw-text-opacity: 1;color:rgb(24 24 27 / var(--tw-text-opacity))}.hover\:opacity-100:hover{opacity:1}.hover\:opacity-\[80\%\]:hover{opacity:80%}.hover\:shadow-md:hover{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:border-2:focus{border-width:2px}.focus\:border-gray-300:focus{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity))}.focus\:border-gray-900:focus{--tw-border-opacity: 1;border-color:rgb(17 24 39 / var(--tw-border-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity))}.focus\:border-red-300:focus{--tw-border-opacity: 1;border-color:rgb(252 165 165 / var(--tw-border-opacity))}.focus\:bg-amber-600\/90:focus{background-color:#d97706e6}.focus\:bg-blue-700\/90:focus{background-color:#1d4ed8e6}.focus\:bg-green-700\/90:focus{background-color:#15803de6}.focus\:bg-red-700\/90:focus{background-color:#b91c1ce6}.focus\:bg-white:focus{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.focus\:underline:focus{text-decoration-line:underline}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-amber-600:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(217 119 6 / var(--tw-ring-opacity))}.focus\:ring-blue-700:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(29 78 216 / var(--tw-ring-opacity))}.focus\:ring-gray-200\/60:focus{--tw-ring-color: rgb(229 231 235 / .6)}.focus\:ring-gray-200\/80:focus{--tw-ring-color: rgb(229 231 235 / .8)}.focus\:ring-gray-900:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(17 24 39 / var(--tw-ring-opacity))}.focus\:ring-green-700:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(21 128 61 / var(--tw-ring-opacity))}.focus\:ring-indigo-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity))}.focus\:ring-red-700:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(185 28 28 / var(--tw-ring-opacity))}.focus\:ring-zinc-800:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(39 39 42 / var(--tw-ring-opacity))}.focus\:ring-opacity-25:focus{--tw-ring-opacity: .25}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.active\:bg-white:active{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:-translate-x-0{--tw-translate-x: -0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:-translate-x-0\.5{--tw-translate-x: -.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:-translate-y-px{--tw-translate-y: -1px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:translate-x-px{--tw-translate-x: 1px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:scale-\[1\.03\]{--tw-scale-x: 1.03;--tw-scale-y: 1.03;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-zinc-600{--tw-text-opacity: 1;color:rgb(82 82 91 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.peer:checked~.peer-checked\:from-blue-600{--tw-gradient-from: #2563eb var(--tw-gradient-from-position);--tw-gradient-to: rgb(37 99 235 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.peer:checked~.peer-checked\:to-indigo-600{--tw-gradient-to: #4f46e5 var(--tw-gradient-to-position)}.peer:checked~.peer-checked\:text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.peer:checked~.peer-checked\:after\:translate-x-full:after{content:var(--tw-content);--tw-translate-x: 100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.peer:checked~.peer-checked\:after\:border-white:after{content:var(--tw-content);--tw-border-opacity: 1;border-color:rgb(255 255 255 / var(--tw-border-opacity))}.peer:focus~.peer-focus\:outline-none{outline:2px solid transparent;outline-offset:2px}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[focus\]\:outline[data-focus]{outline-style:solid}.data-\[focus\]\:outline-2[data-focus]{outline-width:2px}.data-\[focus\]\:outline-offset-2[data-focus]{outline-offset:2px}.data-\[focus\]\:outline-blue-500[data-focus]{outline-color:#3b82f6}.data-\[active\]\:\[--btn-icon\:theme\(colors\.indigo\.100\)\][data-active]{--btn-icon: #e0e7ff}.data-\[hover\]\:\[--btn-icon\:theme\(colors\.indigo\.200\)\][data-hover]{--btn-icon: #c7d2fe}.before\:data-\[disabled\]\:shadow-none[data-disabled]:before{content:var(--tw-content);--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)}.after\:data-\[active\]\:bg-\[--btn-hover-overlay\][data-active]:after{content:var(--tw-content);background-color:var(--btn-hover-overlay)}.after\:data-\[hover\]\:bg-\[--btn-hover-overlay\][data-hover]:after{content:var(--tw-content);background-color:var(--btn-hover-overlay)}.after\:data-\[disabled\]\:shadow-none[data-disabled]:after{content:var(--tw-content);--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)}@media (min-width: 640px){.sm\:top-auto{top:auto}.sm\:mx-auto{margin-left:auto;margin-right:auto}.sm\:ml-0{margin-left:0}.sm\:mr-0{margin-right:0}.sm\:block{display:block}.sm\:hidden{display:none}.sm\:h-full{height:100%}.sm\:w-full{width:100%}.sm\:max-w-md{max-width:28rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:items-center{align-items:center}.sm\:rounded-xl{border-radius:.75rem}.sm\:border{border-width:1px}.sm\:border-l{border-left-width:1px}.sm\:border-r{border-right-width:1px}.sm\:px-\[calc\(theme\(spacing\.3\)-1px\)\]{padding-left:calc(.75rem - 1px);padding-right:calc(.75rem - 1px)}.sm\:py-10{padding-top:2.5rem;padding-bottom:2.5rem}.sm\:py-\[calc\(theme\(spacing\[1\.5\]\)-1px\)\]{padding-top:calc(.375rem - 1px);padding-bottom:calc(.375rem - 1px)}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}.sm\:text-sm\/6{font-size:.875rem;line-height:1.5rem}}@media (min-width: 1024px){.lg\:p-0{padding:0}}.peer:checked~.rtl\:peer-checked\:after\:-translate-x-full:where([dir=rtl],[dir=rtl] *):after{content:var(--tw-content);--tw-translate-x: -100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@media (prefers-color-scheme: dark){.dark\:border-gray-400\/10{border-color:#9ca3af1a}.dark\:border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity))}.dark\:border-gray-700{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity))}.dark\:border-white\/5{border-color:#ffffff0d}.dark\:bg-\[--btn-bg\]{background-color:var(--btn-bg)}.dark\:bg-gray-700{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity))}.dark\:bg-gray-800\/50{background-color:#1f293780}.dark\:bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(17 24 39 / var(--tw-bg-opacity))}.dark\:bg-green-600{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity))}.dark\:bg-zinc-700{--tw-bg-opacity: 1;background-color:rgb(63 63 70 / var(--tw-bg-opacity))}.dark\:bg-zinc-950{--tw-bg-opacity: 1;background-color:rgb(9 9 11 / var(--tw-bg-opacity))}.dark\:text-gray-100{--tw-text-opacity: 1;color:rgb(243 244 246 / var(--tw-text-opacity))}.dark\:text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.dark\:text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity))}.dark\:text-green-200{--tw-text-opacity: 1;color:rgb(187 247 208 / var(--tw-text-opacity))}.dark\:text-neutral-400{--tw-text-opacity: 1;color:rgb(163 163 163 / var(--tw-text-opacity))}.dark\:text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}.dark\:text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.dark\:\[--btn-bg\:theme\(colors\.indigo\.600\)\]{--btn-bg: #4f46e5}.dark\:\[--btn-hover-overlay\:theme\(colors\.white\/5\%\)\]{--btn-hover-overlay: rgb(255 255 255 / 5%)}.dark\:placeholder\:text-gray-400::-moz-placeholder{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:placeholder\:text-gray-400::placeholder{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity))}.dark\:before\:hidden:before{content:var(--tw-content);display:none}.dark\:after\:-inset-px:after{content:var(--tw-content);top:-1px;right:-1px;bottom:-1px;left:-1px}.dark\:after\:rounded-lg:after{content:var(--tw-content);border-radius:.5rem}.dark\:hover\:border-gray-500:hover{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity))}.dark\:hover\:bg-gray-600:hover{--tw-bg-opacity: 1;background-color:rgb(75 85 99 / var(--tw-bg-opacity))}.dark\:hover\:bg-gray-800\/70:hover{background-color:#1f2937b3}.dark\:hover\:text-gray-300:hover{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}.dark\:focus\:border-gray-700:focus{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity))}.dark\:focus\:ring-gray-700:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(55 65 81 / var(--tw-ring-opacity))}.dark\:focus\:ring-offset-gray-900:focus{--tw-ring-offset-color: #111827}.peer:checked~.dark\:peer-checked\:text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity))}}@media (forced-colors: active){.forced-colors\:\[--btn-icon\:ButtonText\],.forced-colors\:data-\[hover\]\:\[--btn-icon\:ButtonText\][data-hover]{--btn-icon: ButtonText}}.\[\&\:has\(svg\)\]\:pl-11:has(svg){padding-left:2.75rem}.\[\&\>\[data-slot\=icon\]\]\:-mx-0\.5>[data-slot=icon]{margin-left:-.125rem;margin-right:-.125rem}.\[\&\>\[data-slot\=icon\]\]\:my-0\.5>[data-slot=icon]{margin-top:.125rem;margin-bottom:.125rem}.\[\&\>\[data-slot\=icon\]\]\:size-5>[data-slot=icon]{width:1.25rem;height:1.25rem}.\[\&\>\[data-slot\=icon\]\]\:shrink-0>[data-slot=icon]{flex-shrink:0}.\[\&\>\[data-slot\=icon\]\]\:text-\[--btn-icon\]>[data-slot=icon]{color:var(--btn-icon)}@media (min-width: 640px){.\[\&\>\[data-slot\=icon\]\]\:sm\:my-1>[data-slot=icon]{margin-top:.25rem;margin-bottom:.25rem}.\[\&\>\[data-slot\=icon\]\]\:sm\:size-4>[data-slot=icon]{width:1rem;height:1rem}}.\[\&\>button\:hover\]\:bg-zinc-100>button:hover{--tw-bg-opacity: 1;background-color:rgb(244 244 245 / var(--tw-bg-opacity))}.\[\&\>button\]\:block>button{display:block}.\[\&\>button\]\:w-full>button{width:100%}.\[\&\>button\]\:rounded-md>button{border-radius:.375rem}.\[\&\>button\]\:px-3>button{padding-left:.75rem;padding-right:.75rem}.\[\&\>button\]\:py-1\.5>button{padding-top:.375rem;padding-bottom:.375rem}.\[\&\>button\]\:text-left>button{text-align:left}.\[\&\>button\]\:text-sm>button{font-size:.875rem;line-height:1.25rem}.\[\&\>svg\+div\]\:translate-y-\[-3px\]>svg+div{--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>svg\]\:absolute>svg{position:absolute}.\[\&\>svg\]\:left-4>svg{left:1rem}.\[\&\>svg\]\:top-4>svg{top:1rem}.peer:checked~.peer-checked\:\[\&_\.custom-checkbox\]\:border-gray-800 .custom-checkbox{--tw-border-opacity: 1;border-color:rgb(31 41 55 / var(--tw-border-opacity))}.peer:checked~.peer-checked\:\[\&_\.custom-checkbox\]\:bg-gray-800 .custom-checkbox{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity))}@media (prefers-color-scheme: dark){.peer:checked~.dark\:peer-checked\:\[\&_\.custom-checkbox\]\:bg-white .custom-checkbox{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}}.\[\&_svg\]\:scale-0 svg{--tw-scale-x: 0;--tw-scale-y: 0;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.peer:checked~.peer-checked\:\[\&_svg\]\:scale-100 svg{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))} diff --git a/resources/views/pages/auth/two-factor-challenge.blade.php b/resources/views/pages/auth/two-factor-challenge.blade.php index 9d2bfea..40257d6 100644 --- a/resources/views/pages/auth/two-factor-challenge.blade.php +++ b/resources/views/pages/auth/two-factor-challenge.blade.php @@ -75,18 +75,7 @@ public function submitCode($code) } - public function submit_auth_code() - { - $google2fa = new Google2FA(); - //$this->verify(auth()->user()->two_factor_secret, $this->auth_code, $google2fa); - $valid = $google2fa->verifyKey(decrypt(auth()->user()->two_factor_secret), $this->auth_code); - - if ($valid) { - dd('Valid!'); - } else { - dd('Failed'); - } - } + // TODO - Make sure that submitting the recovery codes work public function submit_recovery_code(){ $valid = in_array($this->recovery_code, auth()->user()->two_factor_recovery_codes); @@ -97,31 +86,6 @@ public function submit_recovery_code(){ dd('not valid'); } } - - /*private function verify($secret, $code, $google2fa) - { - $cachedTimestampKey = 'auth.2fa_codes.'.md5($code); - - if (is_int($customWindow = config('fortify-options.two-factor-authentication.window'))) { - $google2fa->setWindow($customWindow); - } - - $timestamp = $google2fa->verifyKeyNewer( - $secret, $code, Cache::get($cachedTimestampKey) - ); - - if ($timestamp !== false) { - if ($timestamp === true) { - $timestamp = $google2fa->getTimestamp(); - } - - optional($cache)->put($cachedTimestampKey, $timestamp, ($google2fa->getWindow() ?: 1) * 60); - - return true; - } - - return false; - }*/ } ?> diff --git a/resources/views/pages/auth/two-factor.blade.php b/resources/views/pages/auth/two-factor.blade.php deleted file mode 100644 index 71a41ef..0000000 --- a/resources/views/pages/auth/two-factor.blade.php +++ /dev/null @@ -1,170 +0,0 @@ - - - - @volt('auth.two-factor') -
-
-

- {{ __('Two Factor Authentication') }} -

- -

- {{ __('Add additional security to your account using two factor authentication.') }} -

- -
-

- - @if ($showingConfirmation) - {{ __('Finish enabling two factor authentication.') }} - @else - {{ __('You have enabled two factor authentication.') }} - @endif - -

- -
-

- {{ __('When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone\'s Google Authenticator application.') }} -

-
- - - @if ($showingQrCode) -
-

- @if ($showingConfirmation) - {{ __('To finish enabling two factor authentication, scan the following QR code using your phone\'s authenticator application or enter the setup key and provide the generated OTP code.') }} - @else - {{ __('Two factor authentication is now enabled. Scan the following QR code using your phone\'s authenticator application or enter the setup key.') }} - @endif -

-
- -
- {!! auth()->user()->twoFactorQrCodeSvg() !!} -
- -
-

- {{-- {{ __('Setup Key') }}: {{ decrypt(auth()->user()->two_factor_secret) }} --}} -

-
- - @if ($showingConfirmation) -
-
- @endif - @endif - - @if ($showingRecoveryCodes) -
-

- {{ __('Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.') }} -

-
- -
- {{-- @foreach (json_decode(decrypt(auth()->user()->two_factor_recovery_codes), true) as $code) -
{{ $code }}
- @endforeach --}} -
- @endif - -
- - @if ($showingRecoveryCodes) - - - - @elseif ($showingConfirmation) - - - - @else - - - - @endif - - @if ($showingConfirmation) - - - - @else - - - - @endif -
-
-
-
- @endvolt - -
\ No newline at end of file