diff --git a/app/Enums/EditorLanguages.php b/app/Enums/EditorLanguages.php new file mode 100644 index 0000000000..26f4520d93 --- /dev/null +++ b/app/Enums/EditorLanguages.php @@ -0,0 +1,98 @@ +name; + } +} diff --git a/app/Filament/App/Resources/ServerResource.php b/app/Filament/App/Resources/ServerResource.php new file mode 100644 index 0000000000..e63682b56e --- /dev/null +++ b/app/Filament/App/Resources/ServerResource.php @@ -0,0 +1,28 @@ + Pages\ListServers::route('/'), + ]; + } +} diff --git a/app/Filament/App/Resources/ServerResource/Pages/ListServers.php b/app/Filament/App/Resources/ServerResource/Pages/ListServers.php new file mode 100644 index 0000000000..8becc75542 --- /dev/null +++ b/app/Filament/App/Resources/ServerResource/Pages/ListServers.php @@ -0,0 +1,99 @@ +paginated(false) + ->query(fn () => auth()->user()->can('viewList server') ? Server::query() : auth()->user()->accessibleServers()) + ->columns([ + Stack::make([ + ServerEntryColumn::make('server_entry') + ->searchable(['name']), + ]), + ]) + ->contentGrid([ + 'default' => 1, + 'xl' => 2, + ]) + ->recordUrl(fn (Server $server) => Console::getUrl(panel: 'server', tenant: $server)) + ->emptyStateIcon('tabler-brand-docker') + ->emptyStateDescription('') + ->emptyStateHeading('You don\'t have access to any servers!'); + } + + // @phpstan-ignore-next-line + private function uptime(Server $server): string + { + $uptime = collect(cache()->get("servers.{$server->id}.uptime"))->last() ?? 0; + + if ($uptime === 0) { + return 'Offline'; + } + + return now()->subMillis($uptime)->diffForHumans(syntax: CarbonInterface::DIFF_ABSOLUTE, short: true, parts: 2); + } + + // @phpstan-ignore-next-line + private function cpu(Server $server): string + { + $cpu = Number::format(collect(cache()->get("servers.{$server->id}.cpu_absolute"))->last() ?? 0, maxPrecision: 2, locale: auth()->user()->language) . '%'; + $max = Number::format($server->cpu, locale: auth()->user()->language) . '%'; + + return $cpu . ($server->cpu > 0 ? ' Of ' . $max : ''); + } + + // @phpstan-ignore-next-line + private function memory(Server $server): string + { + $latestMemoryUsed = collect(cache()->get("servers.{$server->id}.memory_bytes"))->last() ?? 0; + $totalMemory = collect(cache()->get("servers.{$server->id}.memory_limit_bytes"))->last() ?? 0; + + $used = config('panel.use_binary_prefix') + ? Number::format($latestMemoryUsed / 1024 / 1024 / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB' + : Number::format($latestMemoryUsed / 1000 / 1000 / 1000, maxPrecision: 2, locale: auth()->user()->language) . ' GB'; + + if ($totalMemory === 0) { + $total = config('panel.use_binary_prefix') + ? Number::format($server->memory / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB' + : Number::format($server->memory / 1000, maxPrecision: 2, locale: auth()->user()->language) . ' GB'; + } else { + $total = config('panel.use_binary_prefix') + ? Number::format($totalMemory / 1024 / 1024 / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB' + : Number::format($totalMemory / 1000 / 1000 / 1000, maxPrecision: 2, locale: auth()->user()->language) . ' GB'; + } + + return $used . ($server->memory > 0 ? ' Of ' . $total : ''); + } + + // @phpstan-ignore-next-line + private function disk(Server $server): string + { + $usedDisk = collect(cache()->get("servers.{$server->id}.disk_bytes"))->last() ?? 0; + + $used = config('panel.use_binary_prefix') + ? Number::format($usedDisk / 1024 / 1024 / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB' + : Number::format($usedDisk / 1000 / 1000 / 1000, maxPrecision: 2, locale: auth()->user()->language) . ' GB'; + + $total = config('panel.use_binary_prefix') + ? Number::format($server->disk / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB' + : Number::format($server->disk / 1000, maxPrecision: 2, locale: auth()->user()->language) . ' GB'; + + return $used . ($server->disk > 0 ? ' Of ' . $total : ''); + } +} diff --git a/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php b/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php index 606b9ca82b..fd281793c6 100644 --- a/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php +++ b/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php @@ -82,6 +82,7 @@ public function form(Form $form): Form Select::make('node_id') ->searchable() ->preload() + ->unique() ->helperText('This setting only defaults to this database host when adding a database to a server on the selected node.') ->label('Linked Node') ->relationship('node', 'name'), diff --git a/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php b/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php index 424482fde2..2ff8fd040b 100644 --- a/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php +++ b/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php @@ -77,6 +77,7 @@ public function form(Form $form): Form Select::make('node_id') ->searchable() ->preload() + ->unique() ->helperText('This setting only defaults to this database host when adding a database to a server on the selected node.') ->label('Linked Node') ->relationship('node', 'name'), diff --git a/app/Filament/Resources/RoleResource.php b/app/Filament/Resources/RoleResource.php index 510a03a88e..20f4516c99 100644 --- a/app/Filament/Resources/RoleResource.php +++ b/app/Filament/Resources/RoleResource.php @@ -91,6 +91,8 @@ private static function makeSection(string $model, array $options): Section $icon = ('\App\Filament\Resources\\' . $model . 'Resource')::getNavigationIcon(); } elseif (class_exists('\App\Filament\Pages\\' . $model)) { $icon = ('\App\Filament\Pages\\' . $model)::getNavigationIcon(); + } elseif (class_exists('\App\Filament\Server\Resources\\' . $model . 'Resource')) { + $icon = ('\App\Filament\Server\Resources\\' . $model . 'Resource')::getNavigationIcon(); } return Section::make(Str::headline(Str::plural($model))) diff --git a/app/Filament/Resources/ServerResource/Pages/EditServer.php b/app/Filament/Resources/ServerResource/Pages/EditServer.php index a61a4e3bba..172c1ebf45 100644 --- a/app/Filament/Resources/ServerResource/Pages/EditServer.php +++ b/app/Filament/Resources/ServerResource/Pages/EditServer.php @@ -512,23 +512,19 @@ public function form(Form $form): Form ->label('Startup Command') ->required() ->columnSpan(6) - ->rows(function ($state) { - return str($state)->explode("\n")->reduce( - fn (int $carry, $line) => $carry + floor(strlen($line) / 125), - 0 - ); - }), + ->autosize(), Textarea::make('defaultStartup') ->hintAction(CopyAction::make()) ->label('Default Startup Command') ->disabled() + ->autosize() + ->columnSpan(6) ->formatStateUsing(function ($state, Get $get) { $egg = Egg::query()->find($get('egg_id')); return $egg->startup; - }) - ->columnSpan(6), + }), Repeater::make('server_variables') ->relationship('serverVariables', function (Builder $query) { @@ -868,7 +864,7 @@ protected function getHeaderActions(): array ->action(function (Server $server, ServerDeletionService $service) { $service->handle($server); - return redirect(ListServers::getUrl()); + return redirect(ListServers::getUrl(panel: 'admin')); }) ->authorize(fn (Server $server) => auth()->user()->can('delete server', $server)), Actions\Action::make('console') diff --git a/app/Filament/Resources/ServerResource/Pages/ListServers.php b/app/Filament/Resources/ServerResource/Pages/ListServers.php index dd6fc4a16a..d43e09cfef 100644 --- a/app/Filament/Resources/ServerResource/Pages/ListServers.php +++ b/app/Filament/Resources/ServerResource/Pages/ListServers.php @@ -2,6 +2,7 @@ namespace App\Filament\Resources\ServerResource\Pages; +use App\Filament\Server\Pages\Console; use App\Filament\Resources\ServerResource; use App\Models\Server; use Filament\Actions; @@ -82,8 +83,8 @@ public function table(Table $table): Table ->actions([ Action::make('View') ->icon('tabler-terminal') - ->url(fn (Server $server) => "/server/$server->uuid_short") - ->authorize(fn () => auth()->user()->can('view server')), + ->url(fn (Server $server) => Console::getUrl(panel: 'server', tenant: $server)) + ->authorize(fn (Server $server) => auth()->user()->canAccessTenant($server)), EditAction::make(), ]) ->emptyStateIcon('tabler-brand-docker') diff --git a/app/Filament/Resources/UserResource/Pages/EditProfile.php b/app/Filament/Resources/UserResource/Pages/EditProfile.php index 3895422539..987b4a9fac 100644 --- a/app/Filament/Resources/UserResource/Pages/EditProfile.php +++ b/app/Filament/Resources/UserResource/Pages/EditProfile.php @@ -31,6 +31,7 @@ use Filament\Forms\Components\TextInput; use Filament\Forms\Get; use Filament\Notifications\Notification; +use Filament\Support\Enums\MaxWidth; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Hash; @@ -51,6 +52,11 @@ public function boot(ToggleTwoFactorService $toggleTwoFactorService): void $this->toggleTwoFactorService = $toggleTwoFactorService; } + public function getMaxWidth(): MaxWidth|string + { + return MaxWidth::SevenExtraLarge; + } + protected function getForms(): array { return [ @@ -236,7 +242,7 @@ protected function getForms(): array ->content(fn () => new HtmlString("
$image
")) - ->helperText('Setup Key: '. $secret), + ->helperText('Setup Key: ' . $secret), TextInput::make('2facode') ->label('Code') ->requiredWith('2fapassword') @@ -368,4 +374,17 @@ public function exception(Exception $e, Closure $stopPropagation): void $stopPropagation(); } } + + protected function getFormActions(): array + { + return []; + } + + protected function getHeaderActions(): array + { + return [ + $this->getSaveFormAction()->formId('form'), + ]; + + } } diff --git a/app/Filament/Server/Pages/Console.php b/app/Filament/Server/Pages/Console.php new file mode 100644 index 0000000000..cd3fb46d03 --- /dev/null +++ b/app/Filament/Server/Pages/Console.php @@ -0,0 +1,72 @@ + Filament::getTenant(), + 'user' => auth()->user(), + ]; + } + + public function getWidgets(): array + { + return [ + ServerOverview::class, + ServerConsole::class, + ServerCpuChart::class, + ServerMemoryChart::class, + //ServerNetworkChart::class, TODO: convert units. + ]; + } + + public function getVisibleWidgets(): array + { + return $this->filterVisibleWidgets($this->getWidgets()); + } + + public function getColumns(): int|string|array + { + return 3; + } + + protected function getHeaderActions(): array + { + /** @var Server $server */ + $server = Filament::getTenant(); + + return [ + Action::make('start') + ->color('primary') + ->action(fn () => $this->dispatch('setServerState', state: 'start')) + ->disabled(fn () => $server->isInConflictState()), + Action::make('restart') + ->color('gray') + ->action(fn () => $this->dispatch('setServerState', state: 'restart')) + ->disabled(fn () => $server->isInConflictState() || $server->retrieveStatus() == 'offline'), + Action::make('stop') + ->color('danger') + ->action(fn () => $this->dispatch('setServerState', state: 'stop')) + ->disabled(fn () => $server->isInConflictState() || $server->retrieveStatus() == 'offline'), + ]; + } +} diff --git a/app/Filament/Server/Pages/ServerFormPage.php b/app/Filament/Server/Pages/ServerFormPage.php new file mode 100644 index 0000000000..da9866615a --- /dev/null +++ b/app/Filament/Server/Pages/ServerFormPage.php @@ -0,0 +1,79 @@ +authorizeAccess(); + + $this->fillForm(); + } + + protected function authorizeAccess(): void {} + + protected function fillForm(): void + { + $data = $this->getRecord()->attributesToArray(); + $this->form->fill($data); + } + + /** + * @return array + */ + protected function getForms(): array + { + return [ + 'form' => $this->form($this->makeForm() + ->model($this->getRecord()) + ->statePath($this->getFormStatePath()) + ->columns($this->hasInlineLabels() ? 1 : 2) + ->inlineLabel($this->hasInlineLabels()), + ), + ]; + } + + public function getFormStatePath(): ?string + { + return 'data'; + } + + public function getRecord(): Server + { + /** @var Server $server */ + $server = Filament::getTenant(); + + return $server; + } + + // TODO: find better way handle server conflict state + public static function canAccess(): bool + { + /** @var Server $server */ + $server = Filament::getTenant(); + + if ($server->isInConflictState()) { + return false; + } + + return parent::canAccess(); + } +} diff --git a/app/Filament/Server/Pages/Settings.php b/app/Filament/Server/Pages/Settings.php new file mode 100644 index 0000000000..1095c8e06c --- /dev/null +++ b/app/Filament/Server/Pages/Settings.php @@ -0,0 +1,271 @@ +columns([ + 'default' => 1, + 'sm' => 2, + 'md' => 4, + 'lg' => 6, + ]) + ->schema([ + Section::make('Server Information') + ->columns([ + 'default' => 1, + 'sm' => 2, + 'md' => 4, + 'lg' => 6, + ]) + ->schema([ + Fieldset::make('Server') + ->label('Information') + ->schema([ + TextInput::make('name') + ->label('Server Name') + ->disabled(!auth()->user()->can(Permission::ACTION_SETTINGS_RENAME, $server)) + ->required() + ->columnSpan([ + 'default' => 1, + 'sm' => 2, + 'md' => 4, + 'lg' => 6, + ]) + ->live(onBlur: true) + ->afterStateUpdated(fn ($state, Server $server) => $this->updateName($state, $server)), + Textarea::make('description') + ->label('Server Description') + ->disabled(!auth()->user()->can(Permission::ACTION_SETTINGS_RENAME, $server)) + ->columnSpan([ + 'default' => 1, + 'sm' => 2, + 'md' => 4, + 'lg' => 6, + ]) + ->autosize() + ->live(onBlur: true) + ->afterStateUpdated(fn ($state, Server $server) => $this->updateDescription($state ?? '', $server)), + TextInput::make('uuid') + ->label('Server UUID') + ->columnSpan([ + 'default' => 1, + 'sm' => 1, + 'md' => 3, + 'lg' => 5, + ]) + ->disabled(), + TextInput::make('id') + ->label('Server ID') + ->disabled() + ->columnSpan(1), + ]), + Fieldset::make('Limits') + ->label('Limits') + ->columns([ + 'default' => 1, + 'sm' => 1, + 'md' => 3, + 'lg' => 3, + ]) + ->schema([ + TextInput::make('backup_limit') + ->label('Backup Limit') + ->columnSpan(1) + ->disabled() + ->formatStateUsing(fn ($state, Server $server) => !$state ? 'No Backups can be created' : $server->backups->count() . ' of ' . $state), + TextInput::make('database_limit') + ->label('Database Limit') + ->columnSpan(1) + ->disabled() + ->formatStateUsing(fn ($state, Server $server) => !$state ? 'No Databases can be created' : $server->databases->count() . ' of ' . $state), + TextInput::make('allocation_limit') + ->label('Allocation Limit') + ->columnSpan(1) + ->disabled() + ->formatStateUsing(fn ($state, Server $server) => !$state ? 'No additional Allocations can be created' : $server->allocations->count() . ' of ' . ($state + 1)), + ]), + ]), + Section::make('Node Information') + ->schema([ + TextInput::make('node.name') + ->label('Node Name') + ->formatStateUsing(fn (Server $server) => $server->node->name) + ->disabled(), + Fieldset::make('SFTP Information') + ->hidden(fn () => !auth()->user()->can(Permission::ACTION_FILE_SFTP, $server)) + ->label('SFTP Information') + ->columns([ + 'default' => 1, + 'sm' => 1, + 'md' => 3, + 'lg' => 3, + ]) + ->schema([ + TextInput::make('connection') + ->label('Connection') + ->columnSpan(1) + ->disabled() + ->hintActions([ + Action::make('connect_sftp') + ->label('Connect to SFTP') + ->color('success') + ->icon('tabler-plug') + ->url(function (Server $server) { + $fqdn = $server->node->daemon_sftp_alias ?? $server->node->fqdn; + + return 'sftp://' . auth()->user()->username . '.' . $server->uuid_short . '@' . $fqdn . ':' . $server->node->daemon_sftp; + }), + ]) + ->formatStateUsing(function (Server $server) { + $fqdn = $server->node->daemon_sftp_alias ?? $server->node->fqdn; + + return 'sftp://' . auth()->user()->username . '.' . $server->uuid_short . '@' . $fqdn . ':' . $server->node->daemon_sftp; + }), + TextInput::make('username') + ->label('Username') + ->columnSpan(1) + ->disabled() + ->formatStateUsing(fn (Server $server) => auth()->user()->username . '.' . $server->uuid_short), + Placeholder::make('password') + ->columnSpan(1) + ->content('Your SFTP password is the same as the password you use to access this panel.'), + ]), + ]), + Section::make('Reinstall Server') + ->hidden(fn () => !auth()->user()->can(Permission::ACTION_SETTINGS_REINSTALL, $server)) + ->collapsible()->collapsed() + ->footerActions([ + Action::make('reinstall') + ->color('danger') + ->disabled(!auth()->user()->can(Permission::ACTION_SETTINGS_REINSTALL, $server)) + ->label('Reinstall') + ->requiresConfirmation() + ->modalHeading('Are you sure you want to reinstall the server?') + ->modalDescription('Some files may be deleted or modified during this process, please back up your data before continuing.') + ->modalSubmitActionLabel('Yes, Reinstall') + ->action(function (Server $server) { + abort_unless(auth()->user()->can(Permission::ACTION_SETTINGS_REINSTALL, $server), 403); + + $server->fill(['status' => ServerState::Installing])->save(); + try { + Http::daemon($server->node)->post(sprintf( + '/api/servers/%s/reinstall', + $server->uuid + )); + } catch (TransferException $exception) { + throw new DaemonConnectionException($exception); + } + + Activity::event('server:settings.reinstall') + ->log(); + + Notification::make() + ->success() + ->title('Server Reinstall Started') + ->send(); + }), + ]) + ->footerActionsAlignment(Alignment::Right) + ->schema([ + Placeholder::make('') + ->label('Reinstalling your server will stop it, and then re-run the installation script that initially set it up.'), + Placeholder::make('') + ->label('Some files may be deleted or modified during this process, please back up your data before continuing.'), + ]), + ]); + } + + public function updateName(string $name, Server $server): void + { + abort_unless(auth()->user()->can(Permission::ACTION_SETTINGS_RENAME, $server), 403); + + $original = $server->name; + + try { + $server->forceFill([ + 'name' => $name, + ])->saveOrFail(); + + if ($original !== $name) { + Activity::event('server:settings.rename') + ->property(['old' => $original, 'new' => $name]) + ->log(); + } + + Notification::make() + ->success() + ->duration(5000) // 5 seconds + ->title('Updated Server Name') + ->body(fn () => $original . ' -> ' . $name) + ->send(); + } catch (Exception $exception) { + Notification::make() + ->danger() + ->title('Failed') + ->body($exception->getMessage()) + ->send(); + } + } + + public function updateDescription(string $description, Server $server): void + { + abort_unless(auth()->user()->can(Permission::ACTION_SETTINGS_RENAME, $server), 403); + + $original = $server->description; + + try { + $server->forceFill([ + 'description' => $description, + ])->saveOrFail(); + + if ($original !== $description) { + Activity::event('server:settings.description') + ->property(['old' => $original, 'new' => $description]) + ->log(); + } + + Notification::make() + ->success() + ->duration(5000) // 5 seconds + ->title('Updated Server Description') + ->body(fn () => $original . ' -> ' . $description) + ->send(); + } catch (Exception $exception) { + Notification::make() + ->danger() + ->title('Failed') + ->body($exception->getMessage()) + ->send(); + } + } +} diff --git a/app/Filament/Server/Pages/Startup.php b/app/Filament/Server/Pages/Startup.php new file mode 100644 index 0000000000..943a9a4d9b --- /dev/null +++ b/app/Filament/Server/Pages/Startup.php @@ -0,0 +1,238 @@ +columns([ + 'default' => 1, + 'sm' => 1, + 'md' => 4, + 'lg' => 6, + ]) + ->schema([ + Textarea::make('startup') + ->label('Startup Command') + ->columnSpan([ + 'default' => 1, + 'sm' => 1, + 'md' => 2, + 'lg' => 4, + ]) + ->autosize() + ->readOnly(), + TextInput::make('custom_image') + ->label('Docker Image') + ->readOnly() + ->visible(fn (Server $server) => !in_array($server->image, $server->egg->docker_images)) + ->formatStateUsing(fn (Server $server) => $server->image) + ->columnSpan([ + 'default' => 1, + 'sm' => 1, + 'md' => 2, + 'lg' => 2, + ]), + Select::make('image') + ->label('Docker Image') + ->live() + ->visible(fn (Server $server) => in_array($server->image, $server->egg->docker_images)) + ->disabled(!auth()->user()->can(Permission::ACTION_STARTUP_DOCKER_IMAGE, $server)) + ->afterStateUpdated(function ($state, Server $server) { + $original = $server->image; + $server->forceFill(['image' => $state])->saveOrFail(); + + if ($original !== $server->image) { + Activity::event('server:startup.image') + ->property(['old' => $original, 'new' => $state]) + ->log(); + } + + Notification::make() + ->title('Docker image updated') + ->body('Restart the server to use the new image.') + ->success() + ->send(); + }) + ->options(function (Server $server) { + $images = $server->egg->docker_images; + + return array_flip($images); + }) + ->selectablePlaceholder(false) + ->columnSpan([ + 'default' => 1, + 'sm' => 1, + 'md' => 2, + 'lg' => 2, + ]), + Section::make('Server Variables') + ->schema([ + Repeater::make('server_variables') + ->label('') + ->relationship('viewableServerVariables') + ->grid() + ->disabled(!auth()->user()->can(Permission::ACTION_STARTUP_UPDATE, $server)) + ->reorderable(false)->addable(false)->deletable(false) + ->schema(function () { + $text = TextInput::make('variable_value') + ->hidden($this->shouldHideComponent(...)) + ->disabled(fn (ServerVariable $serverVariable) => !$serverVariable->variable->user_editable) + ->required(fn (ServerVariable $serverVariable) => $serverVariable->variable->getRequiredAttribute()) + ->rules([ + fn (ServerVariable $serverVariable): Closure => function (string $attribute, $value, Closure $fail) use ($serverVariable) { + $validator = Validator::make(['validatorkey' => $value], [ + 'validatorkey' => $serverVariable->variable->rules, + ]); + + if ($validator->fails()) { + $message = str($validator->errors()->first())->replace('validatorkey', $serverVariable->variable->name); + + $fail($message); + } + }, + ]); + + $select = Select::make('variable_value') + ->hidden($this->shouldHideComponent(...)) + ->disabled(fn (ServerVariable $serverVariable) => !$serverVariable->variable->user_editable) + ->options($this->getSelectOptionsFromRules(...)) + ->selectablePlaceholder(false); + + $components = [$text, $select]; + + foreach ($components as &$component) { + $component = $component + ->live(onBlur: true) + ->afterStateUpdated(function ($state, ServerVariable $serverVariable) { + $this->update($state, $serverVariable); + }) + ->hintIcon('tabler-code') + ->label(fn (ServerVariable $serverVariable) => $serverVariable->variable->name) + ->hintIconTooltip(fn (ServerVariable $serverVariable) => implode('|', $serverVariable->variable->rules)) + ->prefix(fn (ServerVariable $serverVariable) => '{{' . $serverVariable->variable->env_variable . '}}') + ->helperText(fn (ServerVariable $serverVariable) => empty($serverVariable->variable->description) ? '—' : $serverVariable->variable->description); + } + + return $components; + }) + ->columnSpan(6), + ]), + ]); + } + + protected function authorizeAccess(): void + { + abort_unless(auth()->user()->can(Permission::ACTION_STARTUP_READ, Filament::getTenant()), 403); + } + + public static function canAccess(): bool + { + return auth()->user()->can(Permission::ACTION_STARTUP_READ, Filament::getTenant()); + } + + private function shouldHideComponent(ServerVariable $serverVariable, Component $component): bool + { + $containsRuleIn = array_first($serverVariable->variable->rules, fn ($value) => str($value)->startsWith('in:'), false); + + if ($component instanceof Select) { + return !$containsRuleIn; + } + + if ($component instanceof TextInput) { + return $containsRuleIn; + } + + throw new \Exception('Component type not supported: ' . $component::class); + } + + private function getSelectOptionsFromRules(ServerVariable $serverVariable): array + { + $inRule = array_first($serverVariable->variable->rules, fn ($value) => str($value)->startsWith('in:')); + + return str($inRule) + ->after('in:') + ->explode(',') + ->each(fn ($value) => str($value)->trim()) + ->mapWithKeys(fn ($value) => [$value => $value]) + ->all(); + } + + public function update(?string $state, ServerVariable $serverVariable): null + { + $original = $serverVariable->variable_value; + + try { + + $validator = Validator::make( + ['variable_value' => $state], + ['variable_value' => $serverVariable->variable->rules] + ); + + if ($validator->fails()) { + Notification::make() + ->danger() + ->title('Validation Failed: ' . $serverVariable->variable->name) + ->body(implode(', ', $validator->errors()->all())) + ->send(); + + return null; + } + + ServerVariable::query()->updateOrCreate([ + 'server_id' => $this->getRecord()->id, + 'variable_id' => $serverVariable->variable->id, + ], [ + 'variable_value' => $state ?? '', + ]); + + if ($original !== $state) { + Activity::event('server:startup.edit') + ->property([ + 'variable' => $serverVariable->variable->env_variable, + 'old' => $original, + 'new' => $state, + ]) + ->log(); + } + Notification::make() + ->success() + ->title('Updated: ' . $serverVariable->variable->name) + ->body(fn () => $original . ' -> ' . $state) + ->send(); + } catch (\Exception $e) { + Notification::make() + ->danger() + ->title('Failed: ' . $serverVariable->variable->name) + ->body($e->getMessage()) + ->send(); + } + + return null; + } +} diff --git a/app/Filament/Server/Resources/ActivityResource.php b/app/Filament/Server/Resources/ActivityResource.php new file mode 100644 index 0000000000..c4762eeb94 --- /dev/null +++ b/app/Filament/Server/Resources/ActivityResource.php @@ -0,0 +1,79 @@ +activity() + ->getQuery() + ->whereNotIn('activity_logs.event', ActivityLog::DISABLED_EVENTS) + ->when(config('activity.hide_admin_activity'), function (Builder $builder) use ($server) { + // We could do this with a query and a lot of joins, but that gets pretty + // painful so for now we'll execute a simpler query. + $subusers = $server->subusers()->pluck('user_id')->merge([$server->owner_id]); + $rootAdmins = Role::getRootAdmin()->users()->pluck('id'); + + $builder->select('activity_logs.*') + ->leftJoin('users', function (JoinClause $join) { + $join->on('users.id', 'activity_logs.actor_id') + ->where('activity_logs.actor_type', (new User())->getMorphClass()); + }) + ->where(function (Builder $builder) use ($subusers, $rootAdmins) { + $builder->whereNull('users.id') + ->orWhereNotIn('users.id', $rootAdmins) + ->orWhereIn('users.id', $subusers); + }); + }); + } + + // TODO: find better way handle server conflict state + public static function canAccess(): bool + { + /** @var Server $server */ + $server = Filament::getTenant(); + + if ($server->isInConflictState()) { + return false; + } + + return parent::canAccess(); + } + + public static function canViewAny(): bool + { + return auth()->user()->can(Permission::ACTION_ACTIVITY_READ, Filament::getTenant()); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListActivities::route('/'), + ]; + } +} diff --git a/app/Filament/Server/Resources/ActivityResource/Pages/ListActivities.php b/app/Filament/Server/Resources/ActivityResource/Pages/ListActivities.php new file mode 100644 index 0000000000..ace768fe45 --- /dev/null +++ b/app/Filament/Server/Resources/ActivityResource/Pages/ListActivities.php @@ -0,0 +1,40 @@ +columns([ + TextColumn::make('event') + ->html() + ->formatStateUsing(fn ($state, ActivityLog $activityLog) => __('activity.'.str($state)->replace(':', '.'))) // TODO: convert properties to a format that trans likes, see ActivityLogEntry.tsx - wrapProperties + ->description(fn ($state) => $state), + TextColumn::make('user') + ->state(fn (ActivityLog $activityLog) => $activityLog->actor instanceof User ? $activityLog->actor->username : 'System') + ->tooltip(fn (ActivityLog $activityLog) => auth()->user()->can('seeIps activityLog') ? $activityLog->ip : '') + ->url(fn (ActivityLog $activityLog): string => $activityLog->actor instanceof User ? route('filament.admin.resources.users.edit', ['record' => $activityLog->actor]) : ''), + DateTimeColumn::make('timestamp') + ->since() + ->sortable(), + ]) + ->defaultSort('timestamp', 'desc'); + } + + public function getBreadcrumbs(): array + { + return []; + } +} diff --git a/app/Filament/Server/Resources/AllocationResource.php b/app/Filament/Server/Resources/AllocationResource.php new file mode 100644 index 0000000000..8ad2c509a2 --- /dev/null +++ b/app/Filament/Server/Resources/AllocationResource.php @@ -0,0 +1,64 @@ +isInConflictState()) { + return false; + } + + return parent::canAccess(); + } + + public static function canViewAny(): bool + { + return auth()->user()->can(Permission::ACTION_ALLOCATION_READ, Filament::getTenant()); + } + + public static function canCreate(): bool + { + return auth()->user()->can(Permission::ACTION_ALLOCATION_CREATE, Filament::getTenant()); + } + + public static function canEdit(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_ALLOCATION_UPDATE, Filament::getTenant()); + } + + public static function canDelete(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_ALLOCATION_DELETE, Filament::getTenant()); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListAllocations::route('/'), + ]; + } +} diff --git a/app/Filament/Server/Resources/AllocationResource/Pages/ListAllocations.php b/app/Filament/Server/Resources/AllocationResource/Pages/ListAllocations.php new file mode 100644 index 0000000000..0ca5154048 --- /dev/null +++ b/app/Filament/Server/Resources/AllocationResource/Pages/ListAllocations.php @@ -0,0 +1,104 @@ +columns([ + TextColumn::make('ip') + ->label('Address') + ->formatStateUsing(fn (Allocation $allocation) => $allocation->alias), + TextColumn::make('alias') + ->hidden(), + TextColumn::make('port'), + TextInputColumn::make('notes') + ->disabled(fn () => !auth()->user()->can(Permission::ACTION_ALLOCATION_UPDATE, $server)) + ->label('Notes'), + IconColumn::make('primary') + ->icon(fn ($state) => match ($state) { + true => 'tabler-star-filled', + default => 'tabler-star', + }) + ->color(fn ($state) => match ($state) { + true => 'warning', + default => 'gray', + }) + ->action(function (Allocation $allocation) use ($server) { + if (auth()->user()->can(PERMISSION::ACTION_ALLOCATION_UPDATE, $server)) { + return $server->update(['allocation_id' => $allocation->id]); + } + }) + ->default(fn (Allocation $allocation) => $allocation->id === $server->allocation_id) + ->label('Primary'), + ]) + ->actions([ + DetachAction::make() + ->authorize(fn () => auth()->user()->can(Permission::ACTION_ALLOCATION_DELETE, $server)) + ->label('Delete') + ->icon('tabler-trash') + ->hidden(fn (Allocation $allocation) => $allocation->id === $server->allocation_id) + ->action(function (Allocation $allocation) { + Allocation::query()->where('id', $allocation->id)->update([ + 'notes' => null, + 'server_id' => null, + ]); + + Activity::event('server:allocation.delete') + ->subject($allocation) + ->property('allocation', $allocation->toString()) + ->log(); + }), + ]); + } + + protected function getHeaderActions(): array + { + /** @var Server $server */ + $server = Filament::getTenant(); + + return [ + Actions\Action::make('addAllocation') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_ALLOCATION_CREATE, $server)) + ->label(fn () => $server->allocations()->count() >= $server->allocation_limit ? 'Allocation limit reached' : 'Add Allocation') + ->hidden(fn () => !config('panel.client_features.allocations.enabled')) + ->disabled(fn () => $server->allocations()->count() >= $server->allocation_limit) + ->color(fn () => $server->allocations()->count() >= $server->allocation_limit ? 'danger' : 'primary') + ->action(function (FindAssignableAllocationService $service) use ($server) { + $allocation = $service->handle($server); + + Activity::event('server:allocation.create') + ->subject($allocation) + ->property('allocation', $allocation->toString()) + ->log(); + }), + ]; + } + + public function getBreadcrumbs(): array + { + return []; + } +} diff --git a/app/Filament/Server/Resources/BackupResource.php b/app/Filament/Server/Resources/BackupResource.php new file mode 100644 index 0000000000..3a10c64462 --- /dev/null +++ b/app/Filament/Server/Resources/BackupResource.php @@ -0,0 +1,57 @@ +isInConflictState()) { + return false; + } + + return parent::canAccess(); + } + + public static function canViewAny(): bool + { + return auth()->user()->can(Permission::ACTION_BACKUP_READ, Filament::getTenant()); + } + + public static function canCreate(): bool + { + return auth()->user()->can(Permission::ACTION_BACKUP_CREATE, Filament::getTenant()); + } + + public static function canDelete(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_BACKUP_DELETE, Filament::getTenant()); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListBackups::route('/'), + ]; + } +} diff --git a/app/Filament/Server/Resources/BackupResource/Pages/ListBackups.php b/app/Filament/Server/Resources/BackupResource/Pages/ListBackups.php new file mode 100644 index 0000000000..8681a6d5eb --- /dev/null +++ b/app/Filament/Server/Resources/BackupResource/Pages/ListBackups.php @@ -0,0 +1,189 @@ +schema([ + TextInput::make('name') + ->label('Name') + ->columnSpanFull() + ->required(), + TextArea::make('ignored') + ->columnSpanFull() + ->label('Ignored Files & Directories'), + Toggle::make('is_locked') + ->label('Lock?') + ->helperText('Prevents this backup from being deleted until explicitly unlocked.'), + ]); + } + + public function table(Table $table): Table + { + /** @var Server $server */ + $server = Filament::getTenant(); + + return $table + ->columns([ + TextColumn::make('name') + ->searchable(), + BytesColumn::make('bytes') + ->label('Size'), + DateTimeColumn::make('created_at') + ->label('Created') + ->since() + ->sortable(), + IconColumn::make('is_successful') + ->label('Successful') + ->boolean(), + IconColumn::make('is_locked') + ->label('Lock Status') + ->icon(fn (Backup $backup) => !$backup->is_locked ? 'tabler-lock-open' : 'tabler-lock'), + ]) + ->actions([ + ActionGroup::make([ + Action::make('lock') + ->icon(fn (Backup $backup) => !$backup->is_locked ? 'tabler-lock' : 'tabler-lock-open') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_BACKUP_DELETE, $server)) + ->label(fn (Backup $backup) => !$backup->is_locked ? 'Lock' : 'Unlock') + ->action(fn (BackupController $backupController, Backup $backup, Request $request) => $backupController->toggleLock($request, $server, $backup)), + Action::make('download') + ->color('primary') + ->icon('tabler-download') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_BACKUP_DOWNLOAD, $server)) + ->url(fn (DownloadLinkService $downloadLinkService, Backup $backup, Request $request) => $downloadLinkService->handle($backup, $request->user()), true), + Action::make('restore') + ->color('success') + ->icon('tabler-folder-up') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_BACKUP_RESTORE, $server)) + ->form([ + Placeholder::make('') + ->helperText('Your server will be stopped. You will not be able to control the power state, access the file manager, or create additional backups until this process is completed.'), + Checkbox::make('truncate') + ->label('Delete all files before restoring backup?'), + ]) + ->action(function (Backup $backup, $data, DaemonBackupRepository $daemonRepository, DownloadLinkService $downloadLinkService) use ($server) { + if (!is_null($server->status)) { + return Notification::make() + ->danger() + ->title('Backup Restore Failed') + ->body('This server is not currently in a state that allows for a backup to be restored.') + ->send(); + } + + if (!$backup->is_successful && is_null($backup->completed_at)) { //TODO Change to Notifications + return Notification::make() + ->danger() + ->title('Backup Restore Failed') + ->body('This backup cannot be restored at this time: not completed or failed.') + ->send(); + } + + $log = Activity::event('server:backup.restore') + ->subject($backup) + ->property(['name' => $backup->name, 'truncate' => $data['truncate']]); + + $log->transaction(function () use ($downloadLinkService, $daemonRepository, $backup, $server, $data) { + // If the backup is for an S3 file we need to generate a unique Download link for + // it that will allow daemon to actually access the file. + if ($backup->disk === Backup::ADAPTER_AWS_S3) { + $url = $downloadLinkService->handle($backup, auth()->user()); + } + + // Update the status right away for the server so that we know not to allow certain + // actions against it via the Panel API. + $server->update(['status' => ServerState::RestoringBackup]); + + $daemonRepository->setServer($server)->restore($backup, $url ?? null, $data['truncate']); + }); + + return Notification::make() + ->title('Restoring Backup') + ->send(); + }), + DeleteAction::make('delete') + ->disabled(fn (Backup $backup): bool => $backup->is_locked) + ->modalDescription(fn (Backup $backup) => 'Do you wish to delete, ' . $backup->name . '?') + ->modalSubmitActionLabel('Delete Backup') + ->action(fn (BackupController $backupController, Backup $backup, Request $request) => $backupController->delete($request, $server, $backup)), + ]), + ]); + } + + protected function getHeaderActions(): array + { + /** @var Server $server */ + $server = Filament::getTenant(); + + return [ + Actions\CreateAction::make() + ->authorize(fn () => auth()->user()->can(Permission::ACTION_BACKUP_CREATE, $server)) + ->label(fn () => $server->backups()->count() >= $server->backup_limit ? 'Backup limit reached' : 'Create Backup') + ->disabled(fn () => $server->backups()->count() >= $server->backup_limit) + ->color(fn () => $server->backups()->count() >= $server->backup_limit ? 'danger' : 'primary') + ->createAnother(false) + ->action(function (InitiateBackupService $initiateBackupService, $data) use ($server) { + $action = $initiateBackupService->setIgnoredFiles(explode(PHP_EOL, $data['ignored'] ?? '')); + + if (auth()->user()->can(Permission::ACTION_BACKUP_DELETE, $server)) { + $action->setIsLocked((bool) $data['is_locked']); + } + + $backup = $action->handle($server, $data['name']); + + Activity::event('server:backup.start') + ->subject($backup) + ->property(['name' => $backup->name, 'locked' => (bool) $data['is_locked']]) + ->log(); + + return Notification::make() + ->title('Backup Created') + ->body($backup->name . ' created.') + ->success() + ->send(); + }), + ]; + } + + public function getBreadcrumbs(): array + { + return []; + } +} diff --git a/app/Filament/Server/Resources/DatabaseResource.php b/app/Filament/Server/Resources/DatabaseResource.php new file mode 100644 index 0000000000..48ba842450 --- /dev/null +++ b/app/Filament/Server/Resources/DatabaseResource.php @@ -0,0 +1,65 @@ +isInConflictState()) { + return false; + } + + return parent::canAccess(); + } + + public static function canViewAny(): bool + { + return auth()->user()->can(Permission::ACTION_DATABASE_READ, Filament::getTenant()); + } + + public static function canView(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_DATABASE_READ, Filament::getTenant()); + } + + public static function canCreate(): bool + { + return auth()->user()->can(Permission::ACTION_DATABASE_CREATE, Filament::getTenant()); + } + + public static function canEdit(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_DATABASE_UPDATE, Filament::getTenant()); + } + + public static function canDelete(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_DATABASE_DELETE, Filament::getTenant()); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListDatabases::route('/'), + ]; + } +} diff --git a/app/Filament/Server/Resources/DatabaseResource/Pages/ListDatabases.php b/app/Filament/Server/Resources/DatabaseResource/Pages/ListDatabases.php new file mode 100644 index 0000000000..dc93578da1 --- /dev/null +++ b/app/Filament/Server/Resources/DatabaseResource/Pages/ListDatabases.php @@ -0,0 +1,135 @@ +schema([ + TextInput::make('database') + ->columnSpanFull() + ->suffixAction(CopyAction::make()), + TextInput::make('username') + ->suffixAction(CopyAction::make()), + TextInput::make('password') + ->password()->revealable() + ->hidden(fn () => !auth()->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server)) + ->hintAction( + Action::make('rotate') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_DATABASE_UPDATE, $server)) + ->icon('tabler-refresh') + ->requiresConfirmation() + ->action(function (DatabasePasswordService $service, Database $database, $set, $get) { + $newPassword = $service->handle($database); + + $set('password', $newPassword); + $set('JDBC', 'jdbc:mysql://' . $get('username') . ':' . urlencode($newPassword) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database')); + }) + ) + ->suffixAction(CopyAction::make()) + ->formatStateUsing(fn (Database $database) => $database->password), + TextInput::make('remote') + ->label('Connections From'), + TextInput::make('max_connections') + ->formatStateUsing(fn (Database $database) => $database->max_connections === 0 ? $database->max_connections : 'Unlimited'), + TextInput::make('JDBC') + ->label('JDBC Connection String') + ->password()->revealable() + ->hidden(!auth()->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server)) + ->suffixAction(CopyAction::make()) + ->columnSpanFull() + ->formatStateUsing(fn (Get $get, Database $database) => 'jdbc:mysql://' . $get('username') . ':' . urlencode($database->password) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database')), + ]); + } + + public function table(Table $table): Table + { + return $table + ->columns([ + TextColumn::make('database'), + TextColumn::make('username'), + TextColumn::make('remote'), + DateTimeColumn::make('created_at') + ->sortable(), + ]) + ->actions([ + ViewAction::make() + ->modalHeading(fn (Database $database) => 'Viewing ' . $database->database), + DeleteAction::make(), + ]); + } + + protected function getHeaderActions(): array + { + /** @var Server $server */ + $server = Filament::getTenant(); + + return [ + CreateAction::make('new') + ->label(fn () => $server->databases()->count() >= $server->database_limit ? 'Database limit reached' : 'Create Database') + ->disabled(fn () => $server->databases()->count() >= $server->database_limit) + ->color(fn () => $server->databases()->count() >= $server->database_limit ? 'danger' : 'primary') + ->createAnother(false) + ->form([ + Grid::make() + ->columns(3) + ->schema([ + TextInput::make('database') + ->columnSpan(2) + ->label('Database Name') + ->prefix('s'. $server->id . '_') + ->hintIcon('tabler-question-mark') + ->hintIconTooltip('Leaving this blank will auto generate a random name'), + TextInput::make('remote') + ->columnSpan(1) + ->label('Connections From') + ->default('%'), + ]), + ]) + ->action(function ($data, DatabaseManagementService $service) use ($server) { + if (empty($data['database'])) { + $data['database'] = str_random(12); + } + + $data['database_host_id'] = DatabaseHost::where('node_id', $server->node_id)->first()->id; + $data['database'] = 's'. $server->id . '_' . $data['database']; + + $service->create($server, $data); + }), + ]; + } + + public function getBreadcrumbs(): array + { + return []; + } +} diff --git a/app/Filament/Server/Resources/FileResource.php b/app/Filament/Server/Resources/FileResource.php new file mode 100644 index 0000000000..fd956e9c28 --- /dev/null +++ b/app/Filament/Server/Resources/FileResource.php @@ -0,0 +1,62 @@ +isInConflictState()) { + return false; + } + + return parent::canAccess(); + } + + public static function canViewAny(): bool + { + return auth()->user()->can(Permission::ACTION_FILE_READ, Filament::getTenant()); + } + + public static function canCreate(): bool + { + return auth()->user()->can(Permission::ACTION_FILE_CREATE, Filament::getTenant()); + } + + public static function canEdit(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_FILE_UPDATE, Filament::getTenant()); + } + + public static function canDelete(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_FILE_DELETE, Filament::getTenant()); + } + + public static function getPages(): array + { + return [ + 'edit' => Pages\EditFiles::route('/edit/{path}'), + 'search' => Pages\SearchFiles::route('/search/{searchTerm}'), // TODO: find better way? + 'index' => Pages\ListFiles::route('/{path?}'), + ]; + } +} diff --git a/app/Filament/Server/Resources/FileResource/Pages/EditFiles.php b/app/Filament/Server/Resources/FileResource/Pages/EditFiles.php new file mode 100644 index 0000000000..2d7b9a8629 --- /dev/null +++ b/app/Filament/Server/Resources/FileResource/Pages/EditFiles.php @@ -0,0 +1,178 @@ +path))->orderByDesc('is_directory')->orderBy('name'); + + return $form + ->schema([ + Select::make('lang') + ->live() + ->label('') + ->placeholder('File Language') + ->options(EditorLanguages::class) + ->hidden() //TODO Fix Dis + ->default(function () { + $split = explode('.', $this->path); + + return end($split); + }), + Section::make('Editing: ' . $this->path) + ->footerActions([ + Action::make('save') + ->label('Save Changes') + ->authorize(auth()->user()->can(Permission::ACTION_FILE_UPDATE, $server)) + ->icon('tabler-device-floppy') + ->keyBindings('mod+s') + ->action(function () use ($server) { + $data = $this->form->getState(); + + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->putContent($this->path, $data['editor'] ?? ''); + + Activity::event('server:file.write') + ->property('file', $this->path) + ->log(); + + Notification::make() + ->success() + ->duration(5000) // 5 seconds + ->title('Saved File') + ->body(fn () => $this->path) + ->send(); + }), + Action::make('cancel') + ->label('Cancel') + ->color('danger') + ->icon('tabler-x') + ->url(fn () => ListFiles::getUrl(['path' => dirname($this->path)])), + ]) + ->footerActionsAlignment(Alignment::End) + ->schema([ + MonacoEditor::make('editor') + ->label('') + ->formatStateUsing(function () use ($server) { + // @phpstan-ignore-next-line + return app(DaemonFileRepository::class) + ->setServer($server) + ->getContent($this->path, config('panel.files.max_edit_size')); + }) + ->language(fn (Get $get) => $get('lang') ?? 'plaintext') + ->view('filament.plugins.monaco-editor'), + ]), + ]); + } + + public function mount(string $path): void + { + $this->authorizeAccess(); + + $this->path = $path; + + $this->form->fill(); + } + + protected function authorizeAccess(): void + { + abort_unless(auth()->user()->can(Permission::ACTION_FILE_READ_CONTENT, Filament::getTenant()), 403); + } + + /** + * @return array + */ + protected function getForms(): array + { + return [ + 'form' => $this->form(static::getResource()::form( + $this->makeForm() + ->statePath($this->getFormStatePath()) + ->columns($this->hasInlineLabels() ? 1 : 2) + ->inlineLabel($this->hasInlineLabels()), + )), + ]; + } + + public function getFormStatePath(): ?string + { + return 'data'; + } + + public function getBreadcrumbs(): array + { + $resource = static::getResource(); + + $breadcrumbs = [ + $resource::getUrl() => $resource::getBreadcrumb(), + ]; + + $previousParts = ''; + foreach (explode('/', $this->path) as $part) { + $previousParts = $previousParts . '/' . $part; + $breadcrumbs[self::getUrl(['path' => ltrim($previousParts, '/')])] = $part; + } + + return $breadcrumbs; + } + + public static function route(string $path): PageRegistration + { + return new PageRegistration( + page: static::class, + route: fn (Panel $panel): Route => RouteFacade::get($path, static::class) + ->middleware(static::getRouteMiddleware($panel)) + ->withoutMiddleware(static::getWithoutRouteMiddleware($panel)) + ->where('path', '.*'), + ); + } +} diff --git a/app/Filament/Server/Resources/FileResource/Pages/ListFiles.php b/app/Filament/Server/Resources/FileResource/Pages/ListFiles.php new file mode 100644 index 0000000000..309e68754f --- /dev/null +++ b/app/Filament/Server/Resources/FileResource/Pages/ListFiles.php @@ -0,0 +1,588 @@ +path = $path ?? '/'; + } + + public function getBreadcrumbs(): array + { + $resource = static::getResource(); + + $breadcrumbs = [ + $resource::getUrl() => $resource::getBreadcrumb(), + ]; + + $previousParts = ''; + foreach (explode('/', $this->path) as $part) { + $previousParts = $previousParts . '/' . $part; + $breadcrumbs[self::getUrl(['path' => ltrim($previousParts, '/')])] = $part; + } + + return $breadcrumbs; + } + + public function table(Table $table): Table + { + /** @var Server $server */ + $server = Filament::getTenant(); + + return $table + ->paginated([15, 25, 50, 100]) + ->defaultPaginationPageOption(15) + ->query(fn () => File::get($server, $this->path)->orderByDesc('is_directory')->orderBy('name')) + ->columns([ + TextColumn::make('name') + ->searchable() + ->icon(fn (File $file) => $file->getIcon()), + BytesColumn::make('size'), + DateTimeColumn::make('modified_at') + ->since() + ->sortable(), + ]) + ->recordUrl(function (File $file) use ($server) { + + if ($file->is_directory) { + return self::getUrl(['path' => join_paths($this->path, $file->name)]); + } + + if (!auth()->user()->can(Permission::ACTION_FILE_READ_CONTENT, $server)) { + return null; + } + + return $file->canEdit() ? EditFiles::getUrl(['path' => join_paths($this->path, $file->name)]) : null; + }) + ->actions([ + Action::make('view') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_READ, $server)) + ->label('Open') + ->icon('tabler-eye') + ->visible(fn (File $file) => $file->is_directory) + ->url(fn (File $file) => self::getUrl(['path' => join_paths($this->path, $file->name)])), + EditAction::make('edit') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_READ_CONTENT, $server)) + ->label('Edit') + ->icon('tabler-edit') + ->visible(fn (File $file) => $file->canEdit()) + ->url(fn (File $file) => EditFiles::getUrl(['path' => join_paths($this->path, $file->name)])), + ActionGroup::make([ + Action::make('rename') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_UPDATE, $server)) + ->label('Rename') + ->icon('tabler-forms') + ->form([ + TextInput::make('name') + ->label('File name') + ->default(fn (File $file) => $file->name) + ->required(), + ]) + ->action(function ($data, File $file) use ($server) { + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->renameFiles($this->path, [['to' => $data['name'], 'from' => $file->name]]); + + Activity::event('server:file.rename') + ->property('directory', $this->path) + ->property('files', [['to' => $data['name'], 'from' => $file->name]]) + ->log(); + + Notification::make() + ->title('File Renamed') + ->body(fn () => $file->name . ' -> ' . $data['name']) + ->success() + ->send(); + }), + Action::make('copy') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server)) + ->label('Copy') + ->icon('tabler-copy') + ->visible(fn (File $file) => $file->is_file) + ->action(function (File $file) use ($server) { + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->copyFile(join_paths($this->path, $file->name)); + + Activity::event('server:file.copy') + ->property('file', join_paths($this->path, $file->name)) + ->log(); + + Notification::make() + ->title('File copied') + ->success() + ->send(); + + return redirect(ListFiles::getUrl(['path' => $this->path])); + }), + Action::make('download') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_READ_CONTENT, $server)) + ->label('Download') + ->icon('tabler-download') + ->visible(fn (File $file) => $file->is_file) + ->action(function (File $file) use ($server) { + // @phpstan-ignore-next-line + $token = app(NodeJWTService::class) + ->setExpiresAt(CarbonImmutable::now()->addMinutes(15)) + ->setUser(auth()->user()) + ->setClaims([ + 'file_path' => rawurldecode(join_paths($this->path, $file->name)), + 'server_uuid' => $server->uuid, + ]) + ->handle($server->node, auth()->user()->id . $server->uuid); + + Activity::event('server:file.download') + ->property('file', join_paths($this->path, $file->name)) + ->log(); + + return redirect()->away(sprintf('%s/download/file?token=%s', $server->node->getConnectionAddress(), $token->toString())); // TODO: download works, but breaks modals + }), + Action::make('move') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_UPDATE, $server)) + ->label('Move') + ->icon('tabler-replace') + ->form([ + TextInput::make('location') + ->label('File name') + ->hint('Enter the new name and directory of this file or folder, relative to the current directory.') + ->default(fn (File $file) => $file->name) + ->required() + ->live(), + Placeholder::make('new_location') + ->content(fn (Get $get) => resolve_path('./' . join_paths($this->path, $get('location')))), + ]) + ->action(function ($data, File $file) use ($server) { + $location = resolve_path(join_paths($this->path, $data['location'])); + + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->renameFiles($this->path, [['to' => $location, 'from' => $file->name]]); + + Activity::event('server:file.rename') + ->property('directory', $this->path) + ->property('files', [['to' => $location, 'from' => $file->name]]) + ->log(); + + Notification::make() + ->title(join_paths($this->path, $file->name) . ' was moved to ' . $location) + ->success() + ->send(); + }), + Action::make('permissions') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_UPDATE, $server)) + ->label('Permissions') + ->icon('tabler-license') + ->form([ + CheckboxList::make('owner') + ->bulkToggleable() + ->options([ + 'read' => 'Read', + 'write' => 'Write', + 'execute' => 'Execute', + ]) + ->formatStateUsing(function ($state, File $file) { + $mode = (int) substr((string) $file->mode_bits, 0, 1); + + return $this->getPermissionsFromModeBit($mode); + }), + CheckboxList::make('group') + ->bulkToggleable() + ->options([ + 'read' => 'Read', + 'write' => 'Write', + 'execute' => 'Execute', + ]) + ->formatStateUsing(function ($state, File $file) { + $mode = (int) substr((string) $file->mode_bits, 1, 1); + + return $this->getPermissionsFromModeBit($mode); + }), + CheckboxList::make('public') + ->bulkToggleable() + ->options([ + 'read' => 'Read', + 'write' => 'Write', + 'execute' => 'Execute', + ]) + ->formatStateUsing(function ($state, File $file) { + $mode = (int) substr((string) $file->mode_bits, 2, 1); + + return $this->getPermissionsFromModeBit($mode); + }), + ]) + ->action(function ($data, File $file) use ($server) { + $owner = (in_array('read', $data['owner']) ? 4 : 0) | (in_array('write', $data['owner']) ? 2 : 0) | (in_array('execute', $data['owner']) ? 1 : 0); + $group = (in_array('read', $data['group']) ? 4 : 0) | (in_array('write', $data['group']) ? 2 : 0) | (in_array('execute', $data['group']) ? 1 : 0); + $public = (in_array('read', $data['public']) ? 4 : 0) | (in_array('write', $data['public']) ? 2 : 0) | (in_array('execute', $data['public']) ? 1 : 0); + + $mode = $owner . $group . $public; + + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->chmodFiles($this->path, [['file' => $file->name, 'mode' => $mode]]); + + Notification::make() + ->title('Permissions changed to ' . $mode) + ->success() + ->send(); + }), + Action::make('archive') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_ARCHIVE, $server)) + ->label('Archive') + ->icon('tabler-archive') + ->action(function (File $file) use ($server) { + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->compressFiles($this->path, [$file->name]); + + Activity::event('server:file.compress') + ->property('directory', $this->path) + ->property('files', [$file->name]) + ->log(); + + Notification::make() + ->title('Archive created') + ->success() + ->send(); + + return redirect(ListFiles::getUrl(['path' => $this->path])); + }), + Action::make('unarchive') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_ARCHIVE, $server)) + ->label('Unarchive') + ->icon('tabler-archive') + ->visible(fn (File $file) => $file->isArchive()) + ->action(function (File $file) use ($server) { + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->decompressFile($this->path, $file->name); + + Activity::event('server:file.decompress') + ->property('directory', $this->path) + ->property('files', $file->name) + ->log(); + + Notification::make() + ->title('Unarchive completed') + ->success() + ->send(); + + return redirect(ListFiles::getUrl(['path' => $this->path])); + }), + ]), + DeleteAction::make() + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_DELETE, $server)) + ->label('') + ->icon('tabler-trash') + ->requiresConfirmation() + ->modalDescription(fn (File $file) => $file->name) + ->modalHeading('Delete file?') + ->action(function (File $file) use ($server) { + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->deleteFiles($this->path, [$file->name]); + + Activity::event('server:file.delete') + ->property('directory', $this->path) + ->property('files', $file->name) + ->log(); + }), + ]) + ->bulkActions([ + BulkActionGroup::make([ + BulkAction::make('move') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_UPDATE, $server)) + ->form([ + TextInput::make('location') + ->label('File name') + ->hint('Enter the new name and directory of this file or folder, relative to the current directory.') + ->default(fn (File $file) => $file->name) + ->required() + ->live(), + Placeholder::make('new_location') + ->content(fn (Get $get) => resolve_path('./' . join_paths($this->path, $get('location') ?? ''))), + ]) + ->action(function (Collection $files, $data) use ($server) { + $location = resolve_path(join_paths($this->path, $data['location'])); + + // @phpstan-ignore-next-line + $files = $files->map(fn ($file) => ['to' => $location, 'from' => $file->name])->toArray(); + + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->renameFiles($this->path, $files); + + Activity::event('server:file.rename') + ->property('directory', $this->path) + ->property('files', $files) + ->log(); + + Notification::make() + ->title(count($files) . ' Files were moved from to ' . $location) + ->success() + ->send(); + }), + BulkAction::make('archive') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_ARCHIVE, $server)) + ->action(function (Collection $files) use ($server) { + // @phpstan-ignore-next-line + $files = $files->map(fn ($file) => $file->name)->toArray(); + + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->compressFiles($this->path, $files); + + Activity::event('server:file.compress') + ->property('directory', $this->path) + ->property('files', $files) + ->log(); + + Notification::make() + ->title('Archive created') + ->success() + ->send(); + + return redirect(ListFiles::getUrl(['path' => $this->path])); + }), + DeleteBulkAction::make() + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_DELETE, $server)) + ->action(function (Collection $files) use ($server) { + // @phpstan-ignore-next-line + $files = $files->map(fn ($file) => $file->name)->toArray(); + + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->deleteFiles($this->path, $files); + + Activity::event('server:file.delete') + ->property('directory', $this->path) + ->property('files', $files) + ->log(); + + Notification::make() + ->title(count($files) . ' Files deleted.') + ->success() + ->send(); + }), + ]), + ]); + } + + protected function getHeaderActions(): array + { + /** @var Server $server */ + $server = Filament::getTenant(); + + return [ + HeaderAction::make('new_file') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server)) + ->label('New File') + ->color('gray') + ->keyBindings('') + ->modalSubmitActionLabel('Create') + ->action(function ($data) use ($server) { + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->putContent(join_paths($this->path, $data['name']), $data['editor'] ?? ''); + + Activity::event('server:file.write') + ->property('file', join_paths($this->path, $data['name'])) + ->log(); + }) + ->form([ + TextInput::make('name') + ->label('File Name') + ->required(), + Select::make('lang') + ->live() + ->hidden() //TODO: Make file language selection work + ->label('Language') + ->placeholder('File Language') + ->options(EditorLanguages::class), + MonacoEditor::make('editor') + ->label('') + ->view('filament.plugins.monaco-editor') + ->language(fn (Get $get) => $get('lang')), + ]), + HeaderAction::make('new_folder') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server)) + ->label('New Folder') + ->color('gray') + ->action(function ($data) use ($server) { + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->createDirectory($data['name'], $this->path); + + Activity::event('server:file.write') + ->property('file', join_paths($this->path, $data['name'])) + ->log(); + }) + ->form([ + TextInput::make('name') + ->label('Folder Name') + ->required(), + ]), + HeaderAction::make('upload') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_CREATE, $server)) + ->label('Upload') + ->action(function ($data) use ($server) { + if (count($data['files']) > 0 && !isset($data['url'])) { + /** @var UploadedFile $file */ + foreach ($data['files'] as $file) { + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->putContent(join_paths($this->path, $file->getClientOriginalName()), $file->getContent()); + + Activity::event('server:file.uploaded') + ->property('directory', $this->path) + ->property('file', $file->getFilename()) + ->log(); + } + } elseif ($data['url'] !== null) { + // @phpstan-ignore-next-line + app(DaemonFileRepository::class) + ->setServer($server) + ->pull($data['url'], $this->path); + + Activity::event('server:file.pull') + ->property('url', $data['url']) + ->property('directory', $this->path) + ->log(); + } + + return redirect(ListFiles::getUrl(['path' => $this->path])); + + }) + ->form([ + Tabs::make() + ->contained(false) + ->schema([ + Tabs\Tab::make('Upload Files') + ->live() + ->schema([ + FileUpload::make('files') + ->label('File(s)') + ->storeFiles(false) + ->previewable(false) + ->preserveFilenames() + ->multiple(), + ]), + Tabs\Tab::make('Upload From URL') + ->live() + ->disabled(fn (Get $get) => count($get('files')) > 0) + ->schema([ + TextInput::make('url') + ->label('URL') + ->url(), + ]), + ]), + ]), + HeaderAction::make('search') + ->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_READ, $server)) + ->label('Global Search') + ->modalSubmitActionLabel('Search') + ->form([ + TextInput::make('searchTerm') + ->placeholder('Enter a search term, e.g. *.txt') + ->minLength(3), + ]) + ->action(fn ($data) => redirect(SearchFiles::getUrl([ + 'searchTerm' => $data['searchTerm'], + 'path' => $this->path, + ]))), + ]; + } + + public static function route(string $path): PageRegistration + { + return new PageRegistration( + page: static::class, + route: fn (Panel $panel): Route => RouteFacade::get($path, static::class) + ->middleware(static::getRouteMiddleware($panel)) + ->withoutMiddleware(static::getWithoutRouteMiddleware($panel)) + ->where('path', '.*'), + ); + } + + private function getPermissionsFromModeBit(int $mode): array + { + if ($mode === 1) { + return ['execute']; + } elseif ($mode === 2) { + return ['write']; + } elseif ($mode === 3) { + return ['write', 'execute']; + } elseif ($mode === 4) { + return ['read']; + } elseif ($mode === 5) { + return ['read', 'execute']; + } elseif ($mode === 6) { + return ['read', 'write']; + } elseif ($mode === 7) { + return ['read', 'write', 'execute']; + } + + return []; + } +} diff --git a/app/Filament/Server/Resources/FileResource/Pages/SearchFiles.php b/app/Filament/Server/Resources/FileResource/Pages/SearchFiles.php new file mode 100644 index 0000000000..7e89a349f7 --- /dev/null +++ b/app/Filament/Server/Resources/FileResource/Pages/SearchFiles.php @@ -0,0 +1,70 @@ +searchTerm = $searchTerm; + $this->path = $path ?? '/'; + } + + public function getBreadcrumbs(): array + { + $resource = static::getResource(); + + return [ + $resource::getUrl() => $resource::getBreadcrumb(), + self::getUrl(['searchTerm' => $this->searchTerm]) => 'Search "' . $this->searchTerm . '"', + ]; + } + + public function table(Table $table): Table + { + /** @var Server $server */ + $server = Filament::getTenant(); + + return $table + ->paginated(false) + ->query(fn () => File::get($server, $this->path, $this->searchTerm)->orderByDesc('is_directory')->orderBy('name')) + ->columns([ + TextColumn::make('name') + ->searchable() + ->icon(fn (File $file) => $file->getIcon()), + BytesColumn::make('size'), + DateTimeColumn::make('modified_at') + ->since() + ->sortable(), + ]) + ->recordUrl(function (File $file) { + if ($file->is_directory) { + return ListFiles::getUrl(['path' => join_paths($this->path, $file->name)]); + } + + return $file->canEdit() ? EditFiles::getUrl(['path' => join_paths($this->path, $file->name)]) : null; + }); + } +} diff --git a/app/Filament/Server/Resources/ScheduleResource.php b/app/Filament/Server/Resources/ScheduleResource.php new file mode 100644 index 0000000000..470fc5ada8 --- /dev/null +++ b/app/Filament/Server/Resources/ScheduleResource.php @@ -0,0 +1,268 @@ +isInConflictState()) { + return false; + } + + return parent::canAccess(); + } + + public static function canViewAny(): bool + { + return auth()->user()->can(Permission::ACTION_SCHEDULE_READ, Filament::getTenant()); + } + + public static function canCreate(): bool + { + return auth()->user()->can(Permission::ACTION_SCHEDULE_CREATE, Filament::getTenant()); + } + + public static function canEdit(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_SCHEDULE_UPDATE, Filament::getTenant()); + } + + public static function canDelete(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_SCHEDULE_DELETE, Filament::getTenant()); + } + + public static function form(Form $form): Form + { + return $form + ->columns(10) + ->schema([ + TextInput::make('name') + ->columnSpan(10) + ->label('Schedule Name') + ->placeholder('A human readable identifier for this schedule.') + ->autocomplete(false) + ->required(), + Toggle::make('only_when_online') + ->label('Only when Server is Online?') + ->hintIconTooltip('Only execute this schedule when the server is in a running state.') + ->hintIcon('tabler-question-mark') + ->columnSpan(5) + ->required() + ->default(1), + Toggle::make('is_active') + ->label('Enable Schedule?') + ->hintIconTooltip('This schedule will be executed automatically if enabled.') + ->hintIcon('tabler-question-mark') + ->columnSpan(5) + ->required() + ->default(1), + TextInput::make('cron_minute') + ->columnSpan(2) + ->label('Minute') + ->default('*/5') + ->required(), + TextInput::make('cron_hour') + ->columnSpan(2) + ->label('Hour') + ->default('*') + ->required(), + TextInput::make('cron_day_of_month') + ->columnSpan(2) + ->label('Day of Month') + ->default('*') + ->required(), + TextInput::make('cron_month') + ->columnSpan(2) + ->label('Month') + ->default('*') + ->required(), + TextInput::make('cron_day_of_week') + ->columnSpan(2) + ->label('Day of Week') + ->default('*') + ->required(), + Section::make('Presets') + ->schema([ + Actions::make([ + Action::make('hourly') + ->disabled(fn (string $operation) => $operation === 'view') + ->action(function (Set $set) { + $set('cron_minute', '0'); + $set('cron_hour', '*'); + $set('cron_day_of_month', '*'); + $set('cron_month', '*'); + $set('cron_day_of_week', '*'); + }), + Action::make('daily') + ->disabled(fn (string $operation) => $operation === 'view') + ->action(function (Set $set) { + $set('cron_minute', '0'); + $set('cron_hour', '0'); + $set('cron_day_of_month', '*'); + $set('cron_month', '*'); + $set('cron_day_of_week', '*'); + }), + Action::make('weekly') + ->disabled(fn (string $operation) => $operation === 'view') + ->action(function (Set $set) { + $set('cron_minute', '0'); + $set('cron_hour', '0'); + $set('cron_day_of_month', '*'); + $set('cron_month', '*'); + $set('cron_day_of_week', '0'); + }), + Action::make('monthly') + ->disabled(fn (string $operation) => $operation === 'view') + ->action(function (Set $set) { + $set('cron_minute', '0'); + $set('cron_hour', '0'); + $set('cron_day_of_month', '1'); + $set('cron_month', '*'); + $set('cron_day_of_week', '0'); + }), + Action::make('every_x_minutes') + ->disabled(fn (string $operation) => $operation === 'view') + ->form([ + TextInput::make('x') + ->label('') + ->numeric() + ->minValue(1) + ->maxValue(60) + ->prefix('Every') + ->suffix('Minutes'), + ]) + ->action(function (Set $set, $data) { + $set('cron_minute', '*/' . $data['x']); + $set('cron_hour', '*'); + $set('cron_day_of_month', '*'); + $set('cron_month', '*'); + $set('cron_day_of_week', '*'); + }), + Action::make('every_x_hours') + ->disabled(fn (string $operation) => $operation === 'view') + ->form([ + TextInput::make('x') + ->label('') + ->numeric() + ->minValue(1) + ->maxValue(24) + ->prefix('Every') + ->suffix('Hours'), + ]) + ->action(function (Set $set, $data) { + $set('cron_minute', '0'); + $set('cron_hour', '*/' . $data['x']); + $set('cron_day_of_month', '*'); + $set('cron_month', '*'); + $set('cron_day_of_week', '*'); + }), + Action::make('every_x_days') + ->disabled(fn (string $operation) => $operation === 'view') + ->form([ + TextInput::make('x') + ->label('') + ->numeric() + ->minValue(1) + ->maxValue(24) + ->prefix('Every') + ->suffix('Days'), + ]) + ->action(function (Set $set, $data) { + $set('cron_minute', '0'); + $set('cron_hour', '0'); + $set('cron_day_of_month', '*/' . $data['x']); + $set('cron_month', '*'); + $set('cron_day_of_week', '*'); + }), + Action::make('every_x_months') + ->disabled(fn (string $operation) => $operation === 'view') + ->form([ + TextInput::make('x') + ->label('') + ->numeric() + ->minValue(1) + ->maxValue(24) + ->prefix('Every') + ->suffix('Months'), + ]) + ->action(function (Set $set, $data) { + $set('cron_minute', '0'); + $set('cron_hour', '0'); + $set('cron_day_of_month', '0'); + $set('cron_month', '*/' . $data['x']); + $set('cron_day_of_week', '*'); + }), + Action::make('every_x_day_of_week') + ->disabled(fn (string $operation) => $operation === 'view') + ->form([ + Select::make('x') + ->label('') + ->prefix('Every') + ->options([ + '0' => 'Sunday', + '1' => 'Monday', + '2' => 'Tuesday', + '3' => 'Wednesday', + '4' => 'Thursday', + '5' => 'Friday', + '6' => 'Saturday', + ]), + ]) + ->action(function (Set $set, $data) { + $set('cron_minute', '0'); + $set('cron_hour', '0'); + $set('cron_day_of_month', '*'); + $set('cron_month', '*'); + $set('cron_day_of_week', $data['x']); + }), + ]), + ]), + ]); + } + + public static function getRelations(): array + { + return [ + TasksRelationManager::class, + ]; + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListSchedules::route('/'), + 'create' => Pages\CreateSchedule::route('/create'), + 'view' => Pages\ViewSchedule::route('/{record}'), + 'edit' => Pages\EditSchedule::route('/{record}/edit'), + ]; + } +} diff --git a/app/Filament/Server/Resources/ScheduleResource/Pages/CreateSchedule.php b/app/Filament/Server/Resources/ScheduleResource/Pages/CreateSchedule.php new file mode 100644 index 0000000000..89f62a7425 --- /dev/null +++ b/app/Filament/Server/Resources/ScheduleResource/Pages/CreateSchedule.php @@ -0,0 +1,55 @@ +id; + } + + if (!isset($data['next_run_at'])) { + $data['next_run_at'] = $this->getNextRunAt($data['cron_minute'], $data['cron_hour'], $data['cron_day_of_month'], $data['cron_month'], $data['cron_day_of_week']); + } + + return $data; + } + + protected function getNextRunAt(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek): Carbon + { + try { + return Utilities::getScheduleNextRunDate( + $minute, + $hour, + $dayOfMonth, + $month, + $dayOfWeek + ); + } catch (Exception) { + throw new DisplayException('The cron data provided does not evaluate to a valid expression.'); + } + } + + public function getBreadcrumbs(): array + { + return []; + } +} diff --git a/app/Filament/Server/Resources/ScheduleResource/Pages/EditSchedule.php b/app/Filament/Server/Resources/ScheduleResource/Pages/EditSchedule.php new file mode 100644 index 0000000000..16f5e29e88 --- /dev/null +++ b/app/Filament/Server/Resources/ScheduleResource/Pages/EditSchedule.php @@ -0,0 +1,25 @@ +columns([ + TextColumn::make('name') + ->searchable(), + TextColumn::make('cron') + ->state(fn (Schedule $schedule) => $schedule->cron_minute . ' ' . $schedule->cron_hour . ' ' . $schedule->cron_day_of_month . ' ' . $schedule->cron_month . ' ' . $schedule->cron_day_of_week), + TextColumn::make('status') + ->state(fn (Schedule $schedule) => !$schedule->is_active ? 'Inactive' : ($schedule->is_processing ? 'Processing' : 'Active')), + IconColumn::make('only_when_online') + ->boolean() + ->sortable(), + DateTimeColumn::make('last_run_at') + ->label('Last run') + ->since() + ->sortable(), + DateTimeColumn::make('next_run_at') + ->label('Next run') + ->since() + ->sortable(), + ]) + ->actions([ + ViewAction::make(), + EditAction::make(), + DeleteAction::make(), + ]); + } + + protected function getHeaderActions(): array + { + return [ + Actions\CreateAction::make(), + ]; + } + + public function getBreadcrumbs(): array + { + return []; + } +} diff --git a/app/Filament/Server/Resources/ScheduleResource/Pages/ViewSchedule.php b/app/Filament/Server/Resources/ScheduleResource/Pages/ViewSchedule.php new file mode 100644 index 0000000000..7e965bb587 --- /dev/null +++ b/app/Filament/Server/Resources/ScheduleResource/Pages/ViewSchedule.php @@ -0,0 +1,24 @@ +getOwnerRecord(); + + return $table + ->reorderable('sequence_id', true) + ->columns([ + TextColumn::make('action') + ->state(fn (Task $task) => match ($task->action) { + Task::ACTION_POWER => 'Send power action', + Task::ACTION_COMMAND => 'Send command', + Task::ACTION_BACKUP => 'Create backup', + Task::ACTION_DELETE_FILES => 'Delete files', + default => $task->action + }), + TextColumn::make('time_offset') + ->hidden(fn () => config('queue.default') === 'sync') + ->suffix(' Seconds'), + IconColumn::make('continue_on_failure') + ->boolean(), + ]) + ->headerActions([ + CreateAction::make() + ->createAnother(false) + ->label(fn () => $schedule->tasks()->count() >= config('panel.client_features.schedules.per_schedule_task_limit', 10) ? 'Task Limit Reached' : 'Create Task') + ->disabled(fn () => $schedule->tasks()->count() >= config('panel.client_features.schedules.per_schedule_task_limit', 10)) + ->form([ + Select::make('action') + ->required() + ->live() + ->disableOptionWhen(fn (string $value): bool => $value === Task::ACTION_BACKUP && $schedule->server->backup_limit === 0) + ->options([ + Task::ACTION_POWER => 'Send power action', + Task::ACTION_COMMAND => 'Send command', + Task::ACTION_BACKUP => 'Create backup', + Task::ACTION_DELETE_FILES => 'Delete files', + ]), + Textarea::make('payload') + ->hidden(fn (Get $get) => $get('action') === Task::ACTION_POWER) + ->label(fn (Get $get) => match ($get('action')) { + Task::ACTION_POWER => 'Power action', + Task::ACTION_COMMAND => 'Command', + Task::ACTION_BACKUP => 'Files to ignore', + Task::ACTION_DELETE_FILES => 'Files to delete', + default => 'Payload' + }), + Select::make('payload') + ->visible(fn (Get $get) => $get('action') === Task::ACTION_POWER) + ->label('Power Action') + ->required() + ->options([ + 'start' => 'Start', + 'restart' => 'Restart', + 'stop' => 'Stop', + 'Kill' => 'Kill', + ]), + TextInput::make('time_offset') + ->hidden(fn (Get $get) => config('queue.default') === 'sync' || $get('sequence_id') === 1) + ->default(0) + ->numeric() + ->minValue(0) + ->maxValue(900) + ->suffix('Seconds'), + Toggle::make('continue_on_failure'), + ]) + ->action(function ($data) use ($schedule) { + $sequenceId = ($schedule->tasks()->orderByDesc('sequence_id')->first()->sequence_id ?? 0) + 1; + + $task = Task::query()->create([ + 'schedule_id' => $schedule->id, + 'sequence_id' => $sequenceId, + 'action' => $data['action'], + 'payload' => $data['payload'] ?? '', + 'time_offset' => $data['time_offset'] ?? 0, + 'continue_on_failure' => (bool) $data['continue_on_failure'], + ]); + + Activity::event('server:task.create') + ->subject($schedule, $task) + ->property(['name' => $schedule->name, 'action' => $task->action, 'payload' => $task->payload]) + ->log(); + }), + ]); + } +} diff --git a/app/Filament/Server/Resources/UserResource.php b/app/Filament/Server/Resources/UserResource.php new file mode 100644 index 0000000000..6cc03a2164 --- /dev/null +++ b/app/Filament/Server/Resources/UserResource.php @@ -0,0 +1,469 @@ +isInConflictState()) { + return false; + } + + return parent::canAccess(); + } + + public static function canViewAny(): bool + { + return auth()->user()->can(Permission::ACTION_USER_READ, Filament::getTenant()); + } + + public static function canCreate(): bool + { + return auth()->user()->can(Permission::ACTION_USER_CREATE, Filament::getTenant()); + } + + public static function canEdit(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_USER_UPDATE, Filament::getTenant()); + } + + public static function canDelete(Model $record): bool + { + return auth()->user()->can(Permission::ACTION_USER_DELETE, Filament::getTenant()); + } + + public static function table(Table $table): Table + { + /** @var Server $server */ + $server = Filament::getTenant(); + + return $table + ->paginated(false) + ->searchable(false) + ->columns([ + ImageColumn::make('picture') + ->visibleFrom('lg') + ->label('') + ->extraImgAttributes(['class' => 'rounded-full']) + ->defaultImageUrl(fn (User $user) => 'https://gravatar.com/avatar/' . md5(strtolower($user->email))), + TextColumn::make('username') + ->searchable(), + TextColumn::make('email') + ->searchable(), + TextColumn::make('permissions') + ->state(fn (User $user) => count(Subuser::query()->where('user_id', $user->id)->where('server_id', $server->id)->first()->permissions)), + ]) + ->actions([ + DeleteAction::make() + ->label('Remove User') + ->hidden(fn (User $user) => auth()->user()->id === $user->id) + ->action(function (User $user, SubuserDeletionService $subuserDeletionService) use ($server) { + $subuser = Subuser::query()->where('user_id', $user->id)->where('server_id', $server->id)->first(); + $subuserDeletionService->handle($subuser, $server); + + }), + EditAction::make() + ->label('Edit User') + + ->authorize(fn () => auth()->user()->can(Permission::ACTION_USER_UPDATE, $server)) + ->modalHeading(fn (User $user) => 'Editing ' . $user->email) + ->action(function (array $data, SubuserUpdateService $subuserUpdateService, User $user) use ($server) { + $subuser = Subuser::query()->where('user_id', $user->id)->where('server_id', $server->id)->first(); + + if (in_array('console', $data['control'])) { + $data['websocket'][0] = 'connect'; + } + + $permissions = collect($data)->forget('email')->map(fn ($permissions, $key) => collect($permissions)->map(fn ($permission) => "$key.$permission"))->flatten()->all(); + $subuserUpdateService->handle($subuser, $server, $permissions); + + Notification::make() + ->title('User Updated!') + ->success() + ->send(); + + return redirect(self::getUrl(tenant: $server)); + }) + ->form([ + Grid::make() + ->columnSpanFull() + ->columns([ + 'default' => 1, + 'sm' => 1, + 'md' => 5, + 'lg' => 6, + ]) + ->schema([ + TextInput::make('email') + ->inlineLabel() + ->disabled() + ->columnSpan([ + 'default' => 1, + 'sm' => 1, + 'md' => 4, + 'lg' => 5, + ]), + Actions::make([ + Action::make('assignAll') + ->label('Assign All') + ->action(function (Set $set) { + $permissions = [ + 'control' => [ + 'console', + 'start', + 'stop', + 'restart', + ], + 'user' => [ + 'read', + 'create', + 'update', + 'delete', + ], + 'file' => [ + 'read', + 'read-content', + 'create', + 'update', + 'delete', + 'archive', + 'sftp', + ], + 'backup' => [ + 'read', + 'create', + 'delete', + 'download', + 'restore', + ], + 'allocation' => [ + 'read', + 'create', + 'update', + 'delete', + ], + 'startup' => [ + 'read', + 'update', + 'docker-image', + ], + 'database' => [ + 'read', + 'create', + 'update', + 'delete', + 'view_password', + ], + 'schedule' => [ + 'read', + 'create', + 'update', + 'delete', + ], + 'settings' => [ + 'rename', + 'reinstall', + 'activity', + ], + ]; + + foreach ($permissions as $key => $value) { + $allValues = array_unique($value); + $set($key, $allValues); + } + }), + ]) + ->columnSpan([ + 'default' => 1, + 'sm' => 1, + 'md' => 1, + 'lg' => 1, + ]), + Tabs::make() + ->columnSpanFull() + ->schema([ + Tab::make('Console') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.control_desc')) + ->icon('tabler-terminal-2') + ->schema([ + CheckboxList::make('control') + ->formatStateUsing(function (User $user, Set $set) use ($server) { + $permissionsArray = Subuser::query() + ->where('user_id', $user->id) + ->where('server_id', $server->id) + ->first() + ->permissions; + + $transformedPermissions = []; + + foreach ($permissionsArray as $permission) { + [$group, $action] = explode('.', $permission, 2); + $transformedPermissions[$group][] = $action; + } + + foreach ($transformedPermissions as $key => $value) { + $set($key, $value); + } + + return $transformedPermissions['control'] ?? []; + }) + ->bulkToggleable() + ->label('') + ->options([ + 'console' => 'Console', + 'start' => 'Start', + 'stop' => 'Stop', + 'restart' => 'Restart', + ]) + ->descriptions([ + 'console' => trans('server/users.permissions.control_console'), + 'start' => trans('server/users.permissions.control_start'), + 'stop' => trans('server/users.permissions.control_stop'), + 'restart' => trans('server/users.permissions.control_restart'), + ]), + ]), + ]), + Tab::make('User') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.user_desc')) + ->icon('tabler-users') + ->schema([ + CheckboxList::make('user') + ->bulkToggleable() + ->label('') + ->options([ + 'read' => 'Read', + 'create' => 'Create', + 'update' => 'Update', + 'delete' => 'Delete', + ]) + ->descriptions([ + 'create' => trans('server/users.permissions.user_create'), + 'read' => trans('server/users.permissions.user_read'), + 'update' => trans('server/users.permissions.user_update'), + 'delete' => trans('server/users.permissions.user_delete'), + ]), + ]), + ]), + Tab::make('File') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.file_desc')) + ->icon('tabler-folders') + ->schema([ + CheckboxList::make('file') + ->bulkToggleable() + ->label('') + ->options([ + 'read' => 'Read', + 'read-content' => 'Read Content', + 'create' => 'Create', + 'update' => 'Update', + 'delete' => 'Delete', + 'archive' => 'Archive', + 'sftp' => 'SFTP', + ]) + ->descriptions([ + 'create' => trans('server/users.permissions.file_create'), + 'read' => trans('server/users.permissions.file_read'), + 'read-content' => trans('server/users.permissions.file_read_content'), + 'update' => trans('server/users.permissions.file_update'), + 'delete' => trans('server/users.permissions.file_delete'), + 'archive' => trans('server/users.permissions.file_archive'), + 'sftp' => trans('server/users.permissions.file_sftp'), + ]), + ]), + ]), + Tab::make('Backup') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.backup_desc')) + ->icon('tabler-download') + ->schema([ + CheckboxList::make('backup') + ->bulkToggleable() + ->label('') + ->options([ + 'read' => 'Read', + 'create' => 'Create', + 'delete' => 'Delete', + 'download' => 'Download', + 'restore' => 'Restore', + ]) + ->descriptions([ + 'create' => trans('server/users.permissions.backup_create'), + 'read' => trans('server/users.permissions.backup_read'), + 'delete' => trans('server/users.permissions.backup_delete'), + 'download' => trans('server/users.permissions.backup_download'), + 'restore' => trans('server/users.permissions.backup_restore'), + ]), + ]), + ]), + Tab::make('Allocation') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.allocation_desc')) + ->icon('tabler-network') + ->schema([ + CheckboxList::make('allocation') + ->bulkToggleable() + ->label('') + ->options([ + 'read' => 'Read', + 'create' => 'Create', + 'update' => 'Update', + 'delete' => 'Delete', + ]) + ->descriptions([ + 'read' => trans('server/users.permissions.allocation_read'), + 'create' => trans('server/users.permissions.allocation_create'), + 'update' => trans('server/users.permissions.allocation_update'), + 'delete' => trans('server/users.permissions.allocation_delete'), + ]), + ]), + ]), + Tab::make('Startup') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.startup_desc')) + ->icon('tabler-question-mark') + ->schema([ + CheckboxList::make('startup') + ->bulkToggleable() + ->label('') + ->options([ + 'read' => 'Read', + 'update' => 'Update', + 'docker-image' => 'Docker Image', + ]) + ->descriptions([ + 'read' => trans('server/users.permissions.startup_read'), + 'update' => trans('server/users.permissions.startup_update'), + 'docker-image' => trans('server/users.permissions.startup_docker_image'), + ]), + ]), + ]), + Tab::make('Database') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.database_desc')) + ->icon('tabler-database') + ->schema([ + CheckboxList::make('database') + ->bulkToggleable() + ->label('') + ->options([ + 'read' => 'Read', + 'create' => 'Create', + 'update' => 'Update', + 'delete' => 'Delete', + 'view_password' => 'View Password', + ]) + ->descriptions([ + 'read' => trans('server/users.permissions.database_read'), + 'create' => trans('server/users.permissions.database_create'), + 'update' => trans('server/users.permissions.database_update'), + 'delete' => trans('server/users.permissions.database_delete'), + 'view_password' => trans('server/users.permissions.database_view_password'), + ]), + ]), + ]), + Tab::make('Schedule') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.schedule_desc')) + ->icon('tabler-clock') + ->schema([ + CheckboxList::make('schedule') + ->bulkToggleable() + ->label('') + ->options([ + 'read' => 'Read', + 'create' => 'Create', + 'update' => 'Update', + 'delete' => 'Delete', + ]) + ->descriptions([ + 'read' => trans('server/users.permissions.schedule_read'), + 'create' => trans('server/users.permissions.schedule_create'), + 'update' => trans('server/users.permissions.schedule_update'), + 'delete' => trans('server/users.permissions.schedule_delete'), + ]), + ]), + ]), + Tab::make('Settings') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.settings_desc')) + ->icon('tabler-settings') + ->schema([ + CheckboxList::make('settings') + ->bulkToggleable() + ->label('') + ->options([ + 'rename' => 'Rename', + 'reinstall' => 'Reinstall', + 'activity' => 'Activity', + ]) + ->descriptions([ + 'rename' => trans('server/users.permissions.setting_rename'), + 'reinstall' => trans('server/users.permissions.setting_reinstall'), + 'activity' => trans('server/users.permissions.setting_activity'), + ]), + ]), + ]), + ]), + ]), + ]), + ]); + } + + public static function getPages(): array + { + return [ + 'index' => Pages\ListUsers::route('/'), + ]; + } +} diff --git a/app/Filament/Server/Resources/UserResource/Pages/ListUsers.php b/app/Filament/Server/Resources/UserResource/Pages/ListUsers.php new file mode 100644 index 0000000000..b19f585fd8 --- /dev/null +++ b/app/Filament/Server/Resources/UserResource/Pages/ListUsers.php @@ -0,0 +1,390 @@ +label('Invite User') + ->createAnother(false) + ->authorize(fn () => auth()->user()->can(Permission::ACTION_USER_CREATE, $server)) + ->form([ + Grid::make() + ->columnSpanFull() + ->columns([ + 'default' => 1, + 'sm' => 1, + 'md' => 5, + 'lg' => 6, + ]) + ->schema([ + TextInput::make('email') + ->email() + ->inlineLabel() + ->columnSpan([ + 'default' => 1, + 'sm' => 1, + 'md' => 4, + 'lg' => 5, + ]) + ->required() + ->unique(), + assignAll::make([ + Action::make('assignAll') + ->label('Assign All') + ->action(function (Set $set, Get $get) { + $permissions = [ + 'control' => [ + 'console', + 'start', + 'stop', + 'restart', + 'kill', + ], + 'user' => [ + 'read', + 'create', + 'update', + 'delete', + ], + 'file' => [ + 'read', + 'read-content', + 'create', + 'update', + 'delete', + 'archive', + 'sftp', + ], + 'backup' => [ + 'read', + 'create', + 'delete', + 'download', + 'restore', + ], + 'allocation' => [ + 'read', + 'create', + 'update', + 'delete', + ], + 'startup' => [ + 'read', + 'update', + 'docker-image', + ], + 'database' => [ + 'read', + 'create', + 'update', + 'delete', + 'view_password', + ], + 'schedule' => [ + 'read', + 'create', + 'update', + 'delete', + ], + 'settings' => [ + 'rename', + 'reinstall', + 'activity', + ], + ]; + + foreach ($permissions as $key => $value) { + $currentValues = $get($key) ?? []; + $allValues = array_unique(array_merge($currentValues, $value)); + $set($key, $allValues); + } + }), + ]) + ->columnSpan([ + 'default' => 1, + 'sm' => 1, + 'md' => 1, + 'lg' => 1, + ]), + Tabs::make() + ->columnSpanFull() + ->schema([ + Tabs\Tab::make('Console') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.control_desc')) + ->icon('tabler-terminal-2') + ->schema([ + CheckboxList::make('control') + ->bulkToggleable() + ->label('') + ->columns(2) + ->options([ + 'console' => 'Console', + 'start' => 'Start', + 'stop' => 'Stop', + 'restart' => 'Restart', + ]) + ->descriptions([ + 'console' => trans('server/users.permissions.control_console'), + 'start' => trans('server/users.permissions.control_start'), + 'stop' => trans('server/users.permissions.control_stop'), + 'restart' => trans('server/users.permissions.control_restart'), + ]), + ]), + ]), + Tabs\Tab::make('User') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.user_desc')) + ->icon('tabler-users') + ->schema([ + CheckboxList::make('user') + ->bulkToggleable() + ->label('') + ->columns(2) + ->options([ + 'read' => 'Read', + 'create' => 'Create', + 'update' => 'Update', + 'delete' => 'Delete', + ]) + ->descriptions([ + 'create' => trans('server/users.permissions.user_create'), + 'read' => trans('server/users.permissions.user_read'), + 'update' => trans('server/users.permissions.user_update'), + 'delete' => trans('server/users.permissions.user_delete'), + ]), + ]), + ]), + Tabs\Tab::make('File') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.file_desc')) + ->icon('tabler-folders') + ->schema([ + CheckboxList::make('file') + ->bulkToggleable() + ->label('') + ->columns(2) + ->options([ + 'read' => 'Read', + 'read-content' => 'Read Content', + 'create' => 'Create', + 'update' => 'Update', + 'delete' => 'Delete', + 'archive' => 'Archive', + 'sftp' => 'SFTP', + ]) + ->descriptions([ + 'create' => trans('server/users.permissions.file_create'), + 'read' => trans('server/users.permissions.file_read'), + 'read-content' => trans('server/users.permissions.file_read_content'), + 'update' => trans('server/users.permissions.file_update'), + 'delete' => trans('server/users.permissions.file_delete'), + 'archive' => trans('server/users.permissions.file_archive'), + 'sftp' => trans('server/users.permissions.file_sftp'), + ]), + ]), + ]), + Tabs\Tab::make('Backup') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.backup_desc')) + ->icon('tabler-download') + ->schema([ + CheckboxList::make('backup') + ->bulkToggleable() + ->label('') + ->columns(2) + ->options([ + 'read' => 'Read', + 'create' => 'Create', + 'delete' => 'Delete', + 'download' => 'Download', + 'restore' => 'Restore', + ]) + ->descriptions([ + 'create' => trans('server/users.permissions.backup_create'), + 'read' => trans('server/users.permissions.backup_read'), + 'delete' => trans('server/users.permissions.backup_delete'), + 'download' => trans('server/users.permissions.backup_download'), + 'restore' => trans('server/users.permissions.backup_restore'), + ]), + ]), + ]), + Tabs\Tab::make('Allocation') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.allocation_desc')) + ->icon('tabler-network') + ->schema([ + CheckboxList::make('allocation') + ->bulkToggleable() + ->label('') + ->columns(2) + ->options([ + 'read' => 'Read', + 'create' => 'Create', + 'update' => 'Update', + 'delete' => 'Delete', + ]) + ->descriptions([ + 'read' => trans('server/users.permissions.allocation_read'), + 'create' => trans('server/users.permissions.allocation_create'), + 'update' => trans('server/users.permissions.allocation_update'), + 'delete' => trans('server/users.permissions.allocation_delete'), + ]), + ]), + ]), + Tabs\Tab::make('Startup') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.startup_desc')) + ->icon('tabler-question-mark') + ->schema([ + CheckboxList::make('startup') + ->bulkToggleable() + ->label('') + ->columns(2) + ->options([ + 'read' => 'Read', + 'update' => 'Update', + 'docker-image' => 'Docker Image', + ]) + ->descriptions([ + 'read' => trans('server/users.permissions.startup_read'), + 'update' => trans('server/users.permissions.startup_update'), + 'docker-image' => trans('server/users.permissions.startup_docker_image'), + ]), + ]), + ]), + Tabs\Tab::make('Database') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.database_desc')) + ->icon('tabler-database') + ->schema([ + CheckboxList::make('database') + ->bulkToggleable() + ->label('') + ->columns(2) + ->options([ + 'read' => 'Read', + 'create' => 'Create', + 'update' => 'Update', + 'delete' => 'Delete', + 'view_password' => 'View Password', + ]) + ->descriptions([ + 'read' => trans('server/users.permissions.database_read'), + 'create' => trans('server/users.permissions.database_create'), + 'update' => trans('server/users.permissions.database_update'), + 'delete' => trans('server/users.permissions.database_delete'), + 'view_password' => trans('server/users.permissions.database_view_password'), + ]), + ]), + ]), + Tabs\Tab::make('Schedule') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.schedule_desc')) + ->icon('tabler-clock') + ->schema([ + CheckboxList::make('schedule') + ->bulkToggleable() + ->label('') + ->columns(2) + ->options([ + 'read' => 'Read', + 'create' => 'Create', + 'update' => 'Update', + 'delete' => 'Delete', + ]) + ->descriptions([ + 'read' => trans('server/users.permissions.schedule_read'), + 'create' => trans('server/users.permissions.schedule_create'), + 'update' => trans('server/users.permissions.schedule_update'), + 'delete' => trans('server/users.permissions.schedule_delete'), + ]), + ]), + ]), + Tabs\Tab::make('Settings') + ->schema([ + Section::make() + ->description(trans('server/users.permissions.settings_desc')) + ->icon('tabler-settings') + ->schema([ + CheckboxList::make('settings') + ->bulkToggleable() + ->label('') + ->columns(2) + ->options([ + 'rename' => 'Rename', + 'reinstall' => 'Reinstall', + 'activity' => 'Activity', + ]) + ->descriptions([ + 'rename' => trans('server/users.permissions.setting_rename'), + 'reinstall' => trans('server/users.permissions.setting_reinstall'), + 'activity' => trans('server/users.permissions.setting_activity'), + ]), + ]), + ]), + ]), + + ]), + ]) + ->modalHeading('Invite User') + ->modalSubmitActionLabel('Invite') + ->action(function (array $data, SubuserCreationService $service) use ($server) { + $email = $data['email']; + + if (in_array('console', $data['control'])) { + $data['websocket'][0] = 'connect'; + } + $permissions = collect($data)->forget('email')->map(fn ($permissions, $key) => collect($permissions)->map(fn ($permission) => "$key.$permission"))->flatten()->all(); + $service->handle($server, $email, $permissions); + + Notification::make() + ->title('User Invited!') + ->success() + ->send(); + + return redirect(self::getUrl(tenant: $server)); + }), + ]; + } + + public function getBreadcrumbs(): array + { + return []; + } +} diff --git a/app/Filament/Server/Widgets/ServerConsole.php b/app/Filament/Server/Widgets/ServerConsole.php new file mode 100644 index 0000000000..3f4eb7d188 --- /dev/null +++ b/app/Filament/Server/Widgets/ServerConsole.php @@ -0,0 +1,71 @@ +historyIndex = min($this->historyIndex + 1, count($this->history) - 1); + + $this->input = $this->history[$this->historyIndex] ?? ''; + } + + public function down(): void + { + $this->historyIndex = max($this->historyIndex - 1, -1); + + $this->input = $this->history[$this->historyIndex] ?? ''; + } + + public function enter(): void + { + if (!empty($this->input)) { + $this->dispatch('sendServerCommand', command: $this->input); + + $this->history = Arr::prepend($this->history, $this->input); + $this->historyIndex = -1; + + $this->input = ''; + } + } + + #[On('storeStats')] + public function storeStats(string $data): void + { + $data = json_decode($data); + + $timestamp = now()->getTimestamp(); + + foreach ($data as $key => $value) { + $cacheKey = "servers.{$this->server->id}.$key"; + $data = cache()->get($cacheKey, []); + + $data[$timestamp] = $value; + + cache()->put($cacheKey, $data, now()->addMinute()); + } + } +} diff --git a/app/Filament/Server/Widgets/ServerCpuChart.php b/app/Filament/Server/Widgets/ServerCpuChart.php new file mode 100644 index 0000000000..0301310225 --- /dev/null +++ b/app/Filament/Server/Widgets/ServerCpuChart.php @@ -0,0 +1,77 @@ +get("servers.{$this->server->id}.cpu_absolute")) + ->slice(-10) + ->map(fn ($value, $key) => [ + 'cpu' => Number::format($value, maxPrecision: 2, locale: auth()->user()->language), + 'timestamp' => Carbon::createFromTimestamp($key, (auth()->user()->timezone ?? 'UTC'))->format('H:i:s'), + ]) + ->all(); + + return [ + 'datasets' => [ + [ + 'data' => array_column($cpu, 'cpu'), + 'backgroundColor' => [ + 'rgba(96, 165, 250, 0.3)', + ], + 'tension' => '0.3', + 'fill' => true, + ], + ], + 'labels' => array_column($cpu, 'timestamp'), + ]; + } + + protected function getType(): string + { + return 'line'; + } + + protected function getOptions(): RawJs + { + return RawJs::make(<<<'JS' + { + scales: { + y: { + min: 0, + }, + x: { + display: false, + } + }, + plugins: { + legend: { + display: false, + } + } + } + JS); + } + + public function getHeading(): string + { + $cpu = Number::format(collect(cache()->get("servers.{$this->server->id}.cpu_absolute"))->last() ?? 0, maxPrecision: 2, locale: auth()->user()->language) . '%'; + $max = Number::format($this->server->cpu, locale: auth()->user()->language) . '%'; + + return 'CPU - ' . $cpu . ($this->server->cpu > 0 ? ' Of ' . $max : ''); + } +} diff --git a/app/Filament/Server/Widgets/ServerMemoryChart.php b/app/Filament/Server/Widgets/ServerMemoryChart.php new file mode 100644 index 0000000000..4cd9525c6e --- /dev/null +++ b/app/Filament/Server/Widgets/ServerMemoryChart.php @@ -0,0 +1,90 @@ +get("servers.{$this->server->id}.memory_bytes"))->slice(-10) + ->map(fn ($value, $key) => [ + 'memory' => Number::format(config('panel.use_binary_prefix') ? $value / 1024 / 1024 / 1024 : $value / 1000 / 1000 / 1000, maxPrecision: 2, locale: auth()->user()->language), + 'timestamp' => Carbon::createFromTimestamp($key, (auth()->user()->timezone ?? 'UTC'))->format('H:i:s'), + ]) + ->all(); + + return [ + 'datasets' => [ + [ + 'data' => array_column($memUsed, 'memory'), + 'backgroundColor' => [ + 'rgba(96, 165, 250, 0.3)', + ], + 'tension' => '0.3', + 'fill' => true, + ], + ], + 'labels' => array_column($memUsed, 'timestamp'), + ]; + } + + protected function getType(): string + { + return 'line'; + } + + protected function getOptions(): RawJs + { + return RawJs::make(<<<'JS' + { + scales: { + y: { + min: 0, + }, + x: { + display: false, + } + }, + plugins: { + legend: { + display: false, + } + } + } + JS); + } + + public function getHeading(): string + { + $latestMemoryUsed = collect(cache()->get("servers.{$this->server->id}.memory_bytes"))->last() ?? 0; + $totalMemory = collect(cache()->get("servers.{$this->server->id}.memory_limit_bytes"))->last() ?? 0; + + $used = config('panel.use_binary_prefix') + ? Number::format($latestMemoryUsed / 1024 / 1024 / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB' + : Number::format($latestMemoryUsed / 1000 / 1000 / 1000, maxPrecision: 2, locale: auth()->user()->language) . ' GB'; + + if ($totalMemory === 0) { + $total = config('panel.use_binary_prefix') + ? Number::format($this->server->memory / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB' + : Number::format($this->server->memory / 1000, maxPrecision: 2, locale: auth()->user()->language) . ' GB'; + } else { + $total = config('panel.use_binary_prefix') + ? Number::format($totalMemory / 1024 / 1024 / 1024, maxPrecision: 2, locale: auth()->user()->language) .' GiB' + : Number::format($totalMemory / 1000 / 1000 / 1000, maxPrecision: 2, locale: auth()->user()->language) . ' GB'; + } + + return 'Memory - ' . $used . ($this->server->memory > 0 ? ' Of ' . $total : ''); + } +} diff --git a/app/Filament/Server/Widgets/ServerNetworkChart.php b/app/Filament/Server/Widgets/ServerNetworkChart.php new file mode 100644 index 0000000000..8caf58e644 --- /dev/null +++ b/app/Filament/Server/Widgets/ServerNetworkChart.php @@ -0,0 +1,93 @@ +get("servers.{$this->server->id}.network"); + + $rx = collect($data) + ->slice(-10) + ->map(fn ($value, $key) => [ + 'rx' => $value->rx_bytes, + 'timestamp' => Carbon::createFromTimestamp($key, (auth()->user()->timezone ?? 'UTC'))->format('H:i:s'), + ]) + ->all(); + + $tx = collect($data) + ->slice(-10) + ->map(fn ($value, $key) => [ + 'tx' => $value->rx_bytes, + 'timestamp' => Carbon::createFromTimestamp($key, (auth()->user()->timezone ?? 'UTC'))->format('H:i:s'), + ]) + ->all(); + + return [ + 'datasets' => [ + [ + 'label' => 'Inbound', + 'data' => array_column($rx, 'rx'), + 'backgroundColor' => [ + 'rgba(96, 165, 250, 0.3)', + ], + 'tension' => '0.3', + 'fill' => true, + ], + [ + 'label' => 'Outbound', + 'data' => array_column($tx, 'tx'), + 'backgroundColor' => [ + 'rgba(165, 96, 250, 0.3)', + ], + 'tension' => '0.3', + 'fill' => true, + ], + ], + 'labels' => array_column($rx, 'timestamp'), + ]; + } + + protected function getType(): string + { + return 'line'; + } + + protected function getOptions(): RawJs + { + return RawJs::make(<<<'JS' + { + scales: { + x: { + grid: { + display: false, + }, + ticks: { + display: true, + }, + display: false, //debug + }, + y: { + ticks: { + display: true, + }, + }, + } + } + JS); + } +} diff --git a/app/Filament/Server/Widgets/ServerOverview.php b/app/Filament/Server/Widgets/ServerOverview.php new file mode 100644 index 0000000000..e11b7a4be9 --- /dev/null +++ b/app/Filament/Server/Widgets/ServerOverview.php @@ -0,0 +1,37 @@ +server->name) + ->description($this->server->description), + Stat::make('Status', Str::title($this->server->condition)), + Stat::make('Uptime', $this->uptime()), + ]; + } + + private function uptime(): string + { + $uptime = collect(cache()->get("servers.{$this->server->id}.uptime"))->last() ?? 0; + + if ($uptime === 0) { + return 'Offline'; + } + + return now()->subMillis($uptime)->diffForHumans(syntax: CarbonInterface::DIFF_ABSOLUTE, short: true, parts: 2); + } +} diff --git a/app/Http/Controllers/Api/Client/Servers/SubuserController.php b/app/Http/Controllers/Api/Client/Servers/SubuserController.php index 14cd56264a..aa3f4dea5e 100644 --- a/app/Http/Controllers/Api/Client/Servers/SubuserController.php +++ b/app/Http/Controllers/Api/Client/Servers/SubuserController.php @@ -3,17 +3,16 @@ namespace App\Http\Controllers\Api\Client\Servers; use App\Models\User; -use App\Notifications\RemovedFromServer; +use App\Services\Subusers\SubuserDeletionService; +use App\Services\Subusers\SubuserUpdateService; use Illuminate\Http\Request; use App\Models\Server; use Illuminate\Http\JsonResponse; use App\Facades\Activity; use App\Models\Permission; use App\Services\Subusers\SubuserCreationService; -use App\Repositories\Daemon\DaemonServerRepository; use App\Transformers\Api\Client\SubuserTransformer; use App\Http\Controllers\Api\Client\ClientApiController; -use App\Exceptions\Http\Connection\DaemonConnectionException; use App\Http\Requests\Api\Client\Servers\Subusers\GetSubuserRequest; use App\Http\Requests\Api\Client\Servers\Subusers\StoreSubuserRequest; use App\Http\Requests\Api\Client\Servers\Subusers\DeleteSubuserRequest; @@ -26,7 +25,8 @@ class SubuserController extends ClientApiController */ public function __construct( private SubuserCreationService $creationService, - private DaemonServerRepository $serverRepository + private SubuserUpdateService $updateService, + private SubuserDeletionService $deletionService ) { parent::__construct(); } @@ -89,40 +89,7 @@ public function update(UpdateSubuserRequest $request, Server $server, User $user /** @var \App\Models\Subuser $subuser */ $subuser = $request->attributes->get('subuser'); - $permissions = $this->getDefaultPermissions($request); - $current = $subuser->permissions; - - sort($permissions); - sort($current); - - $log = Activity::event('server:subuser.update') - ->subject($subuser->user) - ->property([ - 'email' => $subuser->user->email, - 'old' => $current, - 'new' => $permissions, - 'revoked' => true, - ]); - - // Only update the database and hit up the daemon instance to invalidate JTI's if the permissions - // have actually changed for the user. - if ($permissions !== $current) { - $log->transaction(function ($instance) use ($request, $subuser, $server) { - $subuser->update(['permissions' => $this->getDefaultPermissions($request)]); - - try { - $this->serverRepository->setServer($server)->revokeUserJTI($subuser->user_id); - } catch (DaemonConnectionException $exception) { - // Don't block this request if we can't connect to the daemon instance. Chances are it is - // offline and the token will be invalid once daemon boots back. - logger()->warning($exception, ['user_id' => $subuser->user_id, 'server_id' => $server->id]); - - $instance->property('revoked', false); - } - }); - } - - $log->reset(); + $this->updateService->handle($subuser, $server, $this->getDefaultPermissions($request)); return $this->fractal->item($subuser->refresh()) ->transformWith($this->getTransformer(SubuserTransformer::class)) @@ -137,28 +104,7 @@ public function delete(DeleteSubuserRequest $request, Server $server, User $user /** @var \App\Models\Subuser $subuser */ $subuser = $request->attributes->get('subuser'); - $log = Activity::event('server:subuser.delete') - ->subject($subuser->user) - ->property('email', $subuser->user->email) - ->property('revoked', true); - - $log->transaction(function ($instance) use ($server, $subuser) { - $subuser->delete(); - - $subuser->user->notify(new RemovedFromServer([ - 'user' => $subuser->user->name_first, - 'name' => $subuser->server->name, - ])); - - try { - $this->serverRepository->setServer($server)->revokeUserJTI($subuser->user_id); - } catch (DaemonConnectionException $exception) { - // Don't block this request if we can't connect to the daemon instance. - logger()->warning($exception, ['user_id' => $subuser->user_id, 'server_id' => $server->id]); - - $instance->property('revoked', false); - } - }); + $this->deletionService->handle($subuser, $server); return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT); } diff --git a/app/Http/Middleware/Activity/ServerSubject.php b/app/Http/Middleware/Activity/ServerSubject.php index 3f0c45f132..fa6ba4652e 100644 --- a/app/Http/Middleware/Activity/ServerSubject.php +++ b/app/Http/Middleware/Activity/ServerSubject.php @@ -20,6 +20,11 @@ class ServerSubject public function handle(Request $request, \Closure $next): Response { $server = $request->route()->parameter('server'); + + if ($request->route()->hasParameter('tenant')) { + $server = Server::find($request->route()->parameter('tenant')); + } + if ($server instanceof Server) { LogTarget::setActor($request->user()); LogTarget::setSubject($server); diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index 699b051839..4ec50e72d0 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -105,7 +105,7 @@ public function getHasAliasAttribute(?string $value): bool protected function address(): Attribute { return Attribute::make( - get: fn () => "$this->ip:$this->port", + get: fn () => "$this->alias:$this->port", ); } diff --git a/app/Models/File.php b/app/Models/File.php new file mode 100644 index 0000000000..83ca3119ba --- /dev/null +++ b/app/Models/File.php @@ -0,0 +1,177 @@ +is_file && in_array($this->mime_type, self::ARCHIVE_MIMES); + } + + public function isImage(): bool + { + return preg_match('/^image\/(?!svg\+xml)/', $this->mime_type); + } + + public function getIcon(): string + { + if ($this->is_directory) { + return 'tabler-folder'; + } + + if ($this->isArchive()) { + return 'tabler-file-zip'; + } + + if ($this->isImage()) { + return 'tabler-photo'; + } + + return $this->is_symlink ? 'tabler-file-symlink' : 'tabler-file'; + } + + public function canEdit(): bool + { + if ($this->is_directory || $this->isArchive() || $this->is_symlink || $this->isImage()) { + return false; + } + + return $this->is_file && !in_array($this->mime_type, ['application/jar', 'application/octet-stream', 'inode/directory']); + } + + public function server(): Server + { + return self::$server; + } + + protected function casts(): array + { + return [ + 'created_at' => 'datetime', + 'modified_at' => 'datetime', + ]; + } + + public function getSchema(): array + { + return [ + 'name' => 'string', + 'created_at' => 'string', + 'modified_at' => 'string', + 'mode' => 'string', + 'mode_bits' => 'integer', + 'size' => 'integer', + 'is_directory' => 'boolean', + 'is_file' => 'boolean', + 'is_symlink' => 'boolean', + 'mime_type' => 'string', + ]; + } + + public function getRows(): array + { + try { + /** @var DaemonFileRepository $fileRepository */ + $fileRepository = app(DaemonFileRepository::class)->setServer(self::$server); // @phpstan-ignore-line + + if (!is_null(self::$searchTerm)) { + $contents = cache()->remember('file_search_' . self::$path . '_' . self::$searchTerm, now()->addMinute(), fn () => $fileRepository->search(self::$searchTerm, self::$path)); + } else { + $contents = $fileRepository->getDirectory(self::$path ?? '/'); + } + + if (isset($contents['error'])) { + throw new Exception($contents['error']); + } + + return array_map(function ($file) { + return [ + 'name' => $file['name'], + 'created_at' => Carbon::parse($file['created']), + 'modified_at' => Carbon::parse($file['modified']), + 'mode' => $file['mode'], + 'mode_bits' => (int) $file['mode_bits'], + 'size' => (int) $file['size'], + 'is_directory' => $file['directory'], + 'is_file' => $file['file'], + 'is_symlink' => $file['symlink'], + 'mime_type' => $file['mime'], + ]; + }, $contents); + } catch (Exception $exception) { + report($exception); + + Notification::make() + ->title('Error loading files') + ->body($exception->getMessage()) + ->danger() + ->send(); + + return []; + } + } + + protected function sushiShouldCache(): bool + { + return false; + } +} diff --git a/app/Models/Permission.php b/app/Models/Permission.php index 29cbd826d3..8874d4c991 100644 --- a/app/Models/Permission.php +++ b/app/Models/Permission.php @@ -93,7 +93,7 @@ class Permission extends Model public const ACTION_SETTINGS_REINSTALL = 'settings.reinstall'; - public const ACTION_ACTIVITY_READ = 'activity.read'; + public const ACTION_ACTIVITY_READ = 'settings.activity'; /** * Should timestamps be used on this model. diff --git a/app/Models/Role.php b/app/Models/Role.php index d93bbce128..98a1b34d29 100644 --- a/app/Models/Role.php +++ b/app/Models/Role.php @@ -33,6 +33,9 @@ class Role extends BaseRole 'view', 'update', ], + 'activity' => [ + 'seeIps', + ], ]; public function isRootAdmin(): bool diff --git a/app/Models/Server.php b/app/Models/Server.php index 70347e0b97..fbad9c9103 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -44,7 +44,7 @@ * @property string $image * @property int|null $allocation_limit * @property int|null $database_limit - * @property int $backup_limit + * @property int|null $backup_limit * @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $installed_at @@ -287,6 +287,14 @@ public function serverVariables(): HasMany return $this->hasMany(ServerVariable::class); } + public function viewableServerVariables(): HasMany + { + return $this->hasMany(ServerVariable::class)->rightJoin('egg_variables', function (JoinClause $join) { + $join->on('egg_variables.id', 'server_variables.variable_id') + ->where('egg_variables.user_viewable', true); + }); + } + /** * Gets information for the node associated with this server. */ @@ -358,6 +366,11 @@ public function resolveChildRouteBinding($childType, $value, $field) }; } + public function isInConflictState(): bool + { + return $this->isSuspended() || $this->node->isUnderMaintenance() || !$this->isInstalled() || $this->status === ServerState::RestoringBackup || !is_null($this->transfer); + } + /** * Checks if the server is currently in a user-accessible state. If not, an * exception is raised. This should be called whenever something needs to make @@ -367,13 +380,7 @@ public function resolveChildRouteBinding($childType, $value, $field) */ public function validateCurrentState(): void { - if ( - $this->isSuspended() || - $this->node->isUnderMaintenance() || - !$this->isInstalled() || - $this->status === ServerState::RestoringBackup || - !is_null($this->transfer) - ) { + if ($this->isInConflictState()) { throw new ServerStateConflictException($this); } } diff --git a/app/Models/User.php b/app/Models/User.php index 8a35341367..482add4f6f 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -9,7 +9,10 @@ use Filament\Models\Contracts\FilamentUser; use Filament\Models\Contracts\HasAvatar; use Filament\Models\Contracts\HasName; +use Filament\Models\Contracts\HasTenants; use Filament\Panel; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Support\Collection; use Illuminate\Support\Str; use Illuminate\Validation\Rules\In; use Illuminate\Auth\Authenticatable; @@ -86,7 +89,7 @@ * @method static Builder|User whereUsername($value) * @method static Builder|User whereUuid($value) */ -class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, FilamentUser, HasAvatar, HasName +class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, FilamentUser, HasAvatar, HasName, HasTenants { use Authenticatable; use Authorizable {can as protected canned; } @@ -323,6 +326,11 @@ public function subusers(): HasMany return $this->hasMany(Subuser::class); } + public function subServers(): BelongsToMany + { + return $this->belongsToMany(Server::class, 'subusers'); + } + protected function checkPermission(Server $server, string $permission = ''): bool { if ($this->isRootAdmin() || $server->owner_id === $this->id) { @@ -377,7 +385,11 @@ public function canAccessPanel(Panel $panel): bool return true; } - return $this->roles()->count() >= 1 && $this->getAllPermissions()->count() >= 1; + if ($panel->getId() === 'admin') { + return $this->roles()->count() >= 1 && $this->getAllPermissions()->count() >= 1; + } + + return true; } public function getFilamentName(): string @@ -398,4 +410,24 @@ public function canTarget(IlluminateModel $user): bool return $user instanceof User && !$user->isRootAdmin(); } + + public function getTenants(Panel $panel): array|Collection + { + return $this->accessibleServers()->get(); + } + + public function canAccessTenant(IlluminateModel $tenant): bool + { + if ($tenant instanceof Server) { + if ($this->isRootAdmin() || $tenant->owner_id === $this->id) { + return true; + } + + $subuser = $tenant->subusers->where('user_id', $this->id)->first(); + + return $subuser !== null; + } + + return false; + } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index e9dbc067d9..aa44d986c6 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use App\Filament\Server\Pages\Console; use App\Models; use App\Models\ApiKey; use App\Models\Node; @@ -11,6 +12,8 @@ use Dedoc\Scramble\Support\Generator\SecurityScheme; use Filament\Support\Colors\Color; use Filament\Support\Facades\FilamentColor; +use Filament\Support\Facades\FilamentView; +use Filament\View\PanelsRenderHook; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Foundation\Application; use Illuminate\Support\Facades\Event; @@ -92,6 +95,12 @@ public function boot(Application $app): void 'warning' => Color::Amber, ]); + FilamentView::registerRenderHook( + PanelsRenderHook::CONTENT_START, + fn () => view('filament.server-conflict-banner'), + scopes: Console::class, + ); + Gate::before(function (User $user, $ability) { return $user->isRootAdmin() ? true : null; }); diff --git a/app/Providers/Filament/AppPanelProvider.php b/app/Providers/Filament/AppPanelProvider.php new file mode 100644 index 0000000000..1d073702bf --- /dev/null +++ b/app/Providers/Filament/AppPanelProvider.php @@ -0,0 +1,64 @@ +id('app') + ->path('app') + ->spa() + ->breadcrumbs(false) + ->brandName(config('app.name', 'Pelican')) + ->brandLogo(config('app.logo')) + ->brandLogoHeight('2rem') + ->favicon(config('app.favicon', '/pelican.ico')) + ->topNavigation(config('panel.filament.top-navigation', true)) + ->maxContentWidth(MaxWidth::ScreenTwoExtraLarge) + ->profile(EditProfile::class, false) + ->login(Login::class) + ->userMenuItems([ + MenuItem::make() + ->label('Admin') + ->url('/admin') + ->icon('tabler-arrow-forward') + ->sort(5) + ->visible(fn (): bool => auth()->user()->canAccessPanel(Filament::getPanel('admin'))), + ]) + ->discoverResources(in: app_path('Filament/App/Resources'), for: 'App\\Filament\\App\\Resources') + ->middleware([ + EncryptCookies::class, + AddQueuedCookiesToResponse::class, + StartSession::class, + AuthenticateSession::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + SubstituteBindings::class, + DisableBladeIconComponents::class, + DispatchServingFilamentEvent::class, + ]) + ->authMiddleware([ + Authenticate::class, + ]); + } +} diff --git a/app/Providers/Filament/ServerPanelProvider.php b/app/Providers/Filament/ServerPanelProvider.php new file mode 100644 index 0000000000..f1b946f18c --- /dev/null +++ b/app/Providers/Filament/ServerPanelProvider.php @@ -0,0 +1,76 @@ +id('server') + ->path('app/server') + ->homeUrl('/app') + ->spa() + ->tenant(Server::class) + ->brandName(config('app.name', 'Pelican')) + ->brandLogo(config('app.logo')) + ->brandLogoHeight('2rem') + ->favicon(config('app.favicon', '/pelican.ico')) + ->topNavigation(config('panel.filament.top-navigation', true)) + ->maxContentWidth(MaxWidth::ScreenTwoExtraLarge) + ->login(Login::class) + ->userMenuItems([ + 'profile' => MenuItem::make()->label('Profile')->url(fn () => EditProfile::getUrl(panel: 'app')), + MenuItem::make() + ->label('Server List') + ->icon('tabler-brand-docker') + ->url(fn () => ListServers::getUrl(panel: 'app')) + ->sort(6), + MenuItem::make() + ->label('Admin') + ->icon('tabler-arrow-forward') + ->url(fn () => Filament::getPanel('admin')->getUrl()) + ->sort(5) + ->visible(fn (): bool => auth()->user()->canAccessPanel(Filament::getPanel('admin'))), + ]) + ->discoverResources(in: app_path('Filament/Server/Resources'), for: 'App\\Filament\\Server\\Resources') + ->discoverPages(in: app_path('Filament/Server/Pages'), for: 'App\\Filament\\Server\\Pages') + ->discoverWidgets(in: app_path('Filament/Server/Widgets'), for: 'App\\Filament\\Server\\Widgets') + ->middleware([ + EncryptCookies::class, + AddQueuedCookiesToResponse::class, + StartSession::class, + AuthenticateSession::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + SubstituteBindings::class, + DisableBladeIconComponents::class, + DispatchServingFilamentEvent::class, + ServerSubject::class, + ]) + ->authMiddleware([ + Authenticate::class, + ]); + } +} diff --git a/app/Repositories/Daemon/DaemonFileRepository.php b/app/Repositories/Daemon/DaemonFileRepository.php index a65013fb30..0c055c9990 100644 --- a/app/Repositories/Daemon/DaemonFileRepository.php +++ b/app/Repositories/Daemon/DaemonFileRepository.php @@ -273,4 +273,30 @@ public function pull(string $url, ?string $directory, array $params = []): Respo throw new DaemonConnectionException($exception); } } + + /** + * Searches all files in the directory (and its subdirectories) for the given search term. + * + * @throws \App\Exceptions\Http\Connection\DaemonConnectionException + */ + public function search(string $searchTerm, ?string $directory): array + { + Assert::isInstanceOf($this->server, Server::class); + + try { + $response = $this->getHttpClient() + ->timeout(120) + ->get( + sprintf('/api/servers/%s/files/search', $this->server->uuid), + [ + 'pattern' => $searchTerm, + 'directory' => $directory ?? '/', + ] + ); + } catch (TransferException $exception) { + throw new DaemonConnectionException($exception); + } + + return $response->json(); + } } diff --git a/app/Services/Activity/ActivityLogService.php b/app/Services/Activity/ActivityLogService.php index fd08da9055..621800a4e0 100644 --- a/app/Services/Activity/ActivityLogService.php +++ b/app/Services/Activity/ActivityLogService.php @@ -9,6 +9,8 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Request; use App\Models\ActivityLogSubject; +use App\Models\Server; +use Filament\Facades\Filament; use Illuminate\Database\ConnectionInterface; use Illuminate\Contracts\Auth\Factory as AuthFactory; @@ -205,6 +207,10 @@ protected function getActivity(): ActivityLog if ($subject = $this->targetable->subject()) { $this->subject($subject); + } elseif ($tenant = Filament::getTenant()) { + if ($tenant instanceof Server) { + $this->subject($tenant); + } } if ($actor = $this->targetable->actor()) { diff --git a/app/Services/Subusers/SubuserCreationService.php b/app/Services/Subusers/SubuserCreationService.php index a0b3260b71..4566ac3660 100644 --- a/app/Services/Subusers/SubuserCreationService.php +++ b/app/Services/Subusers/SubuserCreationService.php @@ -44,8 +44,6 @@ public function handle(Server $server, string $email, array $permissions): Subus $user = $this->userCreationService->handle([ 'email' => $email, 'username' => $username, - 'name_first' => 'Server', - 'name_last' => 'Subuser', 'root_admin' => false, ]); } diff --git a/app/Services/Subusers/SubuserDeletionService.php b/app/Services/Subusers/SubuserDeletionService.php new file mode 100644 index 0000000000..d3d4158d2c --- /dev/null +++ b/app/Services/Subusers/SubuserDeletionService.php @@ -0,0 +1,43 @@ +subject($subuser->user) + ->property('email', $subuser->user->email) + ->property('revoked', true); + + $log->transaction(function ($instance) use ($server, $subuser) { + $subuser->delete(); + + $subuser->user->notify(new RemovedFromServer([ + 'user' => $subuser->user->name_first, + 'name' => $subuser->server->name, + ])); + + try { + $this->serverRepository->setServer($server)->revokeUserJTI($subuser->user_id); + } catch (DaemonConnectionException $exception) { + // Don't block this request if we can't connect to the daemon instance. + logger()->warning($exception, ['user_id' => $subuser->user_id, 'server_id' => $server->id]); + + $instance->property('revoked', false); + } + }); + } +} diff --git a/app/Services/Subusers/SubuserUpdateService.php b/app/Services/Subusers/SubuserUpdateService.php new file mode 100644 index 0000000000..7c62b5eece --- /dev/null +++ b/app/Services/Subusers/SubuserUpdateService.php @@ -0,0 +1,53 @@ +permissions; + + sort($permissions); + sort($current); + + $log = Activity::event('server:subuser.update') + ->subject($subuser->user) + ->property([ + 'email' => $subuser->user->email, + 'old' => $current, + 'new' => $permissions, + 'revoked' => true, + ]); + + // Only update the database and hit up the daemon instance to invalidate JTI's if the permissions + // have actually changed for the user. + if ($permissions !== $current) { + $log->transaction(function ($instance) use ($subuser, $permissions, $server) { + $subuser->update(['permissions' => $permissions]); + + try { + $this->serverRepository->setServer($server)->revokeUserJTI($subuser->user_id); + } catch (DaemonConnectionException $exception) { + // Don't block this request if we can't connect to the daemon instance. Chances are it is + // offline and the token will be invalid once daemon boots back. + logger()->warning($exception, ['user_id' => $subuser->user_id, 'server_id' => $server->id]); + + $instance->property('revoked', false); + } + }); + } + + $log->reset(); + } +} diff --git a/app/Tables/Columns/BytesColumn.php b/app/Tables/Columns/BytesColumn.php new file mode 100644 index 0000000000..84651bc6be --- /dev/null +++ b/app/Tables/Columns/BytesColumn.php @@ -0,0 +1,15 @@ +formatStateUsing(fn ($state) => $state ? convert_bytes_to_readable($state) : ''); + } +} diff --git a/app/Tables/Columns/DateTimeColumn.php b/app/Tables/Columns/DateTimeColumn.php index a237e62484..144aef35fd 100644 --- a/app/Tables/Columns/DateTimeColumn.php +++ b/app/Tables/Columns/DateTimeColumn.php @@ -10,6 +10,19 @@ protected function setUp(): void { parent::setUp(); - $this->dateTime(timezone: auth()->user()?->timezone ?? config('app.timezone', 'UTC')); + $this->dateTime(); + } + + public function since(?string $timezone = null): static + { + $this->formatStateUsing(fn ($state) => $state->diffForHumans()); + $this->tooltip(fn ($state) => $state?->timezone($this->getTimezone())); + + return $this; + } + + public function getTimezone(): string + { + return auth()->user()?->timezone ?? config('app.timezone', 'UTC'); } } diff --git a/app/Tables/Columns/ServerEntryColumn.php b/app/Tables/Columns/ServerEntryColumn.php new file mode 100644 index 0000000000..2ef33b13f4 --- /dev/null +++ b/app/Tables/Columns/ServerEntryColumn.php @@ -0,0 +1,10 @@ + [ - 'enable-preview' => true, + 'enable-preview' => false, 'show-full-screen-toggle' => true, 'show-placeholder' => true, 'placeholder-text' => 'Your code here...', 'show-loader' => true, - 'font-size' => '15px', + 'font-size' => '16px', 'line-numbers-min-chars' => true, 'automatic-layout' => true, - 'default-theme' => 'iPlastic', + 'default-theme' => 'blackboard', ], 'themes' => [ 'blackboard' => [ diff --git a/config/livewire.php b/config/livewire.php new file mode 100644 index 0000000000..39bce8afe8 --- /dev/null +++ b/config/livewire.php @@ -0,0 +1,7 @@ + [ + 'rules' => 'file', + ], +]; diff --git a/lang/en/activity.php b/lang/en/activity.php index 501a1dcde6..3158063b7d 100644 --- a/lang/en/activity.php +++ b/lang/en/activity.php @@ -22,7 +22,7 @@ ], 'user' => [ 'account' => [ - 'email-changed' => 'Changed email from :old to :new', + 'email-changed' => 'Changed email from :old to :new', 'password-changed' => 'Changed password', ], 'api-key' => [ @@ -50,28 +50,28 @@ 'kill' => 'Killed the server process', ], 'backup' => [ - 'download' => 'Downloaded the :name backup', - 'delete' => 'Deleted the :name backup', - 'restore' => 'Restored the :name backup (deleted files: :truncate)', - 'restore-complete' => 'Completed restoration of the :name backup', - 'restore-failed' => 'Failed to complete restoration of the :name backup', - 'start' => 'Started a new backup :name', - 'complete' => 'Marked the :name backup as complete', - 'fail' => 'Marked the :name backup as failed', - 'lock' => 'Locked the :name backup', - 'unlock' => 'Unlocked the :name backup', + 'download' => 'Downloaded the :name backup', + 'delete' => 'Deleted the :name backup', + 'restore' => 'Restored the :name backup (deleted files: :truncate)', + 'restore-complete' => 'Completed restoration of the :name backup', + 'restore-failed' => 'Failed to complete restoration of the :name backup', + 'start' => 'Started a new backup :name', + 'complete' => 'Marked the :name backup as complete', + 'fail' => 'Marked the :name backup as failed', + 'lock' => 'Locked the :name backup', + 'unlock' => 'Unlocked the :name backup', ], 'database' => [ - 'create' => 'Created new database :name', - 'rotate-password' => 'Password rotated for database :name', - 'delete' => 'Deleted database :name', + 'create' => 'Created new database :name', + 'rotate-password' => 'Password rotated for database :name', + 'delete' => 'Deleted database :name', ], 'file' => [ 'compress_one' => 'Compressed :directory:file', 'compress_other' => 'Compressed :count files in :directory', 'read' => 'Viewed the contents of :file', 'copy' => 'Created a copy of :file', - 'create-directory' => 'Created directory :directory:name', + 'create-directory' => 'Created directory :directory:name', 'decompress' => 'Decompressed :files in :directory', 'delete_one' => 'Deleted :directory:files.0', 'delete_other' => 'Deleted :count files in :directory', @@ -98,33 +98,33 @@ ], 'allocation' => [ 'create' => 'Added :allocation to the server', - 'notes' => 'Updated the notes for :allocation from ":old" to ":new"', + 'notes' => 'Updated the notes for :allocation from ":old" to ":new"', 'primary' => 'Set :allocation as the primary server allocation', 'delete' => 'Deleted the :allocation allocation', ], 'schedule' => [ - 'create' => 'Created the :name schedule', - 'update' => 'Updated the :name schedule', - 'execute' => 'Manually executed the :name schedule', - 'delete' => 'Deleted the :name schedule', + 'create' => 'Created the :name schedule', + 'update' => 'Updated the :name schedule', + 'execute' => 'Manually executed the :name schedule', + 'delete' => 'Deleted the :name schedule', ], 'task' => [ - 'create' => 'Created a new ":action" task for the :name schedule', - 'update' => 'Updated the ":action" task for the :name schedule', - 'delete' => 'Deleted a task for the :name schedule', + 'create' => 'Created a new ":action" task for the :name schedule', + 'update' => 'Updated the ":action" task for the :name schedule', + 'delete' => 'Deleted a task for the :name schedule', ], 'settings' => [ - 'rename' => 'Renamed the server from :old to :new', - 'description' => 'Changed the server description from :old to :new', + 'rename' => 'Renamed the server from :old to :new', + 'description' => 'Changed the server description from :old to :new', ], 'startup' => [ - 'edit' => 'Changed the :variable variable from ":old" to ":new"', - 'image' => 'Updated the Docker Image for the server from :old to :new', + 'edit' => 'Changed the :variable variable from ":old" to ":new"', + 'image' => 'Updated the Docker Image for the server from :old to :new', ], 'subuser' => [ - 'create' => 'Added :email as a subuser', - 'update' => 'Updated the subuser permissions for :email', - 'delete' => 'Removed :email as a subuser', + 'create' => 'Added :email as a subuser', + 'update' => 'Updated the subuser permissions for :email', + 'delete' => 'Removed :email as a subuser', ], ], ]; diff --git a/lang/en/server/users.php b/lang/en/server/users.php index ce77c41010..c449e710cd 100644 --- a/lang/en/server/users.php +++ b/lang/en/server/users.php @@ -2,26 +2,44 @@ return [ 'permissions' => [ - 'websocket_*' => 'Allows access to the websocket for this server.', - 'control_console' => 'Allows the user to send data to the server console.', - 'control_start' => 'Allows the user to start the server instance.', - 'control_stop' => 'Allows the user to stop the server instance.', - 'control_restart' => 'Allows the user to restart the server instance.', - 'control_kill' => 'Allows the user to kill the server instance.', - 'user_create' => 'Allows the user to create new user accounts for the server.', - 'user_read' => 'Allows the user permission to view users associated with this server.', - 'user_update' => 'Allows the user to modify other users associated with this server.', - 'user_delete' => 'Allows the user to delete other users associated with this server.', - 'file_create' => 'Allows the user permission to create new files and directories.', - 'file_read' => 'Allows the user to see files and folders associated with this server instance, as well as view their contents.', - 'file_update' => 'Allows the user to update files and folders associated with the server.', - 'file_delete' => 'Allows the user to delete files and directories.', - 'file_archive' => 'Allows the user to create file archives and decompress existing archives.', - 'file_sftp' => 'Allows the user to perform the above file actions using a SFTP client.', - 'allocation_read' => 'Allows access to the server allocation management pages.', - 'allocation_update' => 'Allows user permission to make modifications to the server\'s allocations.', - 'database_create' => 'Allows user permission to create a new database for the server.', - 'database_read' => 'Allows user permission to view the server databases.', + 'startup_desc' => 'Permissions that control a user\'s ability to view this server\'s startup parameters.', + 'settings_desc' => 'Permissions that control a user\'s access to the schedule management for this server.', + 'control_desc' => 'Permissions that control a user\'s ability to control the power state of a server, or send commands.', + 'user_desc' => 'Permissions that allow a user to manage other subusers on a server. They will never be able to edit their own account, or assign permissions they do not have themselves.', + 'file_desc' => 'Permissions that control a user\'s ability to modify the filesystem for this server.', + 'allocation_desc' => 'Permissions that control a user\'s ability to modify the port allocations for this server.', + 'database_desc' => 'Permissions that control a user\'s access to the database management for this server.', + 'backup_desc' => 'Permissions that control a user\'s ability to generate and manage server backups.', + 'schedule_desc' => 'Permissions that control a user\'s access to the schedule management for this server.', + 'startup_read' => 'Allows a user to view the startup variables for a server.', + 'startup_update' => 'Allows a user to modify the startup variables for the server.', + 'startup_docker_image' => 'Allows a user to modify the Docker image used when running the server.', + 'setting_reinstall' => 'Allows a user to trigger a reinstall of this server.', + 'setting_rename' => 'Allows a user to rename this server and change the description of it.', + 'setting_activity' => 'Allows a user to view the activity logs for the server.', + 'websocket_*' => 'Allows a user access to the websocket for this server.', + 'control_console' => 'Allows a user to send data to the server console.', + 'control_start' => 'Allows a user to start the server instance.', + 'control_stop' => 'Allows a user to stop the server instance.', + 'control_restart' => 'Allows a user to restart the server instance.', + 'control_kill' => 'Allows a user to kill the server instance.', + 'user_create' => 'Allows a user to create new user accounts for the server.', + 'user_read' => 'Allows a user permission to view users associated with this server.', + 'user_update' => 'Allows a user to modify other users associated with this server.', + 'user_delete' => 'Allows a user to delete other users associated with this server.', + 'file_create' => 'Allows a user permission to create new files and directories.', + 'file_read' => 'Allows a user to view the contents of a directory, but not view the contents of or download files.', + 'file_read_content' => 'Allows a user to view the contents of a given file. This will also allow the user to download files.', + 'file_update' => 'Allows a user to update files and folders associated with the server.', + 'file_delete' => 'Allows a user to delete files and directories.', + 'file_archive' => 'Allows a user to create file archives and decompress existing archives.', + 'file_sftp' => 'Allows a user to perform the above file actions using a SFTP client.', + 'allocation_read' => 'Allows a user to view all allocations currently assigned to this server. Users with any level of access to this server can always view the primary allocation.', + 'allocation_update' => 'Allows a user to change the primary server allocation and attach notes to each allocation.', + 'allocation_delete' => 'Allows a user to delete an allocation from the server.', + 'allocation_create' => 'Allows a user to assign additional allocations to the server.', + 'database_create' => 'Allows a user permission to create a new database for the server.', + 'database_read' => 'Allows a user permission to view the server databases.', 'database_update' => 'Allows a user permission to make modifications to a database. If the user does not have the "View Password" permission as well they will not be able to modify the password.', 'database_delete' => 'Allows a user permission to delete a database instance.', 'database_view_password' => 'Allows a user permission to view a database password in the system.', @@ -29,5 +47,10 @@ 'schedule_read' => 'Allows a user permission to view schedules for a server.', 'schedule_update' => 'Allows a user permission to make modifications to an existing server schedule.', 'schedule_delete' => 'Allows a user to delete a schedule for the server.', + 'backup_create' => 'Allows a user to create new backups for this server.', + 'backup_read' => 'Allows a user to view all backups that exist for this server.', + 'backup_delete' => 'Allows a user to remove backups from the system.', + 'backup_download' => 'Allows a user to download a backup for the server. Danger: this allows a user to access all files for the server in the backup.', + 'backup_restore' => 'Allows a user to restore a backup for the server. Danger: this allows the user to delete all of the server files in the process.', ], ]; diff --git a/public/css/filament-monaco-editor/filament-monaco-editor-styles.css b/public/css/filament-monaco-editor/filament-monaco-editor-styles.css index 7192499bd1..5a05b1fb9e 100644 --- a/public/css/filament-monaco-editor/filament-monaco-editor-styles.css +++ b/public/css/filament-monaco-editor/filament-monaco-editor-styles.css @@ -1 +1 @@ -.fme-wrapper{display:flex;width:100%;flex-direction:column}.fme-full-screen{position:fixed;top:0;left:0;z-index:9999;height:100vh;width:100vw;overflow:hidden;border-width:1px;--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.fme-control-section{display:flex;justify-content:space-between;padding:.5rem}.fme-code-preview-tab-item{position:relative;z-index:20;display:inline-flex;height:2rem;cursor:pointer;align-items:center;justify-content:center;white-space:nowrap;border-radius:.375rem;padding-left:.75rem;padding-right:.75rem;font-size:.875rem;line-height:1.25rem;font-weight:500;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.fme-code-preview-tab-marker-container{position:absolute;left:0;z-index:10;height:100%;width:50%;transition-duration:.3s;transition-timing-function:cubic-bezier(0,0,.2,1)}.fme-code-preview-tab-marker{height:100%;width:100%;border-radius:.375rem;--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity));--tw-shadow:0 1px 2px 0 #0000000d;--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)}.fme-full-screen-btn{border-radius:.25rem;padding:.25rem .5rem}.fme-full-screen-btn:focus{--tw-bg-opacity:1;background-color:rgba(var(--gray-100),var(--tw-bg-opacity));--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(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)}.fme-full-screen-btn-icon{height:1rem;width:1rem;--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.fme-code-preview-tab{display:inline-grid;height:2.5rem;width:auto;-webkit-user-select:none;-moz-user-select:none;user-select:none;grid-template-columns:repeat(2,minmax(0,1fr));justify-content:center;border-radius:.5rem;--tw-bg-opacity:1;background-color:rgba(var(--gray-100),var(--tw-bg-opacity));padding:.25rem;--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.fme-code-preview-tab,.fme-container{position:relative;align-items:center}.fme-container{min-height:250px;flex-direction:column;justify-content:flex-start;--tw-bg-opacity:1;background-color:rgb(12 16 33/var(--tw-bg-opacity));padding-top:.75rem}.fme-container,.fme-loader{display:flex;height:100%;width:100%}.fme-loader{position:absolute;inset:0;z-index:20;align-items:center;justify-content:center;transition-duration:1s;transition-timing-function:cubic-bezier(0,0,.2,1)}.fme-loader-icon{height:1rem;width:1rem;animation:spin 1s linear infinite;--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.fme-element-wrapper{position:relative;z-index:10;height:100%;width:100%;border-radius:.25rem}.fme-element{height:100%;width:100%;font-size:1.125rem;line-height:1.75rem}.fme-placeholder{position:absolute;left:0;top:0;z-index:50;margin-left:3.5rem;margin-top:.125rem;width:100%;--tw-translate-x:-0.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;line-height:1.25rem;--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.fme-preview-wrapper{height:100%;width:100%;border-radius:.25rem;border-width:1px;--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity));padding:1rem}.fme-preview{display:flex;height:100%;width:100%}.grow{flex-grow:1}.-translate-x-5,.-translate-y-12{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0,.translate-x-12{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-5,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-rotate-180,.translate-y-12{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180,.scale-100{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-95,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.truncate,.whitespace-nowrap{white-space:nowrap}.\!bg-gray-50,.\!bg-gray-700{--tw-bg-opacity:1!important}.pb-6,.py-6{padding-bottom:1.5rem}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.dark\:prose-invert:is(.dark *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.focus-visible\:ring-1:focus-visible,.focus-visible\:ring-2:focus-visible{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled::-moz-placeholder,.disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled::placeholder{-webkit-text-fill-color:rgba(var(--gray-400),1)}.group\/button:hover .group-hover\/button\:text-gray-500{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.group\/item:focus-visible .group-focus-visible\/item\:underline,.group\/link:focus-visible .group-focus-visible\/link\:underline{text-decoration-line:underline}.dark\:divide-white\/10:is(.dark *)>:not([hidden])~:not([hidden]){border-color:#ffffff1a}.dark\:divide-white\/5:is(.dark *)>:not([hidden])~:not([hidden]){border-color:#ffffff0d}.dark\:border-gray-600:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--gray-600),var(--tw-border-opacity))}.dark\:border-gray-700:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--gray-700),var(--tw-border-opacity))}.dark\:border-primary-500:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--primary-500),var(--tw-border-opacity))}.dark\:border-white\/10:is(.dark *){border-color:#ffffff1a}.dark\:border-t-white\/10:is(.dark *){border-top-color:#ffffff1a}.dark\:\!bg-gray-700:is(.dark *){--tw-bg-opacity:1!important;background-color:rgba(var(--gray-700),var(--tw-bg-opacity))!important}.dark\:bg-custom-400\/10:is(.dark *){background-color:rgba(var(--c-400),.1)}.dark\:bg-custom-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}.dark\:bg-custom-500\/20:is(.dark *){background-color:rgba(var(--c-500),.2)}.dark\:bg-gray-400\/10:is(.dark *){background-color:rgba(var(--gray-400),.1)}.dark\:bg-gray-500\/20:is(.dark *){background-color:rgba(var(--gray-500),.2)}.dark\:bg-gray-700:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-700),var(--tw-bg-opacity))}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-800),var(--tw-bg-opacity))}.dark\:bg-gray-900:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-900),var(--tw-bg-opacity))}.dark\:bg-gray-900\/30:is(.dark *){background-color:rgba(var(--gray-900),.3)}.dark\:bg-gray-950\/75:is(.dark *){background-color:rgba(var(--gray-950),.75)}.dark\:bg-primary-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity))}.dark\:bg-transparent:is(.dark *){background-color:initial}.dark\:bg-white\/5:is(.dark *){background-color:#ffffff0d}.dark\:fill-current:is(.dark *){fill:currentColor}.dark\:text-custom-300\/50:is(.dark *){color:rgba(var(--c-300),.5)}.dark\:text-custom-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--c-400),var(--tw-text-opacity))}.dark\:text-danger-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--danger-400),var(--tw-text-opacity))}.dark\:text-danger-500:is(.dark *){--tw-text-opacity:1;color:rgba(var(--danger-500),var(--tw-text-opacity))}.dark\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.dark\:text-gray-300\/50:is(.dark *){color:rgba(var(--gray-300),.5)}.dark\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.dark\:text-gray-500:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.dark\:text-gray-700:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-700),var(--tw-text-opacity))}.dark\:text-primary-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--primary-400),var(--tw-text-opacity))}.dark\:text-primary-500:is(.dark *){--tw-text-opacity:1;color:rgba(var(--primary-500),var(--tw-text-opacity))}.dark\:text-white:is(.dark *){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.dark\:text-white\/5:is(.dark *){color:#ffffff0d}.dark\:ring-custom-400\/30:is(.dark *){--tw-ring-color:rgba(var(--c-400),0.3)}.dark\:ring-custom-500:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--c-500),var(--tw-ring-opacity))}.dark\:ring-danger-500:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-500),var(--tw-ring-opacity))}.dark\:ring-gray-400\/20:is(.dark *){--tw-ring-color:rgba(var(--gray-400),0.2)}.dark\:ring-gray-50\/10:is(.dark *){--tw-ring-color:rgba(var(--gray-50),0.1)}.dark\:ring-gray-700:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-700),var(--tw-ring-opacity))}.dark\:ring-gray-900:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-900),var(--tw-ring-opacity))}.dark\:ring-white\/10:is(.dark *){--tw-ring-color:#ffffff1a}.dark\:ring-white\/20:is(.dark *){--tw-ring-color:#fff3}.dark\:placeholder\:text-gray-500:is(.dark *)::-moz-placeholder{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.dark\:placeholder\:text-gray-500:is(.dark *)::placeholder{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.dark\:before\:bg-primary-500:is(.dark *):before{content:var(--tw-content);--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity))}.dark\:checked\:bg-danger-500:checked:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--danger-500),var(--tw-bg-opacity))}.dark\:checked\:bg-primary-500:checked:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity))}.dark\:hover\:bg-custom-400:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-400),var(--tw-bg-opacity))}.dark\:hover\:bg-custom-400\/10:hover:is(.dark *){background-color:rgba(var(--c-400),.1)}.dark\:hover\:bg-white\/10:hover:is(.dark *){background-color:#ffffff1a}.dark\:hover\:bg-white\/5:hover:is(.dark *){background-color:#ffffff0d}.dark\:hover\:text-custom-300:hover:is(.dark *){--tw-text-opacity:1;color:rgba(var(--c-300),var(--tw-text-opacity))}.dark\:hover\:text-custom-300\/75:hover:is(.dark *){color:rgba(var(--c-300),.75)}.dark\:hover\:text-gray-200:hover:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.dark\:hover\:text-gray-300\/75:hover:is(.dark *){color:rgba(var(--gray-300),.75)}.dark\:hover\:text-gray-400:hover:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.dark\:focus\:ring-danger-500:focus:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-500),var(--tw-ring-opacity))}.dark\:focus\:ring-primary-500:focus:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-500),var(--tw-ring-opacity))}.dark\:checked\:focus\:ring-danger-400\/50:focus:checked:is(.dark *){--tw-ring-color:rgba(var(--danger-400),0.5)}.dark\:checked\:focus\:ring-primary-400\/50:focus:checked:is(.dark *){--tw-ring-color:rgba(var(--primary-400),0.5)}.dark\:focus-visible\:border-primary-500:focus-visible:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--primary-500),var(--tw-border-opacity))}.dark\:focus-visible\:bg-custom-400\/10:focus-visible:is(.dark *){background-color:rgba(var(--c-400),.1)}.dark\:focus-visible\:bg-white\/5:focus-visible:is(.dark *){background-color:#ffffff0d}.dark\:focus-visible\:text-custom-300\/75:focus-visible:is(.dark *){color:rgba(var(--c-300),.75)}.dark\:focus-visible\:text-gray-300\/75:focus-visible:is(.dark *){color:rgba(var(--gray-300),.75)}.dark\:focus-visible\:ring-custom-400\/50:focus-visible:is(.dark *){--tw-ring-color:rgba(var(--c-400),0.5)}.dark\:focus-visible\:ring-custom-500:focus-visible:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--c-500),var(--tw-ring-opacity))}.dark\:focus-visible\:ring-primary-500:focus-visible:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-500),var(--tw-ring-opacity))}.dark\:disabled\:bg-transparent:disabled:is(.dark *){background-color:initial}.dark\:disabled\:text-gray-400:disabled:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.dark\:disabled\:ring-white\/10:disabled:is(.dark *){--tw-ring-color:#ffffff1a}.dark\:disabled\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled:is(.dark *){-webkit-text-fill-color:rgba(var(--gray-400),1)}.dark\:disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled:is(.dark *)::-moz-placeholder,.dark\:disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled:is(.dark *)::placeholder{-webkit-text-fill-color:rgba(var(--gray-500),1)}.dark\:disabled\:checked\:bg-gray-600:checked:disabled:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-600),var(--tw-bg-opacity))}.group\/button:hover .dark\:group-hover\/button\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.group:focus-visible .dark\:group-focus-visible\:text-gray-200:is(.dark *),.group:hover .dark\:group-hover\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.dark\:\[\&\.trix-active\]\:bg-white\/5.trix-active:is(.dark *){background-color:#ffffff0d}.dark\:\[\&\.trix-active\]\:text-primary-400.trix-active:is(.dark *){--tw-text-opacity:1;color:rgba(var(--primary-400),var(--tw-text-opacity))}.dark\:\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-danger-500:focus-within:not(:has(.fi-ac-action:focus)):is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-500),var(--tw-ring-opacity))}.dark\:\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-primary-500:focus-within:not(:has(.fi-ac-action:focus)):is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-500),var(--tw-ring-opacity))}.dark\:\[\&\:not\(\:nth-child\(1_of_\.fi-btn\)\)\]\:shadow-\[-1px_0_0_0_theme\(colors\.white\/20\%\)\]:not(:nth-child(1 of .fi-btn)):is(.dark *){--tw-shadow:-1px 0 0 0 #fff3;--tw-shadow-colored:-1px 0 0 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)}.\[\&_optgroup\]\:dark\:bg-gray-900:is(.dark *) optgroup{--tw-bg-opacity:1;background-color:rgba(var(--gray-900),var(--tw-bg-opacity))}.\[\&_option\]\:dark\:bg-gray-900:is(.dark *) option{--tw-bg-opacity:1;background-color:rgba(var(--gray-900),var(--tw-bg-opacity))}:checked+*>.\[\:checked\+\*\>\&\]\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}input:checked+.\[input\:checked\+\&\]\:bg-custom-600{--tw-bg-opacity:1;background-color:rgba(var(--c-600),var(--tw-bg-opacity))}input:checked+.\[input\:checked\+\&\]\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}input:checked+.\[input\:checked\+\&\]\:ring-0{--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(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)}input:checked+.\[input\:checked\+\&\]\:hover\:bg-custom-500:hover,input:checked+.dark\:\[input\:checked\+\&\]\:bg-custom-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}input:checked+.dark\:\[input\:checked\+\&\]\:hover\:bg-custom-400:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-400),var(--tw-bg-opacity))}input:checked:focus-visible+.\[input\:checked\:focus-visible\+\&\]\:ring-custom-500\/50{--tw-ring-color:rgba(var(--c-500),0.5)}input:checked:focus-visible+.dark\:\[input\:checked\:focus-visible\+\&\]\:ring-custom-400\/50:is(.dark *){--tw-ring-color:rgba(var(--c-400),0.5)}input:focus-visible+.\[input\:focus-visible\+\&\]\:z-10{z-index:10}input:focus-visible+.\[input\:focus-visible\+\&\]\:ring-2{--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)}input:focus-visible+.\[input\:focus-visible\+\&\]\:ring-gray-950\/10{--tw-ring-color:rgba(var(--gray-950),0.1)}input:focus-visible+.dark\:\[input\:focus-visible\+\&\]\:ring-white\/20:is(.dark *){--tw-ring-color:#fff3} \ No newline at end of file +.fme-full-screen-btn-icon,.group\/button:hover .group-hover\/button\:text-gray-500{color:rgba(var(--gray-500),var(--tw-text-opacity));--tw-text-opacity:1}.fme-full-screen-btn:focus,input:checked+.\[input\:checked\+\&\]\:ring-0{--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.fme-wrapper{display:flex;width:100%;flex-direction:column}.fme-full-screen{position:fixed;top:0;left:0;z-index:9999;height:100vh;width:100vw;overflow:hidden;border-width:1px;--tw-bg-opacity:1}.fme-control-section{display:flex;justify-content:space-between;padding:.5rem}.fme-full-screen-btn{border-radius:.25rem;padding:.25rem .5rem}.fme-full-screen-btn:focus{--tw-bg-opacity:1;background-color:rgba(var(--gray-100),var(--tw-bg-opacity))}.fme-full-screen-btn-icon{height:1rem;width:1rem}.fme-container{min-height:250px;flex-direction:column;justify-content:flex-start;--tw-bg-opacity:1}.fme-container,.fme-loader{display:flex;height:100%;width:100%}.fme-loader{position:absolute;inset:0;z-index:20;align-items:center;justify-content:center;transition-duration:1s;transition-timing-function:cubic-bezier(0,0,.2,1)}.fme-loader-icon{height:1rem;width:1rem;animation:1s linear infinite spin;--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.fme-element-wrapper{position:relative;z-index:10;height:100%;width:100%;border-radius:.25rem}.fme-element{height:100%;width:100%;font-size:1.125rem;line-height:1.75rem}.grow{flex-grow:1}.-rotate-180,.-translate-x-5,.-translate-y-12,.rotate-180,.scale-100,.scale-95,.transform,.translate-x-0,.translate-x-12,.translate-x-5,.translate-x-full,.translate-y-12{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.truncate,.whitespace-nowrap{white-space:nowrap}.\!bg-gray-50,.\!bg-gray-700{--tw-bg-opacity:1!important}.pb-6,.py-6{padding-bottom:1.5rem}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.focus-visible\:ring-1:focus-visible,.focus-visible\:ring-2:focus-visible{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled::-moz-placeholder,.disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled::placeholder{-webkit-text-fill-color:rgba(var(--gray-400),1)}.group\/item:focus-visible .group-focus-visible\/item\:underline,.group\/link:focus-visible .group-focus-visible\/link\:underline{text-decoration-line:underline}.dark\:disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled:is(.dark *)::-moz-placeholder,.dark\:disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled:is(.dark *)::placeholder{-webkit-text-fill-color:rgba(var(--gray-500),1)}.group:focus-visible .dark\:group-focus-visible\:text-gray-200:is(.dark *),.group:hover .dark\:group-hover\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}:checked+*>.\[\:checked\+\*\>\&\]\:text-white,input:checked+.\[input\:checked\+\&\]\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}input:checked+.\[input\:checked\+\&\]\:bg-custom-600{--tw-bg-opacity:1;background-color:rgba(var(--c-600),var(--tw-bg-opacity))}input:checked+.\[input\:checked\+\&\]\:hover\:bg-custom-500:hover,input:checked+.dark\:\[input\:checked\+\&\]\:bg-custom-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}input:checked+.dark\:\[input\:checked\+\&\]\:hover\:bg-custom-400:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-400),var(--tw-bg-opacity))}input:checked:focus-visible+.\[input\:checked\:focus-visible\+\&\]\:ring-custom-500\/50{--tw-ring-color:rgba(var(--c-500),0.5)}input:checked:focus-visible+.dark\:\[input\:checked\:focus-visible\+\&\]\:ring-custom-400\/50:is(.dark *){--tw-ring-color:rgba(var(--c-400),0.5)}input:focus-visible+.\[input\:focus-visible\+\&\]\:z-10{z-index:10}input:focus-visible+.\[input\:focus-visible\+\&\]\:ring-2{--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)}input:focus-visible+.\[input\:focus-visible\+\&\]\:ring-gray-950\/10{--tw-ring-color:rgba(var(--gray-950),0.1)}input:focus-visible+.dark\:\[input\:focus-visible\+\&\]\:ring-white\/20:is(.dark *){--tw-ring-color:#fff3} diff --git a/public/css/filament/filament/app.css b/public/css/filament/filament/app.css index bb61be9017..2251c3ee1b 100644 --- a/public/css/filament/filament/app.css +++ b/public/css/filament/filament/app.css @@ -1 +1 @@ -*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.13 | MIT License | https://tailwindcss.com*/*,:after,:before{border-color:rgba(var(--gray-200),1);border-style:solid;border-width:0;box-sizing:border-box}:after,:before{--tw-content:""}:host,html{-webkit-text-size-adjust:100%;font-feature-settings:normal;-webkit-tap-highlight-color:transparent;font-family:var(--font-family),ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-feature-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em;font-variation-settings:normal}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:rgba(var(--gray-400),1);opacity:1}input::placeholder,textarea::placeholder{color:rgba(var(--gray-400),1);opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],input:where(:not([type])),select,textarea{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:rgba(var(--gray-500),var(--tw-border-opacity,1));border-radius:0;border-width:1px;font-size:1rem;line-height:1.5rem;padding:.5rem .75rem}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,input:where(:not([type])):focus,select:focus,textarea:focus{--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);border-color:#2563eb;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid transparent;outline-offset:2px}input::-moz-placeholder,textarea::-moz-placeholder{color:rgba(var(--gray-500),var(--tw-text-opacity,1));opacity:1}input::placeholder,textarea::placeholder{color:rgba(var(--gray-500),var(--tw-text-opacity,1));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-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-bottom:0;padding-top:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%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 8 4 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:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;background-origin:border-box;border-color:rgba(var(--gray-500),var(--tw-border-opacity,1));border-width:1px;color:#2563eb;display:inline-block;flex-shrink:0;height:1rem;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle;width:1rem}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{--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);outline:2px solid transparent;outline-offset:2px}[type=checkbox]:checked,[type=radio]:checked{background-color:currentColor;background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:transparent}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.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;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' 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:focus,[type=checkbox]:checked:hover,[type=radio]:checked:focus,[type=radio]:checked:hover{background-color:currentColor;border-color:transparent}[type=checkbox]:indeterminate{background-color:currentColor;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:transparent}@media (forced-colors:active) {[type=checkbox]:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{background-color:currentColor;border-color:transparent}[type=file]{background:unset;border-color:inherit;border-radius:0;border-width:0;font-size:unset;line-height:inherit;padding:0}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}:root.dark{color-scheme:dark}[data-field-wrapper]{scroll-margin-top:8rem}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:3em;margin-top:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){border-inline-start-color:var(--tw-prose-quote-borders);border-inline-start-width:.25rem;color:var(--tw-prose-quotes);font-style:italic;font-weight:500;margin-bottom:1.6em;margin-top:1.6em;padding-inline-start:1em;quotes:"\201C""\201D""\2018""\2019"}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-weight:800;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-weight:700;line-height:1.3333333;margin-bottom:1em;margin-top:2em}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-weight:600;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-bottom:2em;margin-top:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows)/10%);color:var(--tw-prose-kbd);font-family:inherit;font-size:.875em;font-weight:500;padding-inline-end:.375em;padding-bottom:.1875em;padding-top:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;color:var(--tw-prose-pre-code);font-size:.875em;font-weight:400;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;overflow-x:auto;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-top:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-bottom:2em;margin-top:2em;table-layout:auto;width:100%}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em;vertical-align:bottom}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:17 24 39;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-top:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.7142857}.prose-sm :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-bottom:.8888889em;margin-top:.8888889em}.prose-sm :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-inline-start:1.1111111em}.prose-sm :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.1428571em;line-height:1.2;margin-bottom:.8em;margin-top:0}.prose-sm :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.4285714em;line-height:1.4;margin-bottom:.8em;margin-top:1.6em}.prose-sm :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-bottom:.4444444em;margin-top:1.5555556em}.prose-sm :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){line-height:1.4285714;margin-bottom:.5714286em;margin-top:1.4285714em}.prose-sm :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-sm :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;font-size:.8571429em;padding-inline-end:.3571429em;padding-bottom:.1428571em;padding-top:.1428571em;padding-inline-start:.3571429em}.prose-sm :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em}.prose-sm :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.prose-sm :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.25rem;font-size:.8571429em;line-height:1.6666667;margin-bottom:1.6666667em;margin-top:1.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-top:.6666667em;padding-inline-start:1em}.prose-sm :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.2857143em;margin-top:.2857143em}.prose-sm :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(.prose-sm>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.5714286em;margin-top:.5714286em}.prose-sm :where(.prose-sm>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.5714286em;margin-top:.5714286em}.prose-sm :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em}.prose-sm :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;padding-inline-start:1.5714286em}.prose-sm :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2.8571429em;margin-top:2.8571429em}.prose-sm :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.6666667em;padding-top:.6666667em;padding-inline-start:1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-sm :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.3333333;margin-top:.6666667em}.prose-sm :where(.prose-sm>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose-sm>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-base{font-size:1rem;line-height:1.75}.prose-base :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose-base :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.prose-base :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.6em;margin-top:1.6em;padding-inline-start:1em}.prose-base :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.25em;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.prose-base :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.5em;line-height:1.3333333;margin-bottom:1em;margin-top:2em}.prose-base :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.25em;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.prose-base :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.prose-base :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose-base :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose-base :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-base :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose-base :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;font-size:.875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-top:.1875em;padding-inline-start:.375em}.prose-base :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.prose-base :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.prose-base :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.prose-base :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.375rem;font-size:.875em;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-top:.8571429em;padding-inline-start:1.1428571em}.prose-base :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose-base :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose-base :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.prose-base :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose-base :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose-base :where(.prose-base>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose-base :where(.prose-base>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose-base :where(.prose-base>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose-base :where(.prose-base>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose-base :where(.prose-base>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose-base :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose-base :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose-base :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose-base :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose-base :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:3em;margin-top:3em}.prose-base :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-base :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-base :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-base :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-base :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.7142857}.prose-base :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose-base :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-base :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-base :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-top:.5714286em;padding-inline-start:.5714286em}.prose-base :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-base :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-base :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose-base :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-base :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose-base :where(.prose-base>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-base :where(.prose-base>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-lg{font-size:1.125rem;line-height:1.7777778}.prose-lg :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em}.prose-lg :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2222222em;line-height:1.4545455;margin-bottom:1.0909091em;margin-top:1.0909091em}.prose-lg :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.6666667em;margin-top:1.6666667em;padding-inline-start:1em}.prose-lg :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.6666667em;line-height:1;margin-bottom:.8333333em;margin-top:0}.prose-lg :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.6666667em;line-height:1.3333333;margin-bottom:1.0666667em;margin-top:1.8666667em}.prose-lg :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.3333333em;line-height:1.5;margin-bottom:.6666667em;margin-top:1.6666667em}.prose-lg :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){line-height:1.5555556;margin-bottom:.4444444em;margin-top:1.7777778em}.prose-lg :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.prose-lg :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.prose-lg :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-lg :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.prose-lg :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;font-size:.8888889em;padding-inline-end:.4444444em;padding-bottom:.2222222em;padding-top:.2222222em;padding-inline-start:.4444444em}.prose-lg :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.prose-lg :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8666667em}.prose-lg :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.prose-lg :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.375rem;font-size:.8888889em;line-height:1.75;margin-bottom:2em;margin-top:2em;padding-inline-end:1.5em;padding-bottom:1em;padding-top:1em;padding-inline-start:1.5em}.prose-lg :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-inline-start:1.5555556em}.prose-lg :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-inline-start:1.5555556em}.prose-lg :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.6666667em;margin-top:.6666667em}.prose-lg :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4444444em}.prose-lg :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4444444em}.prose-lg :where(.prose-lg>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.prose-lg :where(.prose-lg>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(.prose-lg>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em}.prose-lg :where(.prose-lg>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(.prose-lg>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em}.prose-lg :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.prose-lg :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em}.prose-lg :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.6666667em;padding-inline-start:1.5555556em}.prose-lg :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:3.1111111em;margin-top:3.1111111em}.prose-lg :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;line-height:1.5}.prose-lg :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.75em;padding-bottom:.75em;padding-inline-start:.75em}.prose-lg :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-lg :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-lg :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.75em;padding-bottom:.75em;padding-top:.75em;padding-inline-start:.75em}.prose-lg :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-lg :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-lg :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.prose-lg :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-lg :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;line-height:1.5;margin-top:1em}.prose-lg :where(.prose-lg>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(.prose-lg>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-4{inset:1rem}.inset-x-0{left:0;right:0}.inset-x-4{left:1rem;right:1rem}.inset-y-0{bottom:0;top:0}.-bottom-1\/2{bottom:-50%}.-top-1{top:-.25rem}.-top-1\/2{top:-50%}.-top-2{top:-.5rem}.-top-3{top:-.75rem}.bottom-0{bottom:0}.bottom-1\/2{bottom:50%}.end-0{inset-inline-end:0}.end-4{inset-inline-end:1rem}.end-6{inset-inline-end:1.5rem}.left-3{left:.75rem}.start-0{inset-inline-start:0}.start-full{inset-inline-start:100%}.top-0{top:0}.top-1{top:.25rem}.top-1\/2{top:50%}.top-4{top:1rem}.top-6{top:1.5rem}.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-\[1\]{z-index:1}.order-first{order:-9999}.col-\[--col-span-default\]{grid-column:var(--col-span-default)}.col-span-full{grid-column:1/-1}.col-start-2{grid-column-start:2}.col-start-3{grid-column-start:3}.col-start-\[--col-start-default\]{grid-column-start:var(--col-start-default)}.row-start-2{grid-row-start:2}.-m-0\.5{margin:-.125rem}.-m-1{margin:-.25rem}.-m-1\.5{margin:-.375rem}.-m-2{margin:-.5rem}.-m-2\.5{margin:-.625rem}.-m-3{margin:-.75rem}.-m-3\.5{margin:-.875rem}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.-my-1{margin-bottom:-.25rem;margin-top:-.25rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-3{margin-left:.75rem;margin-right:.75rem}.mx-auto{margin-left:auto;margin-right:auto}.my-16{margin-bottom:4rem;margin-top:4rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-4{margin-bottom:1rem;margin-top:1rem}.my-auto{margin-bottom:auto;margin-top:auto}.\!mt-0{margin-top:0!important}.-mb-4{margin-bottom:-1rem}.-mb-6{margin-bottom:-1.5rem}.-me-2{margin-inline-end:-.5rem}.-ms-0\.5{margin-inline-start:-.125rem}.-ms-1{margin-inline-start:-.25rem}.-ms-2{margin-inline-start:-.5rem}.-mt-3{margin-top:-.75rem}.-mt-4{margin-top:-1rem}.-mt-6{margin-top:-1.5rem}.-mt-7{margin-top:-1.75rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.me-1{margin-inline-end:.25rem}.me-4{margin-inline-end:1rem}.me-6{margin-inline-end:1.5rem}.ml-auto{margin-left:auto}.ms-1{margin-inline-start:.25rem}.ms-auto{margin-inline-start:auto}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-6{margin-top:1.5rem}.mt-auto{margin-top:auto}.line-clamp-\[--line-clamp\]{-webkit-box-orient:vertical;-webkit-line-clamp:var(--line-clamp);display:-webkit-box;overflow:hidden}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.inline-grid{display:inline-grid}.hidden{display:none}.h-0{height:0}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-16{height:4rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-96{height:24rem}.h-\[100dvh\],.h-dvh{height:100dvh}.h-full{height:100%}.h-screen{height:100vh}.max-h-96{max-height:24rem}.min-h-\[theme\(spacing\.48\)\]{min-height:12rem}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-1\/2{width:50%}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-16{width:4rem}.w-20{width:5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\[--sidebar-width\]{width:var(--sidebar-width)}.w-\[calc\(100\%\+2rem\)\]{width:calc(100% + 2rem)}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-px{width:1px}.w-screen{width:100vw}.min-w-0{min-width:0}.min-w-\[theme\(spacing\.4\)\]{min-width:1rem}.min-w-\[theme\(spacing\.5\)\]{min-width:1.25rem}.min-w-\[theme\(spacing\.6\)\]{min-width:1.5rem}.min-w-\[theme\(spacing\.8\)\]{min-width:2rem}.\!max-w-2xl{max-width:42rem!important}.\!max-w-3xl{max-width:48rem!important}.\!max-w-4xl{max-width:56rem!important}.\!max-w-5xl{max-width:64rem!important}.\!max-w-6xl{max-width:72rem!important}.\!max-w-7xl{max-width:80rem!important}.\!max-w-\[14rem\]{max-width:14rem!important}.\!max-w-lg{max-width:32rem!important}.\!max-w-md{max-width:28rem!important}.\!max-w-sm{max-width:24rem!important}.\!max-w-xl{max-width:36rem!important}.\!max-w-xs{max-width:20rem!important}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-6xl{max-width:72rem}.max-w-7xl{max-width:80rem}.max-w-fit{max-width:-moz-fit-content;max-width:fit-content}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-max{max-width:-moz-max-content;max-width:max-content}.max-w-md{max-width:28rem}.max-w-min{max-width:-moz-min-content;max-width:min-content}.max-w-none{max-width:none}.max-w-prose{max-width:65ch}.max-w-screen-2xl{max-width:1536px}.max-w-screen-lg{max-width:1024px}.max-w-screen-md{max-width:768px}.max-w-screen-sm{max-width:640px}.max-w-screen-xl{max-width:1280px}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.flex-grow,.grow{flex-grow:1}.table-auto{table-layout:auto}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-1\/4{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\/4{--tw-translate-x:-25%}.-translate-x-12{--tw-translate-x:-3rem}.-translate-x-12,.-translate-x-5{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-5{--tw-translate-x:-1.25rem}.-translate-x-full{--tw-translate-x:-100%}.-translate-x-full,.-translate-y-1\/2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-12{--tw-translate-y:-3rem}.-translate-y-12,.-translate-y-3\/4{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-3\/4{--tw-translate-y:-75%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-12{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-12{--tw-translate-x:3rem}.translate-x-5{--tw-translate-x:1.25rem}.translate-x-5,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-12{--tw-translate-y:3rem}.-rotate-180,.translate-y-12{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-rotate-180{--tw-rotate:-180deg}.rotate-180{--tw-rotate:180deg}.rotate-180,.scale-100{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x:1;--tw-scale-y:1}.scale-95{--tw-scale-x:.95;--tw-scale-y:.95}.scale-95,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-move{cursor:move}.cursor-pointer{cursor:pointer}.cursor-wait{cursor:wait}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.resize-none{resize:none}.resize{resize:both}.scroll-mt-9{scroll-margin-top:2.25rem}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.columns-\[--cols-default\]{-moz-columns:var(--cols-default);columns:var(--cols-default)}.break-inside-avoid{-moz-column-break-inside:avoid;break-inside:avoid}.auto-cols-fr{grid-auto-columns:minmax(0,1fr)}.grid-flow-col{grid-auto-flow:column}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.grid-cols-\[--cols-default\]{grid-template-columns:var(--cols-default)}.grid-cols-\[1fr_auto_1fr\]{grid-template-columns:1fr auto 1fr}.grid-cols-\[repeat\(7\2c minmax\(theme\(spacing\.7\)\2c 1fr\)\)\]{grid-template-columns:repeat(7,minmax(1.75rem,1fr))}.grid-cols-\[repeat\(auto-fit\2c minmax\(0\2c 1fr\)\)\]{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.grid-rows-\[1fr_auto_1fr\]{grid-template-rows:1fr auto 1fr}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.content-start{align-content:flex-start}.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-items-start{justify-items:start}.justify-items-center{justify-items:center}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-x-1{-moz-column-gap:.25rem;column-gap:.25rem}.gap-x-1\.5{-moz-column-gap:.375rem;column-gap:.375rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-x-2\.5{-moz-column-gap:.625rem;column-gap:.625rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-x-5{-moz-column-gap:1.25rem;column-gap:1.25rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.gap-y-1{row-gap:.25rem}.gap-y-1\.5{row-gap:.375rem}.gap-y-2{row-gap:.5rem}.gap-y-3{row-gap:.75rem}.gap-y-4{row-gap:1rem}.gap-y-6{row-gap:1.5rem}.gap-y-7{row-gap:1.75rem}.gap-y-8{row-gap:2rem}.gap-y-px{row-gap:1px}.-space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-.25rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-.25rem*var(--tw-space-x-reverse))}.-space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-.5rem*var(--tw-space-x-reverse))}.-space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-.75rem*var(--tw-space-x-reverse))}.-space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-1rem*var(--tw-space-x-reverse))}.-space-x-5>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-1.25rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-1.25rem*var(--tw-space-x-reverse))}.-space-x-6>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-1.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-1.5rem*var(--tw-space-x-reverse))}.-space-x-7>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-1.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-1.75rem*var(--tw-space-x-reverse))}.-space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-2rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-2rem*var(--tw-space-x-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.75rem*var(--tw-space-y-reverse));margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.5rem*var(--tw-space-y-reverse));margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)))}.divide-x>:not([hidden])~:not([hidden]){--tw-divide-x-reverse:0;border-left-width:calc(1px*(1 - var(--tw-divide-x-reverse)));border-right-width:calc(1px*var(--tw-divide-x-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgba(var(--gray-100),var(--tw-divide-opacity))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgba(var(--gray-200),var(--tw-divide-opacity))}.self-start{align-self:flex-start}.self-stretch{align-self:stretch}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.justify-self-center{justify-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-x-clip{overflow-x:clip}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.break-words{overflow-wrap:break-word}.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-b-xl{border-bottom-left-radius:.75rem;border-bottom-right-radius:.75rem}.rounded-t-xl{border-top-left-radius:.75rem;border-top-right-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-x-\[0\.5px\]{border-left-width:.5px;border-right-width:.5px}.border-y{border-bottom-width:1px;border-top-width:1px}.\!border-t-0{border-top-width:0!important}.border-b{border-bottom-width:1px}.border-b-0{border-bottom-width:0}.border-e{border-inline-end-width:1px}.border-s{border-inline-start-width:1px}.border-t{border-top-width:1px}.\!border-none{border-style:none!important}.border-none{border-style:none}.border-gray-100{--tw-border-opacity:1;border-color:rgba(var(--gray-100),var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgba(var(--gray-200),var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgba(var(--gray-300),var(--tw-border-opacity))}.border-gray-600{--tw-border-opacity:1;border-color:rgba(var(--gray-600),var(--tw-border-opacity))}.border-primary-500{--tw-border-opacity:1;border-color:rgba(var(--primary-500),var(--tw-border-opacity))}.border-primary-600{--tw-border-opacity:1;border-color:rgba(var(--primary-600),var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-t-gray-200{--tw-border-opacity:1;border-top-color:rgba(var(--gray-200),var(--tw-border-opacity))}.\!bg-gray-50{--tw-bg-opacity:1!important;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))!important}.\!bg-gray-700{--tw-bg-opacity:1!important;background-color:rgba(var(--gray-700),var(--tw-bg-opacity))!important}.bg-black\/50{background-color:rgba(0,0,0,.5)}.bg-custom-100{--tw-bg-opacity:1;background-color:rgba(var(--c-100),var(--tw-bg-opacity))}.bg-custom-50{--tw-bg-opacity:1;background-color:rgba(var(--c-50),var(--tw-bg-opacity))}.bg-custom-600{--tw-bg-opacity:1;background-color:rgba(var(--c-600),var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgba(var(--gray-100),var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgba(var(--gray-200),var(--tw-bg-opacity))}.bg-gray-300{--tw-bg-opacity:1;background-color:rgba(var(--gray-300),var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgba(var(--gray-400),var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.bg-gray-950\/50{background-color:rgba(var(--gray-950),.5)}.bg-primary-500{--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity))}.bg-primary-600{--tw-bg-opacity:1;background-color:rgba(var(--primary-600),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\/0{background-color:hsla(0,0%,100%,0)}.bg-white\/5{background-color:hsla(0,0%,100%,.05)}.\!bg-none{background-image:none!important}.bg-cover{background-size:cover}.bg-center{background-position:50%}.object-cover{-o-object-fit:cover;object-fit:cover}.object-center{-o-object-position:center;object-position:center}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.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-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-bottom:.125rem;padding-top:.125rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-12{padding-bottom:3rem;padding-top:3rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-2\.5{padding-bottom:.625rem;padding-top:.625rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-3\.5{padding-bottom:.875rem;padding-top:.875rem}.py-4{padding-bottom:1rem;padding-top:1rem}.py-5{padding-bottom:1.25rem;padding-top:1.25rem}.py-6{padding-bottom:1.5rem;padding-top:1.5rem}.py-8{padding-bottom:2rem;padding-top:2rem}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pe-0{padding-inline-end:0}.pe-1{padding-inline-end:.25rem}.pe-2{padding-inline-end:.5rem}.pe-3{padding-inline-end:.75rem}.pe-4{padding-inline-end:1rem}.pe-6{padding-inline-end:1.5rem}.pe-8{padding-inline-end:2rem}.ps-0{padding-inline-start:0}.ps-1{padding-inline-start:.25rem}.ps-2{padding-inline-start:.5rem}.ps-3{padding-inline-start:.75rem}.ps-4{padding-inline-start:1rem}.ps-\[5\.25rem\]{padding-inline-start:5.25rem}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-justify{text-align:justify}.text-start{text-align:start}.text-end{text-align:end}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.align-bottom{vertical-align:bottom}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:var(--font-family),ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"}.font-serif{font-family:ui-serif,Georgia,Cambria,Times New Roman,Times,serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-extralight{font-weight:200}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.font-thin{font-weight:100}.capitalize{text-transform:capitalize}.italic{font-style:italic}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-loose{line-height:2}.tracking-tight{letter-spacing:-.025em}.tracking-tighter{letter-spacing:-.05em}.text-custom-400{--tw-text-opacity:1;color:rgba(var(--c-400),var(--tw-text-opacity))}.text-custom-50{--tw-text-opacity:1;color:rgba(var(--c-50),var(--tw-text-opacity))}.text-custom-500{--tw-text-opacity:1;color:rgba(var(--c-500),var(--tw-text-opacity))}.text-custom-600{--tw-text-opacity:1;color:rgba(var(--c-600),var(--tw-text-opacity))}.text-custom-700\/50{color:rgba(var(--c-700),.5)}.text-danger-600{--tw-text-opacity:1;color:rgba(var(--danger-600),var(--tw-text-opacity))}.text-gray-100{--tw-text-opacity:1;color:rgba(var(--gray-100),var(--tw-text-opacity))}.text-gray-200{--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgba(var(--gray-600),var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgba(var(--gray-700),var(--tw-text-opacity))}.text-gray-700\/50{color:rgba(var(--gray-700),.5)}.text-gray-950{--tw-text-opacity:1;color:rgba(var(--gray-950),var(--tw-text-opacity))}.text-primary-400{--tw-text-opacity:1;color:rgba(var(--primary-400),var(--tw-text-opacity))}.text-primary-500{--tw-text-opacity:1;color:rgba(var(--primary-500),var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgba(var(--primary-600),var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-sm,.shadow-xl{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 rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring{--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(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-0{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-0{--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(var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-1{--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)}.ring-1,.ring-2{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-2{--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)}.ring-4{--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(4px + 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)}.ring-inset{--tw-ring-inset:inset}.ring-custom-600{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--c-600),var(--tw-ring-opacity))}.ring-custom-600\/10{--tw-ring-color:rgba(var(--c-600),0.1)}.ring-custom-600\/20{--tw-ring-color:rgba(var(--c-600),0.2)}.ring-danger-600{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-600),var(--tw-ring-opacity))}.ring-gray-200{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-200),var(--tw-ring-opacity))}.ring-gray-300{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-300),var(--tw-ring-opacity))}.ring-gray-600\/10{--tw-ring-color:rgba(var(--gray-600),0.1)}.ring-gray-900\/10{--tw-ring-color:rgba(var(--gray-900),0.1)}.ring-gray-950\/10{--tw-ring-color:rgba(var(--gray-950),0.1)}.ring-gray-950\/5{--tw-ring-color:rgba(var(--gray-950),0.05)}.ring-white{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}.ring-white\/10{--tw-ring-color:hsla(0,0%,100%,.1)}.blur{--tw-blur:blur(8px)}.blur,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;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-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-opacity{transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.delay-100{transition-delay:.1s}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-75{transition-duration:75ms}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[transform\:translateZ\(0\)\]{transform:translateZ(0)}.dark\:prose-invert:is(.dark *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.placeholder\:text-gray-400::-moz-placeholder{--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.placeholder\:text-gray-400::placeholder{--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:inset-y-0:before{bottom:0;content:var(--tw-content);top:0}.before\:start-0:before{content:var(--tw-content);inset-inline-start:0}.before\:h-full:before{content:var(--tw-content);height:100%}.before\:w-0\.5:before{content:var(--tw-content);width:.125rem}.before\:bg-primary-600:before{--tw-bg-opacity:1;background-color:rgba(var(--primary-600),var(--tw-bg-opacity));content:var(--tw-content)}.first\:border-s-0:first-child{border-inline-start-width:0}.first\:border-t-0:first-child{border-top-width:0}.last\:border-e-0:last-child{border-inline-end-width:0}.first-of-type\:ps-1:first-of-type{padding-inline-start:.25rem}.last-of-type\:pe-1:last-of-type{padding-inline-end:.25rem}.checked\:ring-0:checked{--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(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-within\:bg-gray-50:focus-within{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.hover\:bg-custom-400\/10:hover{background-color:rgba(var(--c-400),.1)}.hover\:bg-custom-50:hover{--tw-bg-opacity:1;background-color:rgba(var(--c-50),var(--tw-bg-opacity))}.hover\:bg-custom-500:hover{--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgba(var(--gray-100),var(--tw-bg-opacity))}.hover\:bg-gray-400\/10:hover{background-color:rgba(var(--gray-400),.1)}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.hover\:text-custom-600:hover{--tw-text-opacity:1;color:rgba(var(--c-600),var(--tw-text-opacity))}.hover\:text-custom-700\/75:hover{color:rgba(var(--c-700),.75)}.hover\:text-gray-500:hover{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgba(var(--gray-700),var(--tw-text-opacity))}.hover\:text-gray-700\/75:hover{color:rgba(var(--gray-700),.75)}.hover\:opacity-100:hover{opacity:1}.focus\:ring-0: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(var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-0:focus,.focus\:ring-2:focus{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)}.focus\:ring-danger-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-600),var(--tw-ring-opacity))}.focus\:ring-primary-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-600),var(--tw-ring-opacity))}.focus\:ring-offset-0:focus{--tw-ring-offset-width:0px}.checked\:focus\:ring-danger-500\/50:focus:checked{--tw-ring-color:rgba(var(--danger-500),0.5)}.checked\:focus\:ring-primary-500\/50:focus:checked{--tw-ring-color:rgba(var(--primary-500),0.5)}.focus-visible\:z-10:focus-visible{z-index:10}.focus-visible\:border-primary-500:focus-visible{--tw-border-opacity:1;border-color:rgba(var(--primary-500),var(--tw-border-opacity))}.focus-visible\:bg-custom-50:focus-visible{--tw-bg-opacity:1;background-color:rgba(var(--c-50),var(--tw-bg-opacity))}.focus-visible\:bg-gray-100:focus-visible{--tw-bg-opacity:1;background-color:rgba(var(--gray-100),var(--tw-bg-opacity))}.focus-visible\:bg-gray-50:focus-visible{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.focus-visible\:text-custom-700\/75:focus-visible{color:rgba(var(--c-700),.75)}.focus-visible\:text-gray-500:focus-visible{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.focus-visible\:text-gray-700\/75:focus-visible{color:rgba(var(--gray-700),.75)}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--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-visible\:ring-2:focus-visible{--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-visible\:ring-inset:focus-visible{--tw-ring-inset:inset}.focus-visible\:ring-custom-500\/50:focus-visible{--tw-ring-color:rgba(var(--c-500),0.5)}.focus-visible\:ring-custom-600:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--c-600),var(--tw-ring-opacity))}.focus-visible\:ring-gray-400\/40:focus-visible{--tw-ring-color:rgba(var(--gray-400),0.4)}.focus-visible\:ring-primary-500:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-500),var(--tw-ring-opacity))}.focus-visible\:ring-primary-600:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-600),var(--tw-ring-opacity))}.enabled\:cursor-wait:enabled{cursor:wait}.enabled\:opacity-70:enabled{opacity:.7}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:bg-gray-50:disabled{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.disabled\:text-gray-50:disabled{--tw-text-opacity:1;color:rgba(var(--gray-50),var(--tw-text-opacity))}.disabled\:text-gray-500:disabled{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.disabled\:opacity-70:disabled{opacity:.7}.disabled\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled{-webkit-text-fill-color:rgba(var(--gray-500),1)}.disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled::-moz-placeholder{-webkit-text-fill-color:rgba(var(--gray-400),1)}.disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled::placeholder{-webkit-text-fill-color:rgba(var(--gray-400),1)}.disabled\:checked\:bg-current:checked:disabled{background-color:currentColor}.disabled\:checked\:text-gray-400:checked:disabled{--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.group\/item:first-child .group-first\/item\:rounded-s-lg{border-end-start-radius:.5rem;border-start-start-radius:.5rem}.group\/item:last-child .group-last\/item\:rounded-e-lg{border-end-end-radius:.5rem;border-start-end-radius:.5rem}.group:hover .group-hover\:text-gray-500,.group\/button:hover .group-hover\/button\:text-gray-500{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.group:hover .group-hover\:text-gray-700{--tw-text-opacity:1;color:rgba(var(--gray-700),var(--tw-text-opacity))}.group\/item:hover .group-hover\/item\:underline,.group\/link:hover .group-hover\/link\:underline{text-decoration-line:underline}.group:focus-visible .group-focus-visible\:text-gray-500{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.group:focus-visible .group-focus-visible\:text-gray-700{--tw-text-opacity:1;color:rgba(var(--gray-700),var(--tw-text-opacity))}.group\/item:focus-visible .group-focus-visible\/item\:underline{text-decoration-line:underline}.group\/link:focus-visible .group-focus-visible\/link\:underline{text-decoration-line:underline}.dark\:flex:is(.dark *){display:flex}.dark\:hidden:is(.dark *){display:none}.dark\:divide-white\/10:is(.dark *)>:not([hidden])~:not([hidden]){border-color:hsla(0,0%,100%,.1)}.dark\:divide-white\/5:is(.dark *)>:not([hidden])~:not([hidden]){border-color:hsla(0,0%,100%,.05)}.dark\:border-gray-600:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--gray-600),var(--tw-border-opacity))}.dark\:border-gray-700:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--gray-700),var(--tw-border-opacity))}.dark\:border-primary-500:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--primary-500),var(--tw-border-opacity))}.dark\:border-white\/10:is(.dark *){border-color:hsla(0,0%,100%,.1)}.dark\:border-white\/5:is(.dark *){border-color:hsla(0,0%,100%,.05)}.dark\:border-t-white\/10:is(.dark *){border-top-color:hsla(0,0%,100%,.1)}.dark\:\!bg-gray-700:is(.dark *){--tw-bg-opacity:1!important;background-color:rgba(var(--gray-700),var(--tw-bg-opacity))!important}.dark\:bg-custom-400\/10:is(.dark *){background-color:rgba(var(--c-400),.1)}.dark\:bg-custom-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}.dark\:bg-custom-500\/20:is(.dark *){background-color:rgba(var(--c-500),.2)}.dark\:bg-gray-400\/10:is(.dark *){background-color:rgba(var(--gray-400),.1)}.dark\:bg-gray-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-500),var(--tw-bg-opacity))}.dark\:bg-gray-500\/20:is(.dark *){background-color:rgba(var(--gray-500),.2)}.dark\:bg-gray-600:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-600),var(--tw-bg-opacity))}.dark\:bg-gray-700:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-700),var(--tw-bg-opacity))}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-800),var(--tw-bg-opacity))}.dark\:bg-gray-900:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-900),var(--tw-bg-opacity))}.dark\:bg-gray-900\/30:is(.dark *){background-color:rgba(var(--gray-900),.3)}.dark\:bg-gray-950:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-950),var(--tw-bg-opacity))}.dark\:bg-gray-950\/75:is(.dark *){background-color:rgba(var(--gray-950),.75)}.dark\:bg-primary-400:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--primary-400),var(--tw-bg-opacity))}.dark\:bg-primary-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity))}.dark\:bg-transparent:is(.dark *){background-color:transparent}.dark\:bg-white\/10:is(.dark *){background-color:hsla(0,0%,100%,.1)}.dark\:bg-white\/5:is(.dark *){background-color:hsla(0,0%,100%,.05)}.dark\:fill-current:is(.dark *){fill:currentColor}.dark\:text-custom-300\/50:is(.dark *){color:rgba(var(--c-300),.5)}.dark\:text-custom-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--c-400),var(--tw-text-opacity))}.dark\:text-custom-400\/10:is(.dark *){color:rgba(var(--c-400),.1)}.dark\:text-danger-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--danger-400),var(--tw-text-opacity))}.dark\:text-danger-500:is(.dark *){--tw-text-opacity:1;color:rgba(var(--danger-500),var(--tw-text-opacity))}.dark\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.dark\:text-gray-300\/50:is(.dark *){color:rgba(var(--gray-300),.5)}.dark\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.dark\:text-gray-500:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.dark\:text-gray-700:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-700),var(--tw-text-opacity))}.dark\:text-gray-800:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-800),var(--tw-text-opacity))}.dark\:text-primary-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--primary-400),var(--tw-text-opacity))}.dark\:text-primary-500:is(.dark *){--tw-text-opacity:1;color:rgba(var(--primary-500),var(--tw-text-opacity))}.dark\:text-white:is(.dark *){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.dark\:text-white\/5:is(.dark *){color:hsla(0,0%,100%,.05)}.dark\:ring-custom-400\/30:is(.dark *){--tw-ring-color:rgba(var(--c-400),0.3)}.dark\:ring-custom-500:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--c-500),var(--tw-ring-opacity))}.dark\:ring-danger-500:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-500),var(--tw-ring-opacity))}.dark\:ring-gray-400\/20:is(.dark *){--tw-ring-color:rgba(var(--gray-400),0.2)}.dark\:ring-gray-50\/10:is(.dark *){--tw-ring-color:rgba(var(--gray-50),0.1)}.dark\:ring-gray-700:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-700),var(--tw-ring-opacity))}.dark\:ring-gray-900:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-900),var(--tw-ring-opacity))}.dark\:ring-white\/10:is(.dark *){--tw-ring-color:hsla(0,0%,100%,.1)}.dark\:ring-white\/20:is(.dark *){--tw-ring-color:hsla(0,0%,100%,.2)}.dark\:placeholder\:text-gray-500:is(.dark *)::-moz-placeholder{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.dark\:placeholder\:text-gray-500:is(.dark *)::placeholder{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.dark\:before\:bg-primary-500:is(.dark *):before{--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity));content:var(--tw-content)}.dark\:checked\:bg-danger-500:checked:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--danger-500),var(--tw-bg-opacity))}.dark\:checked\:bg-primary-500:checked:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity))}.dark\:focus-within\:bg-white\/5:focus-within:is(.dark *){background-color:hsla(0,0%,100%,.05)}.dark\:hover\:bg-custom-400:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-400),var(--tw-bg-opacity))}.dark\:hover\:bg-custom-400\/10:hover:is(.dark *){background-color:rgba(var(--c-400),.1)}.dark\:hover\:bg-white\/10:hover:is(.dark *){background-color:hsla(0,0%,100%,.1)}.dark\:hover\:bg-white\/5:hover:is(.dark *){background-color:hsla(0,0%,100%,.05)}.dark\:hover\:text-custom-300:hover:is(.dark *){--tw-text-opacity:1;color:rgba(var(--c-300),var(--tw-text-opacity))}.dark\:hover\:text-custom-300\/75:hover:is(.dark *){color:rgba(var(--c-300),.75)}.dark\:hover\:text-gray-200:hover:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.dark\:hover\:text-gray-300\/75:hover:is(.dark *){color:rgba(var(--gray-300),.75)}.dark\:hover\:text-gray-400:hover:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.dark\:hover\:ring-white\/20:hover:is(.dark *){--tw-ring-color:hsla(0,0%,100%,.2)}.dark\:focus\:ring-danger-500:focus:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-500),var(--tw-ring-opacity))}.dark\:focus\:ring-primary-500:focus:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-500),var(--tw-ring-opacity))}.dark\:checked\:focus\:ring-danger-400\/50:focus:checked:is(.dark *){--tw-ring-color:rgba(var(--danger-400),0.5)}.dark\:checked\:focus\:ring-primary-400\/50:focus:checked:is(.dark *){--tw-ring-color:rgba(var(--primary-400),0.5)}.dark\:focus-visible\:border-primary-500:focus-visible:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--primary-500),var(--tw-border-opacity))}.dark\:focus-visible\:bg-custom-400\/10:focus-visible:is(.dark *){background-color:rgba(var(--c-400),.1)}.dark\:focus-visible\:bg-white\/5:focus-visible:is(.dark *){background-color:hsla(0,0%,100%,.05)}.dark\:focus-visible\:text-custom-300\/75:focus-visible:is(.dark *){color:rgba(var(--c-300),.75)}.dark\:focus-visible\:text-gray-300\/75:focus-visible:is(.dark *){color:rgba(var(--gray-300),.75)}.dark\:focus-visible\:text-gray-400:focus-visible:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.dark\:focus-visible\:ring-custom-400\/50:focus-visible:is(.dark *){--tw-ring-color:rgba(var(--c-400),0.5)}.dark\:focus-visible\:ring-custom-500:focus-visible:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--c-500),var(--tw-ring-opacity))}.dark\:focus-visible\:ring-primary-500:focus-visible:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-500),var(--tw-ring-opacity))}.dark\:disabled\:bg-transparent:disabled:is(.dark *){background-color:transparent}.dark\:disabled\:text-gray-400:disabled:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.dark\:disabled\:ring-white\/10:disabled:is(.dark *){--tw-ring-color:hsla(0,0%,100%,.1)}.dark\:disabled\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled:is(.dark *){-webkit-text-fill-color:rgba(var(--gray-400),1)}.dark\:disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled:is(.dark *)::-moz-placeholder{-webkit-text-fill-color:rgba(var(--gray-500),1)}.dark\:disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled:is(.dark *)::placeholder{-webkit-text-fill-color:rgba(var(--gray-500),1)}.dark\:disabled\:checked\:bg-gray-600:checked:disabled:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-600),var(--tw-bg-opacity))}.group\/button:hover .dark\:group-hover\/button\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.group:hover .dark\:group-hover\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.group:hover .dark\:group-hover\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.group:focus-visible .dark\:group-focus-visible\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.group:focus-visible .dark\:group-focus-visible\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}@media (min-width:640px){.sm\:relative{position:relative}.sm\:inset-x-auto{left:auto;right:auto}.sm\:end-0{inset-inline-end:0}.sm\:col-\[--col-span-sm\]{grid-column:var(--col-span-sm)}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:col-start-\[--col-start-sm\]{grid-column-start:var(--col-start-sm)}.sm\:-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.sm\:-my-2{margin-bottom:-.5rem;margin-top:-.5rem}.sm\:ms-auto{margin-inline-start:auto}.sm\:mt-7{margin-top:1.75rem}.sm\:block{display:block}.sm\:flex{display:flex}.sm\:table-cell{display:table-cell}.sm\:grid{display:grid}.sm\:inline-grid{display:inline-grid}.sm\:hidden{display:none}.sm\:w-\[calc\(100\%\+3rem\)\]{width:calc(100% + 3rem)}.sm\:w-screen{width:100vw}.sm\:max-w-2xl{max-width:42rem}.sm\:max-w-3xl{max-width:48rem}.sm\:max-w-4xl{max-width:56rem}.sm\:max-w-5xl{max-width:64rem}.sm\:max-w-6xl{max-width:72rem}.sm\:max-w-7xl{max-width:80rem}.sm\:max-w-lg{max-width:32rem}.sm\:max-w-md{max-width:28rem}.sm\:max-w-sm{max-width:24rem}.sm\:max-w-xl{max-width:36rem}.sm\:max-w-xs{max-width:20rem}.sm\:columns-\[--cols-sm\]{-moz-columns:var(--cols-sm);columns:var(--cols-sm)}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-\[--cols-sm\]{grid-template-columns:var(--cols-sm)}.sm\:grid-cols-\[repeat\(auto-fit\2c minmax\(0\2c 1fr\)\)\]{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.sm\:grid-rows-\[1fr_auto_3fr\]{grid-template-rows:1fr auto 3fr}.sm\:flex-row{flex-direction:row}.sm\:flex-nowrap{flex-wrap:nowrap}.sm\:items-start{align-items:flex-start}.sm\:items-end{align-items:flex-end}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:gap-1{gap:.25rem}.sm\:gap-3{gap:.75rem}.sm\:gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.sm\:rounded-xl{border-radius:.75rem}.sm\:p-10{padding:2.5rem}.sm\:px-12{padding-left:3rem;padding-right:3rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.sm\:pe-3{padding-inline-end:.75rem}.sm\:pe-6{padding-inline-end:1.5rem}.sm\:ps-3{padding-inline-start:.75rem}.sm\:ps-6{padding-inline-start:1.5rem}.sm\:pt-1\.5{padding-top:.375rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}.sm\:leading-6{line-height:1.5rem}.sm\:first-of-type\:ps-3:first-of-type{padding-inline-start:.75rem}.sm\:first-of-type\:ps-6:first-of-type{padding-inline-start:1.5rem}.sm\:last-of-type\:pe-3:last-of-type{padding-inline-end:.75rem}.sm\:last-of-type\:pe-6:last-of-type{padding-inline-end:1.5rem}}@media (min-width:768px){.md\:bottom-4{bottom:1rem}.md\:order-first{order:-9999}.md\:col-\[--col-span-md\]{grid-column:var(--col-span-md)}.md\:col-span-2{grid-column:span 2/span 2}.md\:col-start-\[--col-start-md\]{grid-column-start:var(--col-start-md)}.md\:block{display:block}.md\:flex{display:flex}.md\:table-cell{display:table-cell}.md\:inline-grid{display:inline-grid}.md\:hidden{display:none}.md\:w-max{width:-moz-max-content;width:max-content}.md\:max-w-60{max-width:15rem}.md\:columns-\[--cols-md\]{-moz-columns:var(--cols-md);columns:var(--cols-md)}.md\:grid-flow-col{grid-auto-flow:column}.md\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-\[--cols-md\]{grid-template-columns:var(--cols-md)}.md\:flex-row{flex-direction:row}.md\:items-start{align-items:flex-start}.md\:items-end{align-items:flex-end}.md\:items-center{align-items:center}.md\:justify-end{justify-content:flex-end}.md\:gap-1{gap:.25rem}.md\:gap-3{gap:.75rem}.md\:divide-y-0>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(0px*var(--tw-divide-y-reverse));border-top-width:calc(0px*(1 - var(--tw-divide-y-reverse)))}.md\:overflow-x-auto{overflow-x:auto}.md\:rounded-xl{border-radius:.75rem}.md\:p-20{padding:5rem}.md\:px-6{padding-left:1.5rem;padding-right:1.5rem}.md\:pe-6{padding-inline-end:1.5rem}.md\:ps-3{padding-inline-start:.75rem}}@media (min-width:1024px){.lg\:sticky{position:sticky}.lg\:z-0{z-index:0}.lg\:col-\[--col-span-lg\]{grid-column:var(--col-span-lg)}.lg\:col-start-\[--col-start-lg\]{grid-column-start:var(--col-start-lg)}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:table-cell{display:table-cell}.lg\:inline-grid{display:inline-grid}.lg\:hidden{display:none}.lg\:h-full{height:100%}.lg\:max-w-xs{max-width:20rem}.lg\:-translate-x-full{--tw-translate-x:-100%}.lg\:-translate-x-full,.lg\:translate-x-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:translate-x-0{--tw-translate-x:0px}.lg\:columns-\[--cols-lg\]{-moz-columns:var(--cols-lg);columns:var(--cols-lg)}.lg\:grid-cols-\[--cols-lg\]{grid-template-columns:var(--cols-lg)}.lg\:flex-row{flex-direction:row}.lg\:items-start{align-items:flex-start}.lg\:items-end{align-items:flex-end}.lg\:items-center{align-items:center}.lg\:gap-1{gap:.25rem}.lg\:gap-3{gap:.75rem}.lg\:bg-transparent{background-color:transparent}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:pe-8{padding-inline-end:2rem}.lg\:shadow-none{--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000}.lg\:shadow-none,.lg\:shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.lg\:shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.lg\:ring-0{--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(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)}.lg\:transition{transition-duration:.15s;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)}.lg\:transition-none{transition-property:none}.lg\:delay-100{transition-delay:.1s}.dark\:lg\:bg-transparent:is(.dark *){background-color:transparent}}@media (min-width:1280px){.xl\:col-\[--col-span-xl\]{grid-column:var(--col-span-xl)}.xl\:col-start-\[--col-start-xl\]{grid-column-start:var(--col-start-xl)}.xl\:block{display:block}.xl\:table-cell{display:table-cell}.xl\:inline-grid{display:inline-grid}.xl\:hidden{display:none}.xl\:columns-\[--cols-xl\]{-moz-columns:var(--cols-xl);columns:var(--cols-xl)}.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:grid-cols-\[--cols-xl\]{grid-template-columns:var(--cols-xl)}.xl\:flex-row{flex-direction:row}.xl\:items-start{align-items:flex-start}.xl\:items-end{align-items:flex-end}.xl\:items-center{align-items:center}.xl\:gap-1{gap:.25rem}.xl\:gap-3{gap:.75rem}}@media (min-width:1536px){.\32xl\:col-\[--col-span-2xl\]{grid-column:var(--col-span-2xl)}.\32xl\:col-start-\[--col-start-2xl\]{grid-column-start:var(--col-start-2xl)}.\32xl\:block{display:block}.\32xl\:table-cell{display:table-cell}.\32xl\:inline-grid{display:inline-grid}.\32xl\:hidden{display:none}.\32xl\:columns-\[--cols-2xl\]{-moz-columns:var(--cols-2xl);columns:var(--cols-2xl)}.\32xl\:grid-cols-\[--cols-2xl\]{grid-template-columns:var(--cols-2xl)}.\32xl\:flex-row{flex-direction:row}.\32xl\:items-start{align-items:flex-start}.\32xl\:items-end{align-items:flex-end}.\32xl\:items-center{align-items:center}.\32xl\:gap-1{gap:.25rem}.\32xl\:gap-3{gap:.75rem}}.ltr\:hidden:where([dir=ltr],[dir=ltr] *){display:none}.rtl\:hidden:where([dir=rtl],[dir=rtl] *){display:none}.rtl\:-translate-x-0:where([dir=rtl],[dir=rtl] *){--tw-translate-x:-0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:-translate-x-5:where([dir=rtl],[dir=rtl] *){--tw-translate-x:-1.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:-translate-x-full:where([dir=rtl],[dir=rtl] *){--tw-translate-x:-100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:translate-x-1\/2:where([dir=rtl],[dir=rtl] *){--tw-translate-x:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:translate-x-1\/4:where([dir=rtl],[dir=rtl] *){--tw-translate-x:25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:translate-x-full:where([dir=rtl],[dir=rtl] *){--tw-translate-x:100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:rotate-180:where([dir=rtl],[dir=rtl] *){--tw-rotate:180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:flex-row-reverse:where([dir=rtl],[dir=rtl] *){flex-direction:row-reverse}.rtl\:divide-x-reverse:where([dir=rtl],[dir=rtl] *)>:not([hidden])~:not([hidden]){--tw-divide-x-reverse:1}@media (min-width:1024px){.rtl\:lg\:-translate-x-0:where([dir=rtl],[dir=rtl] *){--tw-translate-x:-0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:lg\:translate-x-full:where([dir=rtl],[dir=rtl] *){--tw-translate-x:100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}}.\[\&\.trix-active\]\:bg-gray-50.trix-active{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.\[\&\.trix-active\]\:text-primary-600.trix-active{--tw-text-opacity:1;color:rgba(var(--primary-600),var(--tw-text-opacity))}.dark\:\[\&\.trix-active\]\:bg-white\/5.trix-active:is(.dark *){background-color:hsla(0,0%,100%,.05)}.dark\:\[\&\.trix-active\]\:text-primary-400.trix-active:is(.dark *){--tw-text-opacity:1;color:rgba(var(--primary-400),var(--tw-text-opacity))}.\[\&\:\:-ms-reveal\]\:hidden::-ms-reveal{display:none}.\[\&\:not\(\:first-of-type\)\]\:border-s:not(:first-of-type){border-inline-start-width:1px}.\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-2:focus-within:not(:has(.fi-ac-action: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)}.\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-danger-600:focus-within:not(:has(.fi-ac-action:focus)){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-600),var(--tw-ring-opacity))}.\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-primary-600:focus-within:not(:has(.fi-ac-action:focus)){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-600),var(--tw-ring-opacity))}.dark\:\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-danger-500:focus-within:not(:has(.fi-ac-action:focus)):is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-500),var(--tw-ring-opacity))}.dark\:\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-primary-500:focus-within:not(:has(.fi-ac-action:focus)):is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-500),var(--tw-ring-opacity))}.\[\&\:not\(\:last-of-type\)\]\:border-e:not(:last-of-type){border-inline-end-width:1px}.\[\&\:not\(\:nth-child\(1_of_\.fi-btn\)\)\]\:shadow-\[-1px_0_0_0_theme\(colors\.gray\.200\)\]:not(:nth-child(1 of .fi-btn)){--tw-shadow:-1px 0 0 0 rgba(var(--gray-200),1);--tw-shadow-colored:-1px 0 0 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)}.dark\:\[\&\:not\(\:nth-child\(1_of_\.fi-btn\)\)\]\:shadow-\[-1px_0_0_0_theme\(colors\.white\/20\%\)\]:not(:nth-child(1 of .fi-btn)):is(.dark *){--tw-shadow:-1px 0 0 0 hsla(0,0%,100%,.2);--tw-shadow-colored:-1px 0 0 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)}.\[\&\:not\(\:nth-last-child\(1_of_\.fi-btn\)\)\]\:me-px:not(:nth-last-child(1 of .fi-btn)){margin-inline-end:1px}.\[\&\:nth-child\(1_of_\.fi-btn\)\]\:rounded-s-lg:nth-child(1 of .fi-btn){border-end-start-radius:.5rem;border-start-start-radius:.5rem}.\[\&\:nth-last-child\(1_of_\.fi-btn\)\]\:rounded-e-lg:nth-last-child(1 of .fi-btn){border-end-end-radius:.5rem;border-start-end-radius:.5rem}.\[\&\>\*\:first-child\]\:relative>:first-child{position:relative}.\[\&\>\*\:first-child\]\:mt-0>:first-child{margin-top:0}.\[\&\>\*\:first-child\]\:before\:absolute>:first-child:before{content:var(--tw-content);position:absolute}.\[\&\>\*\:first-child\]\:before\:inset-y-0>:first-child:before{bottom:0;content:var(--tw-content);top:0}.\[\&\>\*\:first-child\]\:before\:start-0>:first-child:before{content:var(--tw-content);inset-inline-start:0}.\[\&\>\*\:first-child\]\:before\:w-0\.5>:first-child:before{content:var(--tw-content);width:.125rem}.\[\&\>\*\:first-child\]\:before\:bg-primary-600>:first-child:before{--tw-bg-opacity:1;background-color:rgba(var(--primary-600),var(--tw-bg-opacity));content:var(--tw-content)}.\[\&\>\*\:first-child\]\:dark\:before\:bg-primary-500:is(.dark *)>:first-child:before{--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity));content:var(--tw-content)}.\[\&\>\*\:last-child\]\:mb-0>:last-child{margin-bottom:0}.\[\&_\.choices\\_\\_inner\]\:ps-0 .choices__inner{padding-inline-start:0}.\[\&_\.fi-badge-delete-button\]\:hidden .fi-badge-delete-button{display:none}.\[\&_\.filepond--root\]\:font-sans .filepond--root{font-family:var(--font-family),ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"}.\[\&_optgroup\]\:bg-white optgroup{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.\[\&_optgroup\]\:dark\:bg-gray-900:is(.dark *) optgroup{--tw-bg-opacity:1;background-color:rgba(var(--gray-900),var(--tw-bg-opacity))}.\[\&_option\]\:bg-white option{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.\[\&_option\]\:dark\:bg-gray-900:is(.dark *) option{--tw-bg-opacity:1;background-color:rgba(var(--gray-900),var(--tw-bg-opacity))}:checked+*>.\[\:checked\+\*\>\&\]\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}@media(hover:hover){.\[\@media\(hover\:hover\)\]\:transition{transition-duration:.15s;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)}.\[\@media\(hover\:hover\)\]\:duration-75{transition-duration:75ms}}input:checked+.\[input\:checked\+\&\]\:bg-custom-600{--tw-bg-opacity:1;background-color:rgba(var(--c-600),var(--tw-bg-opacity))}input:checked+.\[input\:checked\+\&\]\:bg-gray-400{--tw-bg-opacity:1;background-color:rgba(var(--gray-400),var(--tw-bg-opacity))}input:checked+.\[input\:checked\+\&\]\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}input:checked+.\[input\:checked\+\&\]\:ring-0{--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(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)}input:checked+.\[input\:checked\+\&\]\:hover\:bg-custom-500:hover{--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}input:checked+.\[input\:checked\+\&\]\:hover\:bg-gray-300:hover{--tw-bg-opacity:1;background-color:rgba(var(--gray-300),var(--tw-bg-opacity))}input:checked+.dark\:\[input\:checked\+\&\]\:bg-custom-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}input:checked+.dark\:\[input\:checked\+\&\]\:bg-gray-600:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-600),var(--tw-bg-opacity))}input:checked+.dark\:\[input\:checked\+\&\]\:hover\:bg-custom-400:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-400),var(--tw-bg-opacity))}input:checked+.dark\:\[input\:checked\+\&\]\:hover\:bg-gray-500:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-500),var(--tw-bg-opacity))}input:checked:focus-visible+.\[input\:checked\:focus-visible\+\&\]\:ring-custom-500\/50{--tw-ring-color:rgba(var(--c-500),0.5)}input:checked:focus-visible+.dark\:\[input\:checked\:focus-visible\+\&\]\:ring-custom-400\/50:is(.dark *){--tw-ring-color:rgba(var(--c-400),0.5)}input:focus-visible+.\[input\:focus-visible\+\&\]\:z-10{z-index:10}input:focus-visible+.\[input\:focus-visible\+\&\]\:ring-2{--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)}input:focus-visible+.\[input\:focus-visible\+\&\]\:ring-gray-950\/10{--tw-ring-color:rgba(var(--gray-950),0.1)}input:focus-visible+.dark\:\[input\:focus-visible\+\&\]\:ring-white\/20:is(.dark *){--tw-ring-color:hsla(0,0%,100%,.2)} \ No newline at end of file +*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.13 | MIT License | https://tailwindcss.com*/*,:after,:before{border-color:rgba(var(--gray-200),1);border-style:solid;border-width:0;box-sizing:border-box}:after,:before{--tw-content:""}:host,html{-webkit-text-size-adjust:100%;font-feature-settings:normal;-webkit-tap-highlight-color:transparent;font-family:var(--font-family),ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-variation-settings:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-feature-settings:normal;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em;font-variation-settings:normal}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-feature-settings:inherit;color:inherit;font-family:inherit;font-size:100%;font-variation-settings:inherit;font-weight:inherit;letter-spacing:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:rgba(var(--gray-400),1);opacity:1}input::placeholder,textarea::placeholder{color:rgba(var(--gray-400),1);opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],input:where(:not([type])),select,textarea{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:rgba(var(--gray-500),var(--tw-border-opacity,1));border-radius:0;border-width:1px;font-size:1rem;line-height:1.5rem;padding:.5rem .75rem}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,input:where(:not([type])):focus,select:focus,textarea:focus{--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);border-color:#2563eb;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);outline:2px solid transparent;outline-offset:2px}input::-moz-placeholder,textarea::-moz-placeholder{color:rgba(var(--gray-500),var(--tw-text-opacity,1));opacity:1}input::placeholder,textarea::placeholder{color:rgba(var(--gray-500),var(--tw-text-opacity,1));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-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-bottom:0;padding-top:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%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 8 4 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:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{--tw-shadow:0 0 #0000;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;background-origin:border-box;border-color:rgba(var(--gray-500),var(--tw-border-opacity,1));border-width:1px;color:#2563eb;display:inline-block;flex-shrink:0;height:1rem;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle;width:1rem}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{--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);outline:2px solid transparent;outline-offset:2px}[type=checkbox]:checked,[type=radio]:checked{background-color:currentColor;background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:transparent}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.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;charset=utf-8,%3Csvg viewBox='0 0 16 16' fill='%23fff' 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:focus,[type=checkbox]:checked:hover,[type=radio]:checked:focus,[type=radio]:checked:hover{background-color:currentColor;border-color:transparent}[type=checkbox]:indeterminate{background-color:currentColor;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:transparent}@media (forced-colors:active) {[type=checkbox]:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{background-color:currentColor;border-color:transparent}[type=file]{background:unset;border-color:inherit;border-radius:0;border-width:0;font-size:unset;line-height:inherit;padding:0}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}:root.dark{color-scheme:dark}[data-field-wrapper]{scroll-margin-top:8rem}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:3em;margin-top:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){border-inline-start-color:var(--tw-prose-quote-borders);border-inline-start-width:.25rem;color:var(--tw-prose-quotes);font-style:italic;font-weight:500;margin-bottom:1.6em;margin-top:1.6em;padding-inline-start:1em;quotes:"\201C""\201D""\2018""\2019"}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-weight:800;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-weight:700;line-height:1.3333333;margin-bottom:1em;margin-top:2em}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-weight:600;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-bottom:2em;margin-top:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows)/10%);color:var(--tw-prose-kbd);font-family:inherit;font-size:.875em;font-weight:500;padding-inline-end:.375em;padding-bottom:.1875em;padding-top:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;color:var(--tw-prose-pre-code);font-size:.875em;font-weight:400;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;overflow-x:auto;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-top:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:transparent;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-bottom:2em;margin-top:2em;table-layout:auto;width:100%}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em;vertical-align:bottom}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:17 24 39;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-top:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.7142857}.prose-sm :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-bottom:.8888889em;margin-top:.8888889em}.prose-sm :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-inline-start:1.1111111em}.prose-sm :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.1428571em;line-height:1.2;margin-bottom:.8em;margin-top:0}.prose-sm :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.4285714em;line-height:1.4;margin-bottom:.8em;margin-top:1.6em}.prose-sm :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-bottom:.4444444em;margin-top:1.5555556em}.prose-sm :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){line-height:1.4285714;margin-bottom:.5714286em;margin-top:1.4285714em}.prose-sm :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-sm :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;font-size:.8571429em;padding-inline-end:.3571429em;padding-bottom:.1428571em;padding-top:.1428571em;padding-inline-start:.3571429em}.prose-sm :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em}.prose-sm :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.prose-sm :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.25rem;font-size:.8571429em;line-height:1.6666667;margin-bottom:1.6666667em;margin-top:1.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-top:.6666667em;padding-inline-start:1em}.prose-sm :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.2857143em;margin-top:.2857143em}.prose-sm :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(.prose-sm>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.5714286em;margin-top:.5714286em}.prose-sm :where(.prose-sm>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.5714286em;margin-top:.5714286em}.prose-sm :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em}.prose-sm :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;padding-inline-start:1.5714286em}.prose-sm :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2.8571429em;margin-top:2.8571429em}.prose-sm :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.6666667em;padding-top:.6666667em;padding-inline-start:1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-sm :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.3333333;margin-top:.6666667em}.prose-sm :where(.prose-sm>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose-sm>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-base{font-size:1rem;line-height:1.75}.prose-base :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose-base :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.prose-base :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.6em;margin-top:1.6em;padding-inline-start:1em}.prose-base :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.25em;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.prose-base :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.5em;line-height:1.3333333;margin-bottom:1em;margin-top:2em}.prose-base :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.25em;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.prose-base :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.prose-base :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose-base :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose-base :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-base :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose-base :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;font-size:.875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-top:.1875em;padding-inline-start:.375em}.prose-base :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.prose-base :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.prose-base :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.prose-base :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.375rem;font-size:.875em;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-top:.8571429em;padding-inline-start:1.1428571em}.prose-base :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose-base :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.prose-base :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.prose-base :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose-base :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose-base :where(.prose-base>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose-base :where(.prose-base>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose-base :where(.prose-base>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose-base :where(.prose-base>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose-base :where(.prose-base>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose-base :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose-base :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose-base :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose-base :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose-base :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:3em;margin-top:3em}.prose-base :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-base :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-base :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-base :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-base :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.7142857}.prose-base :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose-base :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-base :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-base :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-top:.5714286em;padding-inline-start:.5714286em}.prose-base :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-base :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-base :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose-base :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-base :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose-base :where(.prose-base>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-base :where(.prose-base>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-lg{font-size:1.125rem;line-height:1.7777778}.prose-lg :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em}.prose-lg :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2222222em;line-height:1.4545455;margin-bottom:1.0909091em;margin-top:1.0909091em}.prose-lg :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.6666667em;margin-top:1.6666667em;padding-inline-start:1em}.prose-lg :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.6666667em;line-height:1;margin-bottom:.8333333em;margin-top:0}.prose-lg :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.6666667em;line-height:1.3333333;margin-bottom:1.0666667em;margin-top:1.8666667em}.prose-lg :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.3333333em;line-height:1.5;margin-bottom:.6666667em;margin-top:1.6666667em}.prose-lg :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){line-height:1.5555556;margin-bottom:.4444444em;margin-top:1.7777778em}.prose-lg :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.prose-lg :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.prose-lg :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-lg :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.prose-lg :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;font-size:.8888889em;padding-inline-end:.4444444em;padding-bottom:.2222222em;padding-top:.2222222em;padding-inline-start:.4444444em}.prose-lg :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.prose-lg :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8666667em}.prose-lg :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.prose-lg :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.375rem;font-size:.8888889em;line-height:1.75;margin-bottom:2em;margin-top:2em;padding-inline-end:1.5em;padding-bottom:1em;padding-top:1em;padding-inline-start:1.5em}.prose-lg :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-inline-start:1.5555556em}.prose-lg :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-inline-start:1.5555556em}.prose-lg :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.6666667em;margin-top:.6666667em}.prose-lg :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4444444em}.prose-lg :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4444444em}.prose-lg :where(.prose-lg>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.prose-lg :where(.prose-lg>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(.prose-lg>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em}.prose-lg :where(.prose-lg>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(.prose-lg>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em}.prose-lg :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.prose-lg :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em}.prose-lg :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em}.prose-lg :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.6666667em;padding-inline-start:1.5555556em}.prose-lg :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:3.1111111em;margin-top:3.1111111em}.prose-lg :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;line-height:1.5}.prose-lg :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.75em;padding-bottom:.75em;padding-inline-start:.75em}.prose-lg :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-lg :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-lg :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.75em;padding-bottom:.75em;padding-top:.75em;padding-inline-start:.75em}.prose-lg :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-lg :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-lg :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.prose-lg :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-lg :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em;line-height:1.5;margin-top:1em}.prose-lg :where(.prose-lg>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-lg :where(.prose-lg>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-4{inset:1rem}.inset-x-0{left:0;right:0}.inset-x-4{left:1rem;right:1rem}.inset-y-0{bottom:0;top:0}.-bottom-1\/2{bottom:-50%}.-top-1{top:-.25rem}.-top-1\/2{top:-50%}.-top-2{top:-.5rem}.-top-3{top:-.75rem}.bottom-0{bottom:0}.bottom-1\/2{bottom:50%}.end-0{inset-inline-end:0}.end-4{inset-inline-end:1rem}.end-6{inset-inline-end:1.5rem}.left-3{left:.75rem}.start-0{inset-inline-start:0}.start-full{inset-inline-start:100%}.top-0{top:0}.top-1{top:.25rem}.top-1\/2{top:50%}.top-4{top:1rem}.top-6{top:1.5rem}.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-\[1\]{z-index:1}.order-first{order:-9999}.col-\[--col-span-default\]{grid-column:var(--col-span-default)}.col-span-full{grid-column:1/-1}.col-start-2{grid-column-start:2}.col-start-3{grid-column-start:3}.col-start-\[--col-start-default\]{grid-column-start:var(--col-start-default)}.row-start-2{grid-row-start:2}.-m-0\.5{margin:-.125rem}.-m-1{margin:-.25rem}.-m-1\.5{margin:-.375rem}.-m-2{margin:-.5rem}.-m-2\.5{margin:-.625rem}.-m-3{margin:-.75rem}.-m-3\.5{margin:-.875rem}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.-my-1{margin-bottom:-.25rem;margin-top:-.25rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-3{margin-left:.75rem;margin-right:.75rem}.mx-auto{margin-left:auto;margin-right:auto}.my-16{margin-bottom:4rem;margin-top:4rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-4{margin-bottom:1rem;margin-top:1rem}.my-auto{margin-bottom:auto;margin-top:auto}.\!mt-0{margin-top:0!important}.-mb-4{margin-bottom:-1rem}.-mb-6{margin-bottom:-1.5rem}.-me-2{margin-inline-end:-.5rem}.-ms-0\.5{margin-inline-start:-.125rem}.-ms-1{margin-inline-start:-.25rem}.-ms-2{margin-inline-start:-.5rem}.-mt-3{margin-top:-.75rem}.-mt-4{margin-top:-1rem}.-mt-6{margin-top:-1.5rem}.-mt-7{margin-top:-1.75rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.me-1{margin-inline-end:.25rem}.me-4{margin-inline-end:1rem}.me-6{margin-inline-end:1.5rem}.ml-auto{margin-left:auto}.ms-1{margin-inline-start:.25rem}.ms-auto{margin-inline-start:auto}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-6{margin-top:1.5rem}.mt-auto{margin-top:auto}.line-clamp-\[--line-clamp\]{-webkit-box-orient:vertical;-webkit-line-clamp:var(--line-clamp);display:-webkit-box;overflow:hidden}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.inline-grid{display:inline-grid}.hidden{display:none}.h-0{height:0}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-16{height:4rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-96{height:24rem}.h-\[100dvh\],.h-dvh{height:100dvh}.h-full{height:100%}.h-screen{height:100vh}.max-h-96{max-height:24rem}.min-h-\[theme\(spacing\.48\)\]{min-height:12rem}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-1\/2{width:50%}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-16{width:4rem}.w-20{width:5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\[--sidebar-width\]{width:var(--sidebar-width)}.w-\[calc\(100\%\+2rem\)\]{width:calc(100% + 2rem)}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.w-px{width:1px}.w-screen{width:100vw}.min-w-0{min-width:0}.min-w-\[theme\(spacing\.4\)\]{min-width:1rem}.min-w-\[theme\(spacing\.5\)\]{min-width:1.25rem}.min-w-\[theme\(spacing\.6\)\]{min-width:1.5rem}.min-w-\[theme\(spacing\.8\)\]{min-width:2rem}.\!max-w-2xl{max-width:42rem!important}.\!max-w-3xl{max-width:48rem!important}.\!max-w-4xl{max-width:56rem!important}.\!max-w-5xl{max-width:64rem!important}.\!max-w-6xl{max-width:72rem!important}.\!max-w-7xl{max-width:80rem!important}.\!max-w-\[14rem\]{max-width:14rem!important}.\!max-w-lg{max-width:32rem!important}.\!max-w-md{max-width:28rem!important}.\!max-w-sm{max-width:24rem!important}.\!max-w-xl{max-width:36rem!important}.\!max-w-xs{max-width:20rem!important}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-6xl{max-width:72rem}.max-w-7xl{max-width:80rem}.max-w-fit{max-width:-moz-fit-content;max-width:fit-content}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-max{max-width:-moz-max-content;max-width:max-content}.max-w-md{max-width:28rem}.max-w-min{max-width:-moz-min-content;max-width:min-content}.max-w-none{max-width:none}.max-w-prose{max-width:65ch}.max-w-screen-2xl{max-width:1536px}.max-w-screen-lg{max-width:1024px}.max-w-screen-md{max-width:768px}.max-w-screen-sm{max-width:640px}.max-w-screen-xl{max-width:1280px}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.flex-grow,.grow{flex-grow:1}.table-auto{table-layout:auto}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-x-1\/4{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\/4{--tw-translate-x:-25%}.-translate-x-12{--tw-translate-x:-3rem}.-translate-x-12,.-translate-x-5{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-5{--tw-translate-x:-1.25rem}.-translate-x-full{--tw-translate-x:-100%}.-translate-x-full,.-translate-y-1\/2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%}.-translate-y-12{--tw-translate-y:-3rem}.-translate-y-12,.-translate-y-3\/4{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-3\/4{--tw-translate-y:-75%}.translate-x-0{--tw-translate-x:0px}.translate-x-0,.translate-x-12{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-12{--tw-translate-x:3rem}.translate-x-5{--tw-translate-x:1.25rem}.translate-x-5,.translate-x-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-full{--tw-translate-x:100%}.translate-y-12{--tw-translate-y:3rem}.-rotate-180,.translate-y-12{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-rotate-180{--tw-rotate:-180deg}.rotate-180{--tw-rotate:180deg}.rotate-180,.scale-100{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x:1;--tw-scale-y:1}.scale-95{--tw-scale-x:.95;--tw-scale-y:.95}.scale-95,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-move{cursor:move}.cursor-pointer{cursor:pointer}.cursor-wait{cursor:wait}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.resize-none{resize:none}.resize{resize:both}.scroll-mt-9{scroll-margin-top:2.25rem}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.columns-\[--cols-default\]{-moz-columns:var(--cols-default);columns:var(--cols-default)}.break-inside-avoid{-moz-column-break-inside:avoid;break-inside:avoid}.auto-cols-fr{grid-auto-columns:minmax(0,1fr)}.grid-flow-col{grid-auto-flow:column}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.grid-cols-\[--cols-default\]{grid-template-columns:var(--cols-default)}.grid-cols-\[1fr_auto_1fr\]{grid-template-columns:1fr auto 1fr}.grid-cols-\[repeat\(7\2c minmax\(theme\(spacing\.7\)\2c 1fr\)\)\]{grid-template-columns:repeat(7,minmax(1.75rem,1fr))}.grid-cols-\[repeat\(auto-fit\2c minmax\(0\2c 1fr\)\)\]{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.grid-rows-\[1fr_auto_1fr\]{grid-template-rows:1fr auto 1fr}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.content-start{align-content:flex-start}.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-items-start{justify-items:start}.justify-items-center{justify-items:center}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-x-1{-moz-column-gap:.25rem;column-gap:.25rem}.gap-x-1\.5{-moz-column-gap:.375rem;column-gap:.375rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.gap-x-2\.5{-moz-column-gap:.625rem;column-gap:.625rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-x-5{-moz-column-gap:1.25rem;column-gap:1.25rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.gap-y-1{row-gap:.25rem}.gap-y-1\.5{row-gap:.375rem}.gap-y-2{row-gap:.5rem}.gap-y-3{row-gap:.75rem}.gap-y-4{row-gap:1rem}.gap-y-6{row-gap:1.5rem}.gap-y-7{row-gap:1.75rem}.gap-y-8{row-gap:2rem}.gap-y-px{row-gap:1px}.-space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-.25rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-.25rem*var(--tw-space-x-reverse))}.-space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-.5rem*var(--tw-space-x-reverse))}.-space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-.75rem*var(--tw-space-x-reverse))}.-space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-1rem*var(--tw-space-x-reverse))}.-space-x-5>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-1.25rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-1.25rem*var(--tw-space-x-reverse))}.-space-x-6>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-1.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-1.5rem*var(--tw-space-x-reverse))}.-space-x-7>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-1.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-1.75rem*var(--tw-space-x-reverse))}.-space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(-2rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(-2rem*var(--tw-space-x-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.75rem*var(--tw-space-y-reverse));margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.5rem*var(--tw-space-y-reverse));margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)))}.divide-x>:not([hidden])~:not([hidden]){--tw-divide-x-reverse:0;border-left-width:calc(1px*(1 - var(--tw-divide-x-reverse)));border-right-width:calc(1px*var(--tw-divide-x-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(1px*var(--tw-divide-y-reverse));border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)))}.divide-gray-100>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgba(var(--gray-100),var(--tw-divide-opacity))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgba(var(--gray-200),var(--tw-divide-opacity))}.self-start{align-self:flex-start}.self-stretch{align-self:stretch}.justify-self-start{justify-self:start}.justify-self-end{justify-self:end}.justify-self-center{justify-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-x-clip{overflow-x:clip}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.break-words{overflow-wrap:break-word}.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-b-xl{border-bottom-left-radius:.75rem;border-bottom-right-radius:.75rem}.rounded-t-xl{border-top-left-radius:.75rem;border-top-right-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-x-\[0\.5px\]{border-left-width:.5px;border-right-width:.5px}.border-y{border-bottom-width:1px;border-top-width:1px}.\!border-t-0{border-top-width:0!important}.border-b{border-bottom-width:1px}.border-b-0{border-bottom-width:0}.border-e{border-inline-end-width:1px}.border-s{border-inline-start-width:1px}.border-t{border-top-width:1px}.\!border-none{border-style:none!important}.border-none{border-style:none}.border-gray-100{--tw-border-opacity:1;border-color:rgba(var(--gray-100),var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgba(var(--gray-200),var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgba(var(--gray-300),var(--tw-border-opacity))}.border-gray-600{--tw-border-opacity:1;border-color:rgba(var(--gray-600),var(--tw-border-opacity))}.border-primary-500{--tw-border-opacity:1;border-color:rgba(var(--primary-500),var(--tw-border-opacity))}.border-primary-600{--tw-border-opacity:1;border-color:rgba(var(--primary-600),var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-t-gray-200{--tw-border-opacity:1;border-top-color:rgba(var(--gray-200),var(--tw-border-opacity))}.\!bg-gray-50{--tw-bg-opacity:1!important;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))!important}.\!bg-gray-700{--tw-bg-opacity:1!important;background-color:rgba(var(--gray-700),var(--tw-bg-opacity))!important}.bg-black\/50{background-color:rgba(0,0,0,.5)}.bg-custom-100{--tw-bg-opacity:1;background-color:rgba(var(--c-100),var(--tw-bg-opacity))}.bg-custom-50{--tw-bg-opacity:1;background-color:rgba(var(--c-50),var(--tw-bg-opacity))}.bg-custom-600{--tw-bg-opacity:1;background-color:rgba(var(--c-600),var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgba(var(--gray-100),var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgba(var(--gray-200),var(--tw-bg-opacity))}.bg-gray-300{--tw-bg-opacity:1;background-color:rgba(var(--gray-300),var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgba(var(--gray-400),var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.bg-gray-950\/50{background-color:rgba(var(--gray-950),.5)}.bg-primary-500{--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity))}.bg-primary-600{--tw-bg-opacity:1;background-color:rgba(var(--primary-600),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\/0{background-color:hsla(0,0%,100%,0)}.bg-white\/5{background-color:hsla(0,0%,100%,.05)}.\!bg-none{background-image:none!important}.bg-cover{background-size:cover}.bg-center{background-position:50%}.object-cover{-o-object-fit:cover;object-fit:cover}.object-center{-o-object-position:center;object-position:center}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.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-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-bottom:.125rem;padding-top:.125rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-12{padding-bottom:3rem;padding-top:3rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-2\.5{padding-bottom:.625rem;padding-top:.625rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-3\.5{padding-bottom:.875rem;padding-top:.875rem}.py-4{padding-bottom:1rem;padding-top:1rem}.py-5{padding-bottom:1.25rem;padding-top:1.25rem}.py-6{padding-bottom:1.5rem;padding-top:1.5rem}.py-8{padding-bottom:2rem;padding-top:2rem}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pe-0{padding-inline-end:0}.pe-1{padding-inline-end:.25rem}.pe-2{padding-inline-end:.5rem}.pe-3{padding-inline-end:.75rem}.pe-4{padding-inline-end:1rem}.pe-6{padding-inline-end:1.5rem}.pe-8{padding-inline-end:2rem}.ps-0{padding-inline-start:0}.ps-1{padding-inline-start:.25rem}.ps-2{padding-inline-start:.5rem}.ps-3{padding-inline-start:.75rem}.ps-4{padding-inline-start:1rem}.ps-\[5\.25rem\]{padding-inline-start:5.25rem}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.text-justify{text-align:justify}.text-start{text-align:start}.text-end{text-align:end}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.align-bottom{vertical-align:bottom}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:var(--font-family),ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"}.font-serif{font-family:ui-serif,Georgia,Cambria,Times New Roman,Times,serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-extralight{font-weight:200}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.font-thin{font-weight:100}.capitalize{text-transform:capitalize}.italic{font-style:italic}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-loose{line-height:2}.tracking-tight{letter-spacing:-.025em}.tracking-tighter{letter-spacing:-.05em}.text-custom-400{--tw-text-opacity:1;color:rgba(var(--c-400),var(--tw-text-opacity))}.text-custom-50{--tw-text-opacity:1;color:rgba(var(--c-50),var(--tw-text-opacity))}.text-custom-500{--tw-text-opacity:1;color:rgba(var(--c-500),var(--tw-text-opacity))}.text-custom-600{--tw-text-opacity:1;color:rgba(var(--c-600),var(--tw-text-opacity))}.text-custom-700\/50{color:rgba(var(--c-700),.5)}.text-danger-600{--tw-text-opacity:1;color:rgba(var(--danger-600),var(--tw-text-opacity))}.text-gray-100{--tw-text-opacity:1;color:rgba(var(--gray-100),var(--tw-text-opacity))}.text-gray-200{--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgba(var(--gray-600),var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgba(var(--gray-700),var(--tw-text-opacity))}.text-gray-700\/50{color:rgba(var(--gray-700),.5)}.text-gray-950{--tw-text-opacity:1;color:rgba(var(--gray-950),var(--tw-text-opacity))}.text-primary-400{--tw-text-opacity:1;color:rgba(var(--primary-400),var(--tw-text-opacity))}.text-primary-500{--tw-text-opacity:1;color:rgba(var(--primary-500),var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity:1;color:rgba(var(--primary-600),var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-sm,.shadow-xl{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 rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring{--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(3px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring,.ring-0{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-0{--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(var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-1{--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)}.ring-1,.ring-2{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-2{--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)}.ring-4{--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(4px + 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)}.ring-inset{--tw-ring-inset:inset}.ring-custom-600{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--c-600),var(--tw-ring-opacity))}.ring-custom-600\/10{--tw-ring-color:rgba(var(--c-600),0.1)}.ring-custom-600\/20{--tw-ring-color:rgba(var(--c-600),0.2)}.ring-danger-600{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-600),var(--tw-ring-opacity))}.ring-gray-200{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-200),var(--tw-ring-opacity))}.ring-gray-300{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-300),var(--tw-ring-opacity))}.ring-gray-600\/10{--tw-ring-color:rgba(var(--gray-600),0.1)}.ring-gray-900\/10{--tw-ring-color:rgba(var(--gray-900),0.1)}.ring-gray-950\/10{--tw-ring-color:rgba(var(--gray-950),0.1)}.ring-gray-950\/5{--tw-ring-color:rgba(var(--gray-950),0.05)}.ring-white{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}.ring-white\/10{--tw-ring-color:hsla(0,0%,100%,.1)}.blur{--tw-blur:blur(8px)}.blur,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;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-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-opacity{transition-duration:.15s;transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1)}.delay-100{transition-delay:.1s}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-75{transition-duration:75ms}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[transform\:translateZ\(0\)\]{transform:translateZ(0)}.dark\:prose-invert:is(.dark *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.placeholder\:text-gray-400::-moz-placeholder{--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.placeholder\:text-gray-400::placeholder{--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:inset-y-0:before{bottom:0;content:var(--tw-content);top:0}.before\:start-0:before{content:var(--tw-content);inset-inline-start:0}.before\:h-full:before{content:var(--tw-content);height:100%}.before\:w-0\.5:before{content:var(--tw-content);width:.125rem}.before\:bg-primary-600:before{--tw-bg-opacity:1;background-color:rgba(var(--primary-600),var(--tw-bg-opacity));content:var(--tw-content)}.first\:border-s-0:first-child{border-inline-start-width:0}.first\:border-t-0:first-child{border-top-width:0}.last\:border-e-0:last-child{border-inline-end-width:0}.first-of-type\:ps-1:first-of-type{padding-inline-start:.25rem}.last-of-type\:pe-1:last-of-type{padding-inline-end:.25rem}.checked\:ring-0:checked{--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(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-within\:bg-gray-50:focus-within{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.hover\:bg-custom-400\/10:hover{background-color:rgba(var(--c-400),.1)}.hover\:bg-custom-50:hover{--tw-bg-opacity:1;background-color:rgba(var(--c-50),var(--tw-bg-opacity))}.hover\:bg-custom-500:hover{--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgba(var(--gray-100),var(--tw-bg-opacity))}.hover\:bg-gray-400\/10:hover{background-color:rgba(var(--gray-400),.1)}.hover\:bg-gray-50:hover{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.hover\:text-custom-600:hover{--tw-text-opacity:1;color:rgba(var(--c-600),var(--tw-text-opacity))}.hover\:text-custom-700\/75:hover{color:rgba(var(--c-700),.75)}.hover\:text-gray-500:hover{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgba(var(--gray-700),var(--tw-text-opacity))}.hover\:text-gray-700\/75:hover{color:rgba(var(--gray-700),.75)}.hover\:opacity-100:hover{opacity:1}.focus\:ring-0: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(var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-0:focus,.focus\:ring-2:focus{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)}.focus\:ring-danger-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-600),var(--tw-ring-opacity))}.focus\:ring-primary-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-600),var(--tw-ring-opacity))}.focus\:ring-offset-0:focus{--tw-ring-offset-width:0px}.checked\:focus\:ring-danger-500\/50:focus:checked{--tw-ring-color:rgba(var(--danger-500),0.5)}.checked\:focus\:ring-primary-500\/50:focus:checked{--tw-ring-color:rgba(var(--primary-500),0.5)}.focus-visible\:z-10:focus-visible{z-index:10}.focus-visible\:border-primary-500:focus-visible{--tw-border-opacity:1;border-color:rgba(var(--primary-500),var(--tw-border-opacity))}.focus-visible\:bg-custom-50:focus-visible{--tw-bg-opacity:1;background-color:rgba(var(--c-50),var(--tw-bg-opacity))}.focus-visible\:bg-gray-100:focus-visible{--tw-bg-opacity:1;background-color:rgba(var(--gray-100),var(--tw-bg-opacity))}.focus-visible\:bg-gray-50:focus-visible{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.focus-visible\:text-custom-700\/75:focus-visible{color:rgba(var(--c-700),.75)}.focus-visible\:text-gray-500:focus-visible{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.focus-visible\:text-gray-700\/75:focus-visible{color:rgba(var(--gray-700),.75)}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--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-visible\:ring-2:focus-visible{--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-visible\:ring-inset:focus-visible{--tw-ring-inset:inset}.focus-visible\:ring-custom-500\/50:focus-visible{--tw-ring-color:rgba(var(--c-500),0.5)}.focus-visible\:ring-custom-600:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--c-600),var(--tw-ring-opacity))}.focus-visible\:ring-gray-400\/40:focus-visible{--tw-ring-color:rgba(var(--gray-400),0.4)}.focus-visible\:ring-primary-500:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-500),var(--tw-ring-opacity))}.focus-visible\:ring-primary-600:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-600),var(--tw-ring-opacity))}.enabled\:cursor-wait:enabled{cursor:wait}.enabled\:opacity-70:enabled{opacity:.7}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:bg-gray-50:disabled{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.disabled\:text-gray-50:disabled{--tw-text-opacity:1;color:rgba(var(--gray-50),var(--tw-text-opacity))}.disabled\:text-gray-500:disabled{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.disabled\:opacity-70:disabled{opacity:.7}.disabled\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled{-webkit-text-fill-color:rgba(var(--gray-500),1)}.disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled::-moz-placeholder{-webkit-text-fill-color:rgba(var(--gray-400),1)}.disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled::placeholder{-webkit-text-fill-color:rgba(var(--gray-400),1)}.disabled\:checked\:bg-current:checked:disabled{background-color:currentColor}.disabled\:checked\:text-gray-400:checked:disabled{--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.group\/item:first-child .group-first\/item\:rounded-s-lg{border-end-start-radius:.5rem;border-start-start-radius:.5rem}.group\/item:last-child .group-last\/item\:rounded-e-lg{border-end-end-radius:.5rem;border-start-end-radius:.5rem}.group:hover .group-hover\:text-gray-500,.group\/button:hover .group-hover\/button\:text-gray-500{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.group:hover .group-hover\:text-gray-700{--tw-text-opacity:1;color:rgba(var(--gray-700),var(--tw-text-opacity))}.group\/item:hover .group-hover\/item\:underline,.group\/link:hover .group-hover\/link\:underline{text-decoration-line:underline}.group:focus-visible .group-focus-visible\:text-gray-500{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.group:focus-visible .group-focus-visible\:text-gray-700{--tw-text-opacity:1;color:rgba(var(--gray-700),var(--tw-text-opacity))}.group\/item:focus-visible .group-focus-visible\/item\:underline{text-decoration-line:underline}.group\/link:focus-visible .group-focus-visible\/link\:underline{text-decoration-line:underline}.dark\:flex:is(.dark *){display:flex}.dark\:hidden:is(.dark *){display:none}.dark\:divide-white\/10:is(.dark *)>:not([hidden])~:not([hidden]){border-color:hsla(0,0%,100%,.1)}.dark\:divide-white\/5:is(.dark *)>:not([hidden])~:not([hidden]){border-color:hsla(0,0%,100%,.05)}.dark\:border-gray-600:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--gray-600),var(--tw-border-opacity))}.dark\:border-gray-700:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--gray-700),var(--tw-border-opacity))}.dark\:border-primary-500:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--primary-500),var(--tw-border-opacity))}.dark\:border-white\/10:is(.dark *){border-color:hsla(0,0%,100%,.1)}.dark\:border-white\/5:is(.dark *){border-color:hsla(0,0%,100%,.05)}.dark\:border-t-white\/10:is(.dark *){border-top-color:hsla(0,0%,100%,.1)}.dark\:\!bg-gray-700:is(.dark *){--tw-bg-opacity:1!important;background-color:rgba(var(--gray-700),var(--tw-bg-opacity))!important}.dark\:bg-custom-400\/10:is(.dark *){background-color:rgba(var(--c-400),.1)}.dark\:bg-custom-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}.dark\:bg-custom-500\/20:is(.dark *){background-color:rgba(var(--c-500),.2)}.dark\:bg-gray-400\/10:is(.dark *){background-color:rgba(var(--gray-400),.1)}.dark\:bg-gray-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-500),var(--tw-bg-opacity))}.dark\:bg-gray-500\/20:is(.dark *){background-color:rgba(var(--gray-500),.2)}.dark\:bg-gray-600:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-600),var(--tw-bg-opacity))}.dark\:bg-gray-700:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-700),var(--tw-bg-opacity))}.dark\:bg-gray-800:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-800),var(--tw-bg-opacity))}.dark\:bg-gray-900:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-900),var(--tw-bg-opacity))}.dark\:bg-gray-900\/30:is(.dark *){background-color:rgba(var(--gray-900),.3)}.dark\:bg-gray-950:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-950),var(--tw-bg-opacity))}.dark\:bg-gray-950\/75:is(.dark *){background-color:rgba(var(--gray-950),.75)}.dark\:bg-primary-400:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--primary-400),var(--tw-bg-opacity))}.dark\:bg-primary-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity))}.dark\:bg-transparent:is(.dark *){background-color:transparent}.dark\:bg-white\/10:is(.dark *){background-color:hsla(0,0%,100%,.1)}.dark\:bg-white\/5:is(.dark *){background-color:hsla(0,0%,100%,.05)}.dark\:fill-current:is(.dark *){fill:currentColor}.dark\:text-custom-300\/50:is(.dark *){color:rgba(var(--c-300),.5)}.dark\:text-custom-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--c-400),var(--tw-text-opacity))}.dark\:text-custom-400\/10:is(.dark *){color:rgba(var(--c-400),.1)}.dark\:text-danger-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--danger-400),var(--tw-text-opacity))}.dark\:text-danger-500:is(.dark *){--tw-text-opacity:1;color:rgba(var(--danger-500),var(--tw-text-opacity))}.dark\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.dark\:text-gray-300\/50:is(.dark *){color:rgba(var(--gray-300),.5)}.dark\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.dark\:text-gray-500:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.dark\:text-gray-700:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-700),var(--tw-text-opacity))}.dark\:text-gray-800:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-800),var(--tw-text-opacity))}.dark\:text-primary-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--primary-400),var(--tw-text-opacity))}.dark\:text-primary-500:is(.dark *){--tw-text-opacity:1;color:rgba(var(--primary-500),var(--tw-text-opacity))}.dark\:text-white:is(.dark *){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.dark\:text-white\/5:is(.dark *){color:hsla(0,0%,100%,.05)}.dark\:ring-custom-400\/30:is(.dark *){--tw-ring-color:rgba(var(--c-400),0.3)}.dark\:ring-custom-500:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--c-500),var(--tw-ring-opacity))}.dark\:ring-danger-500:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-500),var(--tw-ring-opacity))}.dark\:ring-gray-400\/20:is(.dark *){--tw-ring-color:rgba(var(--gray-400),0.2)}.dark\:ring-gray-50\/10:is(.dark *){--tw-ring-color:rgba(var(--gray-50),0.1)}.dark\:ring-gray-700:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-700),var(--tw-ring-opacity))}.dark\:ring-gray-900:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--gray-900),var(--tw-ring-opacity))}.dark\:ring-white\/10:is(.dark *){--tw-ring-color:hsla(0,0%,100%,.1)}.dark\:ring-white\/20:is(.dark *){--tw-ring-color:hsla(0,0%,100%,.2)}.dark\:placeholder\:text-gray-500:is(.dark *)::-moz-placeholder{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.dark\:placeholder\:text-gray-500:is(.dark *)::placeholder{--tw-text-opacity:1;color:rgba(var(--gray-500),var(--tw-text-opacity))}.dark\:before\:bg-primary-500:is(.dark *):before{--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity));content:var(--tw-content)}.dark\:checked\:bg-danger-500:checked:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--danger-500),var(--tw-bg-opacity))}.dark\:checked\:bg-primary-500:checked:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity))}.dark\:focus-within\:bg-white\/5:focus-within:is(.dark *){background-color:hsla(0,0%,100%,.05)}.dark\:hover\:bg-custom-400:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-400),var(--tw-bg-opacity))}.dark\:hover\:bg-custom-400\/10:hover:is(.dark *){background-color:rgba(var(--c-400),.1)}.dark\:hover\:bg-white\/10:hover:is(.dark *){background-color:hsla(0,0%,100%,.1)}.dark\:hover\:bg-white\/5:hover:is(.dark *){background-color:hsla(0,0%,100%,.05)}.dark\:hover\:text-custom-300:hover:is(.dark *){--tw-text-opacity:1;color:rgba(var(--c-300),var(--tw-text-opacity))}.dark\:hover\:text-custom-300\/75:hover:is(.dark *){color:rgba(var(--c-300),.75)}.dark\:hover\:text-gray-200:hover:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.dark\:hover\:text-gray-300\/75:hover:is(.dark *){color:rgba(var(--gray-300),.75)}.dark\:hover\:text-gray-400:hover:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.dark\:hover\:ring-white\/20:hover:is(.dark *){--tw-ring-color:hsla(0,0%,100%,.2)}.dark\:focus\:ring-danger-500:focus:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-500),var(--tw-ring-opacity))}.dark\:focus\:ring-primary-500:focus:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-500),var(--tw-ring-opacity))}.dark\:checked\:focus\:ring-danger-400\/50:focus:checked:is(.dark *){--tw-ring-color:rgba(var(--danger-400),0.5)}.dark\:checked\:focus\:ring-primary-400\/50:focus:checked:is(.dark *){--tw-ring-color:rgba(var(--primary-400),0.5)}.dark\:focus-visible\:border-primary-500:focus-visible:is(.dark *){--tw-border-opacity:1;border-color:rgba(var(--primary-500),var(--tw-border-opacity))}.dark\:focus-visible\:bg-custom-400\/10:focus-visible:is(.dark *){background-color:rgba(var(--c-400),.1)}.dark\:focus-visible\:bg-white\/5:focus-visible:is(.dark *){background-color:hsla(0,0%,100%,.05)}.dark\:focus-visible\:text-custom-300\/75:focus-visible:is(.dark *){color:rgba(var(--c-300),.75)}.dark\:focus-visible\:text-gray-300\/75:focus-visible:is(.dark *){color:rgba(var(--gray-300),.75)}.dark\:focus-visible\:text-gray-400:focus-visible:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.dark\:focus-visible\:ring-custom-400\/50:focus-visible:is(.dark *){--tw-ring-color:rgba(var(--c-400),0.5)}.dark\:focus-visible\:ring-custom-500:focus-visible:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--c-500),var(--tw-ring-opacity))}.dark\:focus-visible\:ring-primary-500:focus-visible:is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-500),var(--tw-ring-opacity))}.dark\:disabled\:bg-transparent:disabled:is(.dark *){background-color:transparent}.dark\:disabled\:text-gray-400:disabled:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.dark\:disabled\:ring-white\/10:disabled:is(.dark *){--tw-ring-color:hsla(0,0%,100%,.1)}.dark\:disabled\:\[-webkit-text-fill-color\:theme\(colors\.gray\.400\)\]:disabled:is(.dark *){-webkit-text-fill-color:rgba(var(--gray-400),1)}.dark\:disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled:is(.dark *)::-moz-placeholder{-webkit-text-fill-color:rgba(var(--gray-500),1)}.dark\:disabled\:placeholder\:\[-webkit-text-fill-color\:theme\(colors\.gray\.500\)\]:disabled:is(.dark *)::placeholder{-webkit-text-fill-color:rgba(var(--gray-500),1)}.dark\:disabled\:checked\:bg-gray-600:checked:disabled:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-600),var(--tw-bg-opacity))}.group\/button:hover .dark\:group-hover\/button\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.group:hover .dark\:group-hover\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.group:hover .dark\:group-hover\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}.group:focus-visible .dark\:group-focus-visible\:text-gray-200:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-200),var(--tw-text-opacity))}.group:focus-visible .dark\:group-focus-visible\:text-gray-400:is(.dark *){--tw-text-opacity:1;color:rgba(var(--gray-400),var(--tw-text-opacity))}@media (min-width:640px){.sm\:relative{position:relative}.sm\:inset-x-auto{left:auto;right:auto}.sm\:end-0{inset-inline-end:0}.sm\:col-\[--col-span-sm\]{grid-column:var(--col-span-sm)}.sm\:col-span-2{grid-column:span 2/span 2}.sm\:col-start-\[--col-start-sm\]{grid-column-start:var(--col-start-sm)}.sm\:-mx-6{margin-left:-1.5rem;margin-right:-1.5rem}.sm\:-my-2{margin-bottom:-.5rem;margin-top:-.5rem}.sm\:ms-auto{margin-inline-start:auto}.sm\:mt-7{margin-top:1.75rem}.sm\:block{display:block}.sm\:flex{display:flex}.sm\:table-cell{display:table-cell}.sm\:grid{display:grid}.sm\:inline-grid{display:inline-grid}.sm\:hidden{display:none}.sm\:w-\[calc\(100\%\+3rem\)\]{width:calc(100% + 3rem)}.sm\:w-screen{width:100vw}.sm\:max-w-2xl{max-width:42rem}.sm\:max-w-3xl{max-width:48rem}.sm\:max-w-4xl{max-width:56rem}.sm\:max-w-5xl{max-width:64rem}.sm\:max-w-6xl{max-width:72rem}.sm\:max-w-7xl{max-width:80rem}.sm\:max-w-lg{max-width:32rem}.sm\:max-w-md{max-width:28rem}.sm\:max-w-sm{max-width:24rem}.sm\:max-w-xl{max-width:36rem}.sm\:max-w-xs{max-width:20rem}.sm\:columns-\[--cols-sm\]{-moz-columns:var(--cols-sm);columns:var(--cols-sm)}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-\[--cols-sm\]{grid-template-columns:var(--cols-sm)}.sm\:grid-cols-\[repeat\(auto-fit\2c minmax\(0\2c 1fr\)\)\]{grid-template-columns:repeat(auto-fit,minmax(0,1fr))}.sm\:grid-rows-\[1fr_auto_3fr\]{grid-template-rows:1fr auto 3fr}.sm\:flex-row{flex-direction:row}.sm\:flex-nowrap{flex-wrap:nowrap}.sm\:items-start{align-items:flex-start}.sm\:items-end{align-items:flex-end}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:gap-1{gap:.25rem}.sm\:gap-3{gap:.75rem}.sm\:gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.sm\:rounded-xl{border-radius:.75rem}.sm\:p-10{padding:2.5rem}.sm\:px-12{padding-left:3rem;padding-right:3rem}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.sm\:pe-3{padding-inline-end:.75rem}.sm\:pe-6{padding-inline-end:1.5rem}.sm\:ps-3{padding-inline-start:.75rem}.sm\:ps-6{padding-inline-start:1.5rem}.sm\:pt-1\.5{padding-top:.375rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}.sm\:leading-6{line-height:1.5rem}.sm\:first-of-type\:ps-3:first-of-type{padding-inline-start:.75rem}.sm\:first-of-type\:ps-6:first-of-type{padding-inline-start:1.5rem}.sm\:last-of-type\:pe-3:last-of-type{padding-inline-end:.75rem}.sm\:last-of-type\:pe-6:last-of-type{padding-inline-end:1.5rem}}@media (min-width:768px){.md\:bottom-4{bottom:1rem}.md\:order-first{order:-9999}.md\:col-\[--col-span-md\]{grid-column:var(--col-span-md)}.md\:col-span-2{grid-column:span 2/span 2}.md\:col-start-\[--col-start-md\]{grid-column-start:var(--col-start-md)}.md\:block{display:block}.md\:flex{display:flex}.md\:table-cell{display:table-cell}.md\:inline-grid{display:inline-grid}.md\:hidden{display:none}.md\:w-max{width:-moz-max-content;width:max-content}.md\:max-w-60{max-width:15rem}.md\:columns-\[--cols-md\]{-moz-columns:var(--cols-md);columns:var(--cols-md)}.md\:grid-flow-col{grid-auto-flow:column}.md\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-\[--cols-md\]{grid-template-columns:var(--cols-md)}.md\:flex-row{flex-direction:row}.md\:items-start{align-items:flex-start}.md\:items-end{align-items:flex-end}.md\:items-center{align-items:center}.md\:justify-end{justify-content:flex-end}.md\:gap-1{gap:.25rem}.md\:gap-3{gap:.75rem}.md\:divide-y-0>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-bottom-width:calc(0px*var(--tw-divide-y-reverse));border-top-width:calc(0px*(1 - var(--tw-divide-y-reverse)))}.md\:overflow-x-auto{overflow-x:auto}.md\:rounded-xl{border-radius:.75rem}.md\:p-20{padding:5rem}.md\:px-6{padding-left:1.5rem;padding-right:1.5rem}.md\:pe-6{padding-inline-end:1.5rem}.md\:ps-3{padding-inline-start:.75rem}}@media (min-width:1024px){.lg\:sticky{position:sticky}.lg\:z-0{z-index:0}.lg\:col-\[--col-span-lg\]{grid-column:var(--col-span-lg)}.lg\:col-start-\[--col-start-lg\]{grid-column-start:var(--col-start-lg)}.lg\:block{display:block}.lg\:flex{display:flex}.lg\:table-cell{display:table-cell}.lg\:inline-grid{display:inline-grid}.lg\:hidden{display:none}.lg\:h-full{height:100%}.lg\:max-w-xs{max-width:20rem}.lg\:-translate-x-full{--tw-translate-x:-100%}.lg\:-translate-x-full,.lg\:translate-x-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.lg\:translate-x-0{--tw-translate-x:0px}.lg\:columns-\[--cols-lg\]{-moz-columns:var(--cols-lg);columns:var(--cols-lg)}.lg\:grid-cols-\[--cols-lg\]{grid-template-columns:var(--cols-lg)}.lg\:flex-row{flex-direction:row}.lg\:items-start{align-items:flex-start}.lg\:items-end{align-items:flex-end}.lg\:items-center{align-items:center}.lg\:gap-1{gap:.25rem}.lg\:gap-3{gap:.75rem}.lg\:bg-transparent{background-color:transparent}.lg\:px-8{padding-left:2rem;padding-right:2rem}.lg\:pe-8{padding-inline-end:2rem}.lg\:shadow-none{--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000}.lg\:shadow-none,.lg\:shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.lg\:shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.lg\:ring-0{--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(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)}.lg\:transition{transition-duration:.15s;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)}.lg\:transition-none{transition-property:none}.lg\:delay-100{transition-delay:.1s}.dark\:lg\:bg-transparent:is(.dark *){background-color:transparent}}@media (min-width:1280px){.xl\:col-\[--col-span-xl\]{grid-column:var(--col-span-xl)}.xl\:col-start-\[--col-start-xl\]{grid-column-start:var(--col-start-xl)}.xl\:block{display:block}.xl\:table-cell{display:table-cell}.xl\:inline-grid{display:inline-grid}.xl\:hidden{display:none}.xl\:columns-\[--cols-xl\]{-moz-columns:var(--cols-xl);columns:var(--cols-xl)}.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:grid-cols-\[--cols-xl\]{grid-template-columns:var(--cols-xl)}.xl\:flex-row{flex-direction:row}.xl\:items-start{align-items:flex-start}.xl\:items-end{align-items:flex-end}.xl\:items-center{align-items:center}.xl\:gap-1{gap:.25rem}.xl\:gap-3{gap:.75rem}}@media (min-width:1536px){.\32xl\:col-\[--col-span-2xl\]{grid-column:var(--col-span-2xl)}.\32xl\:col-start-\[--col-start-2xl\]{grid-column-start:var(--col-start-2xl)}.\32xl\:block{display:block}.\32xl\:table-cell{display:table-cell}.\32xl\:inline-grid{display:inline-grid}.\32xl\:hidden{display:none}.\32xl\:columns-\[--cols-2xl\]{-moz-columns:var(--cols-2xl);columns:var(--cols-2xl)}.\32xl\:grid-cols-\[--cols-2xl\]{grid-template-columns:var(--cols-2xl)}.\32xl\:flex-row{flex-direction:row}.\32xl\:items-start{align-items:flex-start}.\32xl\:items-end{align-items:flex-end}.\32xl\:items-center{align-items:center}.\32xl\:gap-1{gap:.25rem}.\32xl\:gap-3{gap:.75rem}}.ltr\:hidden:where([dir=ltr],[dir=ltr] *){display:none}.rtl\:hidden:where([dir=rtl],[dir=rtl] *){display:none}.rtl\:-translate-x-0:where([dir=rtl],[dir=rtl] *){--tw-translate-x:-0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:-translate-x-5:where([dir=rtl],[dir=rtl] *){--tw-translate-x:-1.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:-translate-x-full:where([dir=rtl],[dir=rtl] *){--tw-translate-x:-100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:translate-x-1\/2:where([dir=rtl],[dir=rtl] *){--tw-translate-x:50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:translate-x-1\/4:where([dir=rtl],[dir=rtl] *){--tw-translate-x:25%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:translate-x-full:where([dir=rtl],[dir=rtl] *){--tw-translate-x:100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:rotate-180:where([dir=rtl],[dir=rtl] *){--tw-rotate:180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:flex-row-reverse:where([dir=rtl],[dir=rtl] *){flex-direction:row-reverse}.rtl\:divide-x-reverse:where([dir=rtl],[dir=rtl] *)>:not([hidden])~:not([hidden]){--tw-divide-x-reverse:1}@media (min-width:1024px){.rtl\:lg\:-translate-x-0:where([dir=rtl],[dir=rtl] *){--tw-translate-x:-0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rtl\:lg\:translate-x-full:where([dir=rtl],[dir=rtl] *){--tw-translate-x:100%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}}.\[\&\.trix-active\]\:bg-gray-50.trix-active{--tw-bg-opacity:1;background-color:rgba(var(--gray-50),var(--tw-bg-opacity))}.\[\&\.trix-active\]\:text-primary-600.trix-active{--tw-text-opacity:1;color:rgba(var(--primary-600),var(--tw-text-opacity))}.dark\:\[\&\.trix-active\]\:bg-white\/5.trix-active:is(.dark *){background-color:hsla(0,0%,100%,.05)}.dark\:\[\&\.trix-active\]\:text-primary-400.trix-active:is(.dark *){--tw-text-opacity:1;color:rgba(var(--primary-400),var(--tw-text-opacity))}.\[\&\:\:-ms-reveal\]\:hidden::-ms-reveal{display:none}.\[\&\:not\(\:first-of-type\)\]\:border-s:not(:first-of-type){border-inline-start-width:1px}.\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-2:focus-within:not(:has(.fi-ac-action: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)}.\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-danger-600:focus-within:not(:has(.fi-ac-action:focus)){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-600),var(--tw-ring-opacity))}.\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-primary-600:focus-within:not(:has(.fi-ac-action:focus)){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-600),var(--tw-ring-opacity))}.dark\:\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-danger-500:focus-within:not(:has(.fi-ac-action:focus)):is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--danger-500),var(--tw-ring-opacity))}.dark\:\[\&\:not\(\:has\(\.fi-ac-action\:focus\)\)\]\:focus-within\:ring-primary-500:focus-within:not(:has(.fi-ac-action:focus)):is(.dark *){--tw-ring-opacity:1;--tw-ring-color:rgba(var(--primary-500),var(--tw-ring-opacity))}.\[\&\:not\(\:last-of-type\)\]\:border-e:not(:last-of-type){border-inline-end-width:1px}.\[\&\:not\(\:nth-child\(1_of_\.fi-btn\)\)\]\:shadow-\[-1px_0_0_0_theme\(colors\.gray\.200\)\]:not(:nth-child(1 of .fi-btn)){--tw-shadow:-1px 0 0 0 rgba(var(--gray-200),1);--tw-shadow-colored:-1px 0 0 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)}.dark\:\[\&\:not\(\:nth-child\(1_of_\.fi-btn\)\)\]\:shadow-\[-1px_0_0_0_theme\(colors\.white\/20\%\)\]:not(:nth-child(1 of .fi-btn)):is(.dark *){--tw-shadow:-1px 0 0 0 hsla(0,0%,100%,.2);--tw-shadow-colored:-1px 0 0 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)}.\[\&\:not\(\:nth-last-child\(1_of_\.fi-btn\)\)\]\:me-px:not(:nth-last-child(1 of .fi-btn)){margin-inline-end:1px}.\[\&\:nth-child\(1_of_\.fi-btn\)\]\:rounded-s-lg:nth-child(1 of .fi-btn){border-end-start-radius:.5rem;border-start-start-radius:.5rem}.\[\&\:nth-last-child\(1_of_\.fi-btn\)\]\:rounded-e-lg:nth-last-child(1 of .fi-btn){border-end-end-radius:.5rem;border-start-end-radius:.5rem}.\[\&\>\*\:first-child\]\:relative>:first-child{position:relative}.\[\&\>\*\:first-child\]\:mt-0>:first-child{margin-top:0}.\[\&\>\*\:first-child\]\:before\:absolute>:first-child:before{content:var(--tw-content);position:absolute}.\[\&\>\*\:first-child\]\:before\:inset-y-0>:first-child:before{bottom:0;content:var(--tw-content);top:0}.\[\&\>\*\:first-child\]\:before\:start-0>:first-child:before{content:var(--tw-content);inset-inline-start:0}.\[\&\>\*\:first-child\]\:before\:w-0\.5>:first-child:before{content:var(--tw-content);width:.125rem}.\[\&\>\*\:first-child\]\:before\:bg-primary-600>:first-child:before{--tw-bg-opacity:1;background-color:rgba(var(--primary-600),var(--tw-bg-opacity));content:var(--tw-content)}.\[\&\>\*\:first-child\]\:dark\:before\:bg-primary-500:is(.dark *)>:first-child:before{--tw-bg-opacity:1;background-color:rgba(var(--primary-500),var(--tw-bg-opacity));content:var(--tw-content)}.\[\&\>\*\:last-child\]\:mb-0>:last-child{margin-bottom:0}.\[\&_\.choices\\_\\_inner\]\:ps-0 .choices__inner{padding-inline-start:0}.\[\&_\.fi-badge-delete-button\]\:hidden .fi-badge-delete-button{display:none}.\[\&_\.filepond--root\]\:font-sans .filepond--root{font-family:var(--font-family),ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"}.\[\&_optgroup\]\:bg-white optgroup{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.\[\&_optgroup\]\:dark\:bg-gray-900:is(.dark *) optgroup{--tw-bg-opacity:1;background-color:rgba(var(--gray-900),var(--tw-bg-opacity))}.\[\&_option\]\:bg-white option{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.\[\&_option\]\:dark\:bg-gray-900:is(.dark *) option{--tw-bg-opacity:1;background-color:rgba(var(--gray-900),var(--tw-bg-opacity))}:checked+*>.\[\:checked\+\*\>\&\]\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}@media(hover:hover){.\[\@media\(hover\:hover\)\]\:transition{transition-duration:.15s;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)}.\[\@media\(hover\:hover\)\]\:duration-75{transition-duration:75ms}}input:checked+.\[input\:checked\+\&\]\:bg-custom-600{--tw-bg-opacity:1;background-color:rgba(var(--c-600),var(--tw-bg-opacity))}input:checked+.\[input\:checked\+\&\]\:bg-gray-400{--tw-bg-opacity:1;background-color:rgba(var(--gray-400),var(--tw-bg-opacity))}input:checked+.\[input\:checked\+\&\]\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}input:checked+.\[input\:checked\+\&\]\:ring-0{--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(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)}input:checked+.\[input\:checked\+\&\]\:hover\:bg-custom-500:hover{--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}input:checked+.\[input\:checked\+\&\]\:hover\:bg-gray-300:hover{--tw-bg-opacity:1;background-color:rgba(var(--gray-300),var(--tw-bg-opacity))}input:checked+.dark\:\[input\:checked\+\&\]\:bg-custom-500:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-500),var(--tw-bg-opacity))}input:checked+.dark\:\[input\:checked\+\&\]\:bg-gray-600:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-600),var(--tw-bg-opacity))}input:checked+.dark\:\[input\:checked\+\&\]\:hover\:bg-custom-400:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--c-400),var(--tw-bg-opacity))}input:checked+.dark\:\[input\:checked\+\&\]\:hover\:bg-gray-500:hover:is(.dark *){--tw-bg-opacity:1;background-color:rgba(var(--gray-500),var(--tw-bg-opacity))}input:checked:focus-visible+.\[input\:checked\:focus-visible\+\&\]\:ring-custom-500\/50{--tw-ring-color:rgba(var(--c-500),0.5)}input:checked:focus-visible+.dark\:\[input\:checked\:focus-visible\+\&\]\:ring-custom-400\/50:is(.dark *){--tw-ring-color:rgba(var(--c-400),0.5)}input:focus-visible+.\[input\:focus-visible\+\&\]\:z-10{z-index:10}input:focus-visible+.\[input\:focus-visible\+\&\]\:ring-2{--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)}input:focus-visible+.\[input\:focus-visible\+\&\]\:ring-gray-950\/10{--tw-ring-color:rgba(var(--gray-950),0.1)}input:focus-visible+.dark\:\[input\:focus-visible\+\&\]\:ring-white\/20:is(.dark *){--tw-ring-color:hsla(0,0%,100%,.2)} diff --git a/public/js/filament/forms/components/file-upload.js b/public/js/filament/forms/components/file-upload.js index 41e11c8d0e..11526446c0 100644 --- a/public/js/filament/forms/components/file-upload.js +++ b/public/js/filament/forms/components/file-upload.js @@ -25,7 +25,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho ${w.replace(/ /g," ")} `}let x=t.aspectRatio||b/y,_=y,P=_*x,O=typeof t.scaleToFit>"u"||t.scaleToFit,M=t.center?t.center.x:.5,C=t.center?t.center.y:.5,S=Tl({width:y,height:b},Il({width:_,height:P},x),t.rotation,O?{x:M,y:C}:{x:.5,y:.5}),F=t.zoom*S,R=t.rotation*(180/Math.PI),L={x:_*.5,y:P*.5},z={x:L.x-y*M,y:L.y-b*C},D=[`rotate(${R} ${L.x} ${L.y})`,`translate(${L.x} ${L.y})`,`scale(${F})`,`translate(${-L.x} ${-L.y})`,`translate(${z.x} ${z.y})`],k=t.flip&&t.flip.horizontal,B=t.flip&&t.flip.vertical,X=[`scale(${k?-1:1} ${B?-1:1})`,`translate(${k?-y:0} ${B?-b:0})`],q=` -0&&arguments[0]!==void 0?arguments[0]:"",e=et.parse(t,{referenceElement:this.element}).getDocument();return this.loadDocument(e)}loadJSON(t){let{document:e,selectedRange:i}=t;return e=k.fromJSON(e),this.loadSnapshot({document:e,selectedRange:i})}loadSnapshot(t){return this.undoManager=new Et(this.composition),this.composition.loadSnapshot(t)}getDocument(){return this.composition.document}getSelectedDocument(){return this.composition.getSelectedDocument()}getSnapshot(){return this.composition.getSnapshot()}toJSON(){return this.getSnapshot()}deleteInDirection(t){return this.composition.deleteInDirection(t)}insertAttachment(t){return this.composition.insertAttachment(t)}insertAttachments(t){return this.composition.insertAttachments(t)}insertDocument(t){return this.composition.insertDocument(t)}insertFile(t){return this.composition.insertFile(t)}insertFiles(t){return this.composition.insertFiles(t)}insertHTML(t){return this.composition.insertHTML(t)}insertString(t){return this.composition.insertString(t)}insertText(t){return this.composition.insertText(t)}insertLineBreak(){return this.composition.insertLineBreak()}getSelectedRange(){return this.composition.getSelectedRange()}getPosition(){return this.composition.getPosition()}getClientRectAtPosition(t){let e=this.getDocument().locationRangeFromRange([t,t+1]);return this.selectionManager.getClientRectAtLocationRange(e)}expandSelectionInDirection(t){return this.composition.expandSelectionInDirection(t)}moveCursorInDirection(t){return this.composition.moveCursorInDirection(t)}setSelectedRange(t){return this.composition.setSelectedRange(t)}activateAttribute(t){let e=!(arguments.length>1&&arguments[1]!==void 0)||arguments[1];return this.composition.setCurrentAttribute(t,e)}attributeIsActive(t){return this.composition.hasCurrentAttribute(t)}canActivateAttribute(t){return this.composition.canSetCurrentAttribute(t)}deactivateAttribute(t){return this.composition.removeCurrentAttribute(t)}setHTMLAtributeAtPosition(t,e,i){this.composition.setHTMLAtributeAtPosition(t,e,i)}canDecreaseNestingLevel(){return this.composition.canDecreaseNestingLevel()}canIncreaseNestingLevel(){return this.composition.canIncreaseNestingLevel()}decreaseNestingLevel(){if(this.canDecreaseNestingLevel())return this.composition.decreaseNestingLevel()}increaseNestingLevel(){if(this.canIncreaseNestingLevel())return this.composition.increaseNestingLevel()}canRedo(){return this.undoManager.canRedo()}canUndo(){return this.undoManager.canUndo()}recordUndoEntry(t){let{context:e,consolidatable:i}=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return this.undoManager.recordUndoEntry(t,{context:e,consolidatable:i})}redo(){if(this.canRedo())return this.undoManager.redo()}undo(){if(this.canUndo())return this.undoManager.undo()}},zt=class{constructor(t){this.element=t}findLocationFromContainerAndOffset(t,e){let{strict:i}=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{strict:!0},r=0,o=!1,s={index:0,offset:0},a=this.findAttachmentElementParentForNode(t);a&&(t=a.parentNode,e=ae(a));let l=Ft(this.element,{usingFilter:Fi});for(;l.nextNode();){let c=l.currentNode;if(c===t&&xt(t)){st(c)||(s.offset+=e);break}if(c.parentNode===t){if(r++===e)break}else if(!J(t,c)&&r>0)break;$e(c,{strict:i})?(o&&s.index++,s.offset=0,o=!0):s.offset+=ve(c)}return s}findContainerAndOffsetFromLocation(t){let e,i;if(t.index===0&&t.offset===0){for(e=this.element,i=0;e.firstChild;)if(e=e.firstChild,le(e)){i=1;break}return[e,i]}let[r,o]=this.findNodeAndOffsetFromLocation(t);if(r){if(xt(r))ve(r)===0?(e=r.parentNode.parentNode,i=ae(r.parentNode),st(r,{name:"right"})&&i++):(e=r,i=t.offset-o);else{if(e=r.parentNode,!$e(r.previousSibling)&&!le(e))for(;r===e.lastChild&&(r=e,e=e.parentNode,!le(e)););i=ae(r),t.offset!==0&&i++}return[e,i]}}findNodeAndOffsetFromLocation(t){let e,i,r=0;for(let o of this.getSignificantNodesForIndex(t.index)){let s=ve(o);if(t.offset<=r+s)if(xt(o)){if(e=o,i=r,t.offset===i&&st(e))break}else e||(e=o,i=r);if(r+=s,r>t.offset)break}return[e,i]}findAttachmentElementParentForNode(t){for(;t&&t!==this.element;){if($(t))return t;t=t.parentNode}}getSignificantNodesForIndex(t){let e=[],i=Ft(this.element,{usingFilter:Fn}),r=!1;for(;i.nextNode();){let s=i.currentNode;var o;if(ot(s)){if(o!=null?o++:o=0,o===t)r=!0;else if(r)break}else r&&e.push(s)}return e}},ve=function(n){return n.nodeType===Node.TEXT_NODE?st(n)?0:n.textContent.length:x(n)==="br"||$(n)?1:0},Fn=function(n){return Pn(n)===NodeFilter.FILTER_ACCEPT?Fi(n):NodeFilter.FILTER_REJECT},Pn=function(n){return yi(n)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},Fi=function(n){return $(n.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},_t=class{createDOMRangeFromPoint(t){let e,{x:i,y:r}=t;if(document.caretPositionFromPoint){let{offsetNode:o,offset:s}=document.caretPositionFromPoint(i,r);return e=document.createRange(),e.setStart(o,s),e}if(document.caretRangeFromPoint)return document.caretRangeFromPoint(i,r);if(document.body.createTextRange){let o=yt();try{let s=document.body.createTextRange();s.moveToPoint(i,r),s.select()}catch{}return e=yt(),Di(o),e}}getClientRectsForDOMRange(t){let e=Array.from(t.getClientRects());return[e[0],e[e.length-1]]}},I=class extends f{constructor(t){super(...arguments),this.didMouseDown=this.didMouseDown.bind(this),this.selectionDidChange=this.selectionDidChange.bind(this),this.element=t,this.locationMapper=new zt(this.element),this.pointMapper=new _t,this.lockCount=0,p("mousedown",{onElement:this.element,withCallback:this.didMouseDown})}getLocationRange(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};return t.strict===!1?this.createLocationRangeFromDOMRange(yt()):t.ignoreLock?this.currentLocationRange:this.lockedLocationRange?this.lockedLocationRange:this.currentLocationRange}setLocationRange(t){if(this.lockedLocationRange)return;t=g(t);let e=this.createDOMRangeFromLocationRange(t);e&&(Di(e),this.updateCurrentLocationRange(t))}setLocationRangeFromPointRange(t){t=g(t);let e=this.getLocationAtPoint(t[0]),i=this.getLocationAtPoint(t[1]);this.setLocationRange([e,i])}getClientRectAtLocationRange(t){let e=this.createDOMRangeFromLocationRange(t);if(e)return this.getClientRectsForDOMRange(e)[1]}locationIsCursorTarget(t){let e=Array.from(this.findNodeAndOffsetFromLocation(t))[0];return st(e)}lock(){this.lockCount++==0&&(this.updateCurrentLocationRange(),this.lockedLocationRange=this.getLocationRange())}unlock(){if(--this.lockCount==0){let{lockedLocationRange:t}=this;if(this.lockedLocationRange=null,t!=null)return this.setLocationRange(t)}}clearSelection(){var t;return(t=Li())===null||t===void 0?void 0:t.removeAllRanges()}selectionIsCollapsed(){var t;return((t=yt())===null||t===void 0?void 0:t.collapsed)===!0}selectionIsExpanded(){return!this.selectionIsCollapsed()}createLocationRangeFromDOMRange(t,e){if(t==null||!this.domRangeWithinElement(t))return;let i=this.findLocationFromContainerAndOffset(t.startContainer,t.startOffset,e);if(!i)return;let r=t.collapsed?void 0:this.findLocationFromContainerAndOffset(t.endContainer,t.endOffset,e);return g([i,r])}didMouseDown(){return this.pauseTemporarily()}pauseTemporarily(){let t;this.paused=!0;let e=()=>{if(this.paused=!1,clearTimeout(i),Array.from(t).forEach(r=>{r.destroy()}),J(document,this.element))return this.selectionDidChange()},i=setTimeout(e,200);t=["mousemove","keydown"].map(r=>p(r,{onElement:document,withCallback:e}))}selectionDidChange(){if(!this.paused&&!Ue(this.element))return this.updateCurrentLocationRange()}updateCurrentLocationRange(t){var e,i;if((t??(t=this.createLocationRangeFromDOMRange(yt())))&&!Pt(t,this.currentLocationRange))return this.currentLocationRange=t,(e=this.delegate)===null||e===void 0||(i=e.locationRangeDidChange)===null||i===void 0?void 0:i.call(e,this.currentLocationRange.slice(0))}createDOMRangeFromLocationRange(t){let e=this.findContainerAndOffsetFromLocation(t[0]),i=N(t)?e:this.findContainerAndOffsetFromLocation(t[1])||e;if(e!=null&&i!=null){let r=document.createRange();return r.setStart(...Array.from(e||[])),r.setEnd(...Array.from(i||[])),r}}getLocationAtPoint(t){let e=this.createDOMRangeFromPoint(t);var i;if(e)return(i=this.createLocationRangeFromDOMRange(e))===null||i===void 0?void 0:i[0]}domRangeWithinElement(t){return t.collapsed?J(this.element,t.startContainer):J(this.element,t.startContainer)&&J(this.element,t.endContainer)}};I.proxyMethod("locationMapper.findLocationFromContainerAndOffset"),I.proxyMethod("locationMapper.findContainerAndOffsetFromLocation"),I.proxyMethod("locationMapper.findNodeAndOffsetFromLocation"),I.proxyMethod("pointMapper.createDOMRangeFromPoint"),I.proxyMethod("pointMapper.getClientRectsForDOMRange");var Pi=Object.freeze({__proto__:null,Attachment:H,AttachmentManager:Ut,AttachmentPiece:z,Block:S,Composition:F,Document:k,Editor:Ht,HTMLParser:et,HTMLSanitizer:lt,LineBreakInsertion:qt,LocationMapper:zt,ManagedAttachment:m,Piece:j,PointMapper:_t,SelectionManager:I,SplittableList:ut,StringPiece:Rt,Text:R,UndoManager:Et}),In=Object.freeze({__proto__:null,ObjectView:M,AttachmentView:kt,BlockView:jt,DocumentView:ct,PieceView:Ot,PreviewableAttachmentView:Nt,TextView:Mt}),{lang:Ae,css:_,keyNames:Nn}=Lt,xe=function(n){return function(){let t=n.apply(this,arguments);t.do(),this.undos||(this.undos=[]),this.undos.push(t.undo)}},Jt=class extends f{constructor(t,e,i){let r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{};super(...arguments),E(this,"makeElementMutable",xe(()=>({do:()=>{this.element.dataset.trixMutable=!0},undo:()=>delete this.element.dataset.trixMutable}))),E(this,"addToolbar",xe(()=>{let o=d({tagName:"div",className:_.attachmentToolbar,data:{trixMutable:!0},childNodes:d({tagName:"div",className:"trix-button-row",childNodes:d({tagName:"span",className:"trix-button-group trix-button-group--actions",childNodes:d({tagName:"button",className:"trix-button trix-button--remove",textContent:Ae.remove,attributes:{title:Ae.remove},data:{trixAction:"remove"}})})})});return this.attachment.isPreviewable()&&o.appendChild(d({tagName:"div",className:_.attachmentMetadataContainer,childNodes:d({tagName:"span",className:_.attachmentMetadata,childNodes:[d({tagName:"span",className:_.attachmentName,textContent:this.attachment.getFilename(),attributes:{title:this.attachment.getFilename()}}),d({tagName:"span",className:_.attachmentSize,textContent:this.attachment.getFormattedFilesize()})]})})),p("click",{onElement:o,withCallback:this.didClickToolbar}),p("click",{onElement:o,matchingSelector:"[data-trix-action]",withCallback:this.didClickActionButton}),vt("trix-attachment-before-toolbar",{onElement:this.element,attributes:{toolbar:o,attachment:this.attachment}}),{do:()=>this.element.appendChild(o),undo:()=>V(o)}})),E(this,"installCaptionEditor",xe(()=>{let o=d({tagName:"textarea",className:_.attachmentCaptionEditor,attributes:{placeholder:Ae.captionPlaceholder},data:{trixMutable:!0}});o.value=this.attachmentPiece.getCaption();let s=o.cloneNode();s.classList.add("trix-autoresize-clone"),s.tabIndex=-1;let a=function(){s.value=o.value,o.style.height=s.scrollHeight+"px"};p("input",{onElement:o,withCallback:a}),p("input",{onElement:o,withCallback:this.didInputCaption}),p("keydown",{onElement:o,withCallback:this.didKeyDownCaption}),p("change",{onElement:o,withCallback:this.didChangeCaption}),p("blur",{onElement:o,withCallback:this.didBlurCaption});let l=this.element.querySelector("figcaption"),c=l.cloneNode();return{do:()=>{if(l.style.display="none",c.appendChild(o),c.appendChild(s),c.classList.add("".concat(_.attachmentCaption,"--editing")),l.parentElement.insertBefore(c,l),a(),this.options.editCaption)return He(()=>o.focus())},undo(){V(c),l.style.display=null}}})),this.didClickToolbar=this.didClickToolbar.bind(this),this.didClickActionButton=this.didClickActionButton.bind(this),this.didKeyDownCaption=this.didKeyDownCaption.bind(this),this.didInputCaption=this.didInputCaption.bind(this),this.didChangeCaption=this.didChangeCaption.bind(this),this.didBlurCaption=this.didBlurCaption.bind(this),this.attachmentPiece=t,this.element=e,this.container=i,this.options=r,this.attachment=this.attachmentPiece.attachment,x(this.element)==="a"&&(this.element=this.element.firstChild),this.install()}install(){this.makeElementMutable(),this.addToolbar(),this.attachment.isPreviewable()&&this.installCaptionEditor()}uninstall(){var t;let e=this.undos.pop();for(this.savePendingCaption();e;)e(),e=this.undos.pop();(t=this.delegate)===null||t===void 0||t.didUninstallAttachmentEditor(this)}savePendingCaption(){if(this.pendingCaption!=null){let o=this.pendingCaption;var t,e,i,r;this.pendingCaption=null,o?(t=this.delegate)===null||t===void 0||(e=t.attachmentEditorDidRequestUpdatingAttributesForAttachment)===null||e===void 0||e.call(t,{caption:o},this.attachment):(i=this.delegate)===null||i===void 0||(r=i.attachmentEditorDidRequestRemovingAttributeForAttachment)===null||r===void 0||r.call(i,"caption",this.attachment)}}didClickToolbar(t){return t.preventDefault(),t.stopPropagation()}didClickActionButton(t){var e;if(t.target.getAttribute("data-trix-action")==="remove")return(e=this.delegate)===null||e===void 0?void 0:e.attachmentEditorDidRequestRemovalOfAttachment(this.attachment)}didKeyDownCaption(t){var e,i;if(Nn[t.keyCode]==="return")return t.preventDefault(),this.savePendingCaption(),(e=this.delegate)===null||e===void 0||(i=e.attachmentEditorDidRequestDeselectingAttachment)===null||i===void 0?void 0:i.call(e,this.attachment)}didInputCaption(t){this.pendingCaption=t.target.value.replace(/\s/g," ").trim()}didChangeCaption(t){return this.savePendingCaption()}didBlurCaption(t){return this.savePendingCaption()}},Kt=class extends f{constructor(t,e){super(...arguments),this.didFocus=this.didFocus.bind(this),this.didBlur=this.didBlur.bind(this),this.didClickAttachment=this.didClickAttachment.bind(this),this.element=t,this.composition=e,this.documentView=new ct(this.composition.document,{element:this.element}),p("focus",{onElement:this.element,withCallback:this.didFocus}),p("blur",{onElement:this.element,withCallback:this.didBlur}),p("click",{onElement:this.element,matchingSelector:"a[contenteditable=false]",preventDefault:!0}),p("mousedown",{onElement:this.element,matchingSelector:K,withCallback:this.didClickAttachment}),p("click",{onElement:this.element,matchingSelector:"a".concat(K),preventDefault:!0})}didFocus(t){var e;let i=()=>{var r,o;if(!this.focused)return this.focused=!0,(r=this.delegate)===null||r===void 0||(o=r.compositionControllerDidFocus)===null||o===void 0?void 0:o.call(r)};return((e=this.blurPromise)===null||e===void 0?void 0:e.then(i))||i()}didBlur(t){this.blurPromise=new Promise(e=>He(()=>{var i,r;return Ue(this.element)||(this.focused=null,(i=this.delegate)===null||i===void 0||(r=i.compositionControllerDidBlur)===null||r===void 0||r.call(i)),this.blurPromise=null,e()}))}didClickAttachment(t,e){var i,r;let o=this.findAttachmentForElement(e),s=!!q(t.target,{matchingSelector:"figcaption"});return(i=this.delegate)===null||i===void 0||(r=i.compositionControllerDidSelectAttachment)===null||r===void 0?void 0:r.call(i,o,{editCaption:s})}getSerializableElement(){return this.isEditingAttachment()?this.documentView.shadowElement:this.element}render(){var t,e,i,r,o,s;return this.revision!==this.composition.revision&&(this.documentView.setDocument(this.composition.document),this.documentView.render(),this.revision=this.composition.revision),this.canSyncDocumentView()&&!this.documentView.isSynced()&&((i=this.delegate)===null||i===void 0||(r=i.compositionControllerWillSyncDocumentView)===null||r===void 0||r.call(i),this.documentView.sync(),(o=this.delegate)===null||o===void 0||(s=o.compositionControllerDidSyncDocumentView)===null||s===void 0||s.call(o)),(t=this.delegate)===null||t===void 0||(e=t.compositionControllerDidRender)===null||e===void 0?void 0:e.call(t)}rerenderViewForObject(t){return this.invalidateViewForObject(t),this.render()}invalidateViewForObject(t){return this.documentView.invalidateViewForObject(t)}isViewCachingEnabled(){return this.documentView.isViewCachingEnabled()}enableViewCaching(){return this.documentView.enableViewCaching()}disableViewCaching(){return this.documentView.disableViewCaching()}refreshViewCache(){return this.documentView.garbageCollectCachedViews()}isEditingAttachment(){return!!this.attachmentEditor}installAttachmentEditorForAttachment(t,e){var i;if(((i=this.attachmentEditor)===null||i===void 0?void 0:i.attachment)===t)return;let r=this.documentView.findElementForObject(t);if(!r)return;this.uninstallAttachmentEditor();let o=this.composition.document.getAttachmentPieceForAttachment(t);this.attachmentEditor=new Jt(o,r,this.element,e),this.attachmentEditor.delegate=this}uninstallAttachmentEditor(){var t;return(t=this.attachmentEditor)===null||t===void 0?void 0:t.uninstall()}didUninstallAttachmentEditor(){return this.attachmentEditor=null,this.render()}attachmentEditorDidRequestUpdatingAttributesForAttachment(t,e){var i,r;return(i=this.delegate)===null||i===void 0||(r=i.compositionControllerWillUpdateAttachment)===null||r===void 0||r.call(i,e),this.composition.updateAttributesForAttachment(t,e)}attachmentEditorDidRequestRemovingAttributeForAttachment(t,e){var i,r;return(i=this.delegate)===null||i===void 0||(r=i.compositionControllerWillUpdateAttachment)===null||r===void 0||r.call(i,e),this.composition.removeAttributeForAttachment(t,e)}attachmentEditorDidRequestRemovalOfAttachment(t){var e,i;return(e=this.delegate)===null||e===void 0||(i=e.compositionControllerDidRequestRemovalOfAttachment)===null||i===void 0?void 0:i.call(e,t)}attachmentEditorDidRequestDeselectingAttachment(t){var e,i;return(e=this.delegate)===null||e===void 0||(i=e.compositionControllerDidRequestDeselectingAttachment)===null||i===void 0?void 0:i.call(e,t)}canSyncDocumentView(){return!this.isEditingAttachment()}findAttachmentForElement(t){return this.composition.document.getAttachmentById(parseInt(t.dataset.trixId,10))}},$t=class extends f{},Ii="data-trix-mutable",On="[".concat(Ii,"]"),Mn={attributes:!0,childList:!0,characterData:!0,characterDataOldValue:!0,subtree:!0},Gt=class extends f{constructor(t){super(t),this.didMutate=this.didMutate.bind(this),this.element=t,this.observer=new window.MutationObserver(this.didMutate),this.start()}start(){return this.reset(),this.observer.observe(this.element,Mn)}stop(){return this.observer.disconnect()}didMutate(t){var e,i;if(this.mutations.push(...Array.from(this.findSignificantMutations(t)||[])),this.mutations.length)return(e=this.delegate)===null||e===void 0||(i=e.elementDidMutate)===null||i===void 0||i.call(e,this.getMutationSummary()),this.reset()}reset(){this.mutations=[]}findSignificantMutations(t){return t.filter(e=>this.mutationIsSignificant(e))}mutationIsSignificant(t){if(this.nodeIsMutable(t.target))return!1;for(let e of Array.from(this.nodesModifiedByMutation(t)))if(this.nodeIsSignificant(e))return!0;return!1}nodeIsSignificant(t){return t!==this.element&&!this.nodeIsMutable(t)&&!yi(t)}nodeIsMutable(t){return q(t,{matchingSelector:On})}nodesModifiedByMutation(t){let e=[];switch(t.type){case"attributes":t.attributeName!==Ii&&e.push(t.target);break;case"characterData":e.push(t.target.parentNode),e.push(t.target);break;case"childList":e.push(...Array.from(t.addedNodes||[])),e.push(...Array.from(t.removedNodes||[]))}return e}getMutationSummary(){return this.getTextMutationSummary()}getTextMutationSummary(){let{additions:t,deletions:e}=this.getTextChangesFromCharacterData(),i=this.getTextChangesFromChildList();Array.from(i.additions).forEach(a=>{Array.from(t).includes(a)||t.push(a)}),e.push(...Array.from(i.deletions||[]));let r={},o=t.join("");o&&(r.textAdded=o);let s=e.join("");return s&&(r.textDeleted=s),r}getMutationsByType(t){return Array.from(this.mutations).filter(e=>e.type===t)}getTextChangesFromChildList(){let t,e,i=[],r=[];return Array.from(this.getMutationsByType("childList")).forEach(o=>{i.push(...Array.from(o.addedNodes||[])),r.push(...Array.from(o.removedNodes||[]))}),i.length===0&&r.length===1&&ot(r[0])?(t=[],e=[` `]):(t=Ie(i),e=Ie(r)),{additions:t.filter((o,s)=>o!==e[s]).map(bt),deletions:e.filter((o,s)=>o!==t[s]).map(bt)}}getTextChangesFromCharacterData(){let t,e,i=this.getMutationsByType("characterData");if(i.length){let r=i[0],o=i[i.length-1],s=function(a,l){let c,u;return a=Z.box(a),(l=Z.box(l)).length0&&arguments[0]!==void 0?arguments[0]:[],t=[];for(let e of Array.from(n))switch(e.nodeType){case Node.TEXT_NODE:t.push(e.data);break;case Node.ELEMENT_NODE:x(e)==="br"?t.push(` `):t.push(...Array.from(Ie(e.childNodes)||[]))}return t},Xt=class extends at{constructor(t){super(...arguments),this.file=t}perform(t){let e=new FileReader;return e.onerror=()=>t(!1),e.onload=()=>{e.onerror=null;try{e.abort()}catch{}return t(!0,this.file)},e.readAsArrayBuffer(this.file)}},Ne=class{constructor(t){this.element=t}shouldIgnore(t){return!!St.samsungAndroid&&(this.previousEvent=this.event,this.event=t,this.checkSamsungKeyboardBuggyModeStart(),this.checkSamsungKeyboardBuggyModeEnd(),this.buggyMode)}checkSamsungKeyboardBuggyModeStart(){this.insertingLongTextAfterUnidentifiedChar()&&jn(this.element.innerText,this.event.data)&&(this.buggyMode=!0,this.event.preventDefault())}checkSamsungKeyboardBuggyModeEnd(){this.buggyMode&&this.event.inputType!=="insertText"&&(this.buggyMode=!1)}insertingLongTextAfterUnidentifiedChar(){var t;return this.isBeforeInputInsertText()&&this.previousEventWasUnidentifiedKeydown()&&((t=this.event.data)===null||t===void 0?void 0:t.length)>50}isBeforeInputInsertText(){return this.event.type==="beforeinput"&&this.event.inputType==="insertText"}previousEventWasUnidentifiedKeydown(){var t,e;return((t=this.previousEvent)===null||t===void 0?void 0:t.type)==="keydown"&&((e=this.previousEvent)===null||e===void 0?void 0:e.key)==="Unidentified"}},jn=(n,t)=>gi(n)===gi(t),Wn=new RegExp("(".concat("\uFFFC","|").concat(te,"|").concat(U,"|\\s)+"),"g"),gi=n=>n.replace(Wn," ").trim(),ht=class extends f{constructor(t){super(...arguments),this.element=t,this.mutationObserver=new Gt(this.element),this.mutationObserver.delegate=this,this.flakyKeyboardDetector=new Ne(this.element);for(let e in this.constructor.events)p(e,{onElement:this.element,withCallback:this.handlerFor(e)})}elementDidMutate(t){}editorWillSyncDocumentView(){return this.mutationObserver.stop()}editorDidSyncDocumentView(){return this.mutationObserver.start()}requestRender(){var t,e;return(t=this.delegate)===null||t===void 0||(e=t.inputControllerDidRequestRender)===null||e===void 0?void 0:e.call(t)}requestReparse(){var t,e;return(t=this.delegate)===null||t===void 0||(e=t.inputControllerDidRequestReparse)===null||e===void 0||e.call(t),this.requestRender()}attachFiles(t){let e=Array.from(t).map(i=>new Xt(i));return Promise.all(e).then(i=>{this.handleInput(function(){var r,o;return(r=this.delegate)===null||r===void 0||r.inputControllerWillAttachFiles(),(o=this.responder)===null||o===void 0||o.insertFiles(i),this.requestRender()})})}handlerFor(t){return e=>{e.defaultPrevented||this.handleInput(()=>{if(!Ue(this.element)){if(this.flakyKeyboardDetector.shouldIgnore(e))return;this.eventName=t,this.constructor.events[t].call(this,e)}})}}handleInput(t){try{var e;(e=this.delegate)===null||e===void 0||e.inputControllerWillHandleInput(),t.call(this)}finally{var i;(i=this.delegate)===null||i===void 0||i.inputControllerDidHandleInput()}}createLinkHTML(t,e){let i=document.createElement("a");return i.href=t,i.textContent=e||t,i.outerHTML}},ye;E(ht,"events",{});var{browser:Un,keyNames:Ni}=Lt,qn=0,w=class extends ht{constructor(){super(...arguments),this.resetInputSummary()}setInputSummary(){let t=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};this.inputSummary.eventName=this.eventName;for(let e in t){let i=t[e];this.inputSummary[e]=i}return this.inputSummary}resetInputSummary(){this.inputSummary={}}reset(){return this.resetInputSummary(),tt.reset()}elementDidMutate(t){var e,i;return this.isComposing()?(e=this.delegate)===null||e===void 0||(i=e.inputControllerDidAllowUnhandledInput)===null||i===void 0?void 0:i.call(e):this.handleInput(function(){return this.mutationIsSignificant(t)&&(this.mutationIsExpected(t)?this.requestRender():this.requestReparse()),this.reset()})}mutationIsExpected(t){let{textAdded:e,textDeleted:i}=t;if(this.inputSummary.preferDocument)return!0;let r=e!=null?e===this.inputSummary.textAdded:!this.inputSummary.textAdded,o=i!=null?this.inputSummary.didDelete:!this.inputSummary.didDelete,s=[` -`,` +`,` `].includes(e)&&!r,a=i===` `&&!o;if(s&&!a||a&&!s){let c=this.getSelectedRange();if(c){var l;let u=s?e.replace(/\n$/,"").length||-1:e?.length||1;if((l=this.responder)!==null&&l!==void 0&&l.positionIsBlockBreak(c[1]+u))return!0}}return r&&o}mutationIsSignificant(t){var e;let i=Object.keys(t).length>0,r=((e=this.compositionInput)===null||e===void 0?void 0:e.getEndData())==="";return i||!r}getCompositionInput(){if(this.isComposing())return this.compositionInput;this.compositionInput=new B(this)}isComposing(){return this.compositionInput&&!this.compositionInput.isEnded()}deleteInDirection(t,e){var i;return((i=this.responder)===null||i===void 0?void 0:i.deleteInDirection(t))!==!1?this.setInputSummary({didDelete:!0}):e?(e.preventDefault(),this.requestRender()):void 0}serializeSelectionToDataTransfer(t){var e;if(!function(r){if(r==null||!r.setData)return!1;for(let o in Ye){let s=Ye[o];try{if(r.setData(o,s),!r.getData(o)===s)return!1}catch{return!1}}return!0}(t))return;let i=(e=this.responder)===null||e===void 0?void 0:e.getSelectedDocument().toSerializableDocument();return t.setData("application/x-trix-document",JSON.stringify(i)),t.setData("text/html",ct.render(i).innerHTML),t.setData("text/plain",i.toString().replace(/\n$/,"")),!0}canAcceptDataTransfer(t){let e={};return Array.from(t?.types||[]).forEach(i=>{e[i]=!0}),e.Files||e["application/x-trix-document"]||e["text/html"]||e["text/plain"]}getPastedHTMLUsingHiddenElement(t){let e=this.getSelectedRange(),i={position:"absolute",left:"".concat(window.pageXOffset,"px"),top:"".concat(window.pageYOffset,"px"),opacity:0},r=d({style:i,tagName:"div",editable:!0});return document.body.appendChild(r),r.focus(),requestAnimationFrame(()=>{let o=r.innerHTML;return V(r),this.setSelectedRange(e),t(o)})}};E(w,"events",{keydown(n){this.isComposing()||this.resetInputSummary(),this.inputSummary.didInput=!0;let t=Ni[n.keyCode];if(t){var e;let r=this.keys;["ctrl","alt","shift","meta"].forEach(o=>{var s;n["".concat(o,"Key")]&&(o==="ctrl"&&(o="control"),r=(s=r)===null||s===void 0?void 0:s[o])}),((e=r)===null||e===void 0?void 0:e[t])!=null&&(this.setInputSummary({keyName:t}),tt.reset(),r[t].call(this,n))}if(Ei(n)){let r=String.fromCharCode(n.keyCode).toLowerCase();if(r){var i;let o=["alt","shift"].map(s=>{if(n["".concat(s,"Key")])return s}).filter(s=>s);o.push(r),(i=this.delegate)!==null&&i!==void 0&&i.inputControllerDidReceiveKeyboardCommand(o)&&n.preventDefault()}}},keypress(n){if(this.inputSummary.eventName!=null||n.metaKey||n.ctrlKey&&!n.altKey)return;let t=zn(n);var e,i;return t?((e=this.delegate)===null||e===void 0||e.inputControllerWillPerformTyping(),(i=this.responder)===null||i===void 0||i.insertString(t),this.setInputSummary({textAdded:t,didDelete:this.selectionIsExpanded()})):void 0},textInput(n){let{data:t}=n,{textAdded:e}=this.inputSummary;if(e&&e!==t&&e.toUpperCase()===t){var i;let r=this.getSelectedRange();return this.setSelectedRange([r[0],r[1]+e.length]),(i=this.responder)===null||i===void 0||i.insertString(t),this.setInputSummary({textAdded:t}),this.setSelectedRange(r)}},dragenter(n){n.preventDefault()},dragstart(n){var t,e;return this.serializeSelectionToDataTransfer(n.dataTransfer),this.draggedRange=this.getSelectedRange(),(t=this.delegate)===null||t===void 0||(e=t.inputControllerDidStartDrag)===null||e===void 0?void 0:e.call(t)},dragover(n){if(this.draggedRange||this.canAcceptDataTransfer(n.dataTransfer)){n.preventDefault();let i={x:n.clientX,y:n.clientY};var t,e;if(!dt(i,this.draggingPoint))return this.draggingPoint=i,(t=this.delegate)===null||t===void 0||(e=t.inputControllerDidReceiveDragOverPoint)===null||e===void 0?void 0:e.call(t,this.draggingPoint)}},dragend(n){var t,e;(t=this.delegate)===null||t===void 0||(e=t.inputControllerDidCancelDrag)===null||e===void 0||e.call(t),this.draggedRange=null,this.draggingPoint=null},drop(n){var t,e;n.preventDefault();let i=(t=n.dataTransfer)===null||t===void 0?void 0:t.files,r=n.dataTransfer.getData("application/x-trix-document"),o={x:n.clientX,y:n.clientY};if((e=this.responder)===null||e===void 0||e.setLocationRangeFromPointRange(o),i!=null&&i.length)this.attachFiles(i);else if(this.draggedRange){var s,a;(s=this.delegate)===null||s===void 0||s.inputControllerWillMoveText(),(a=this.responder)===null||a===void 0||a.moveTextFromRange(this.draggedRange),this.draggedRange=null,this.requestRender()}else if(r){var l;let c=k.fromJSONString(r);(l=this.responder)===null||l===void 0||l.insertDocument(c),this.requestRender()}this.draggedRange=null,this.draggingPoint=null},cut(n){var t,e;if((t=this.responder)!==null&&t!==void 0&&t.selectionIsExpanded()&&(this.serializeSelectionToDataTransfer(n.clipboardData)&&n.preventDefault(),(e=this.delegate)===null||e===void 0||e.inputControllerWillCutText(),this.deleteInDirection("backward"),n.defaultPrevented))return this.requestRender()},copy(n){var t;(t=this.responder)!==null&&t!==void 0&&t.selectionIsExpanded()&&this.serializeSelectionToDataTransfer(n.clipboardData)&&n.preventDefault()},paste(n){let t=n.clipboardData||n.testClipboardData,e={clipboard:t};if(!t||_n(n))return void this.getPastedHTMLUsingHiddenElement(D=>{var nt,re,oe;return e.type="text/html",e.html=D,(nt=this.delegate)===null||nt===void 0||nt.inputControllerWillPaste(e),(re=this.responder)===null||re===void 0||re.insertHTML(e.html),this.requestRender(),(oe=this.delegate)===null||oe===void 0?void 0:oe.inputControllerDidPaste(e)});let i=t.getData("URL"),r=t.getData("text/html"),o=t.getData("public.url-name");if(i){var s,a,l;let D;e.type="text/html",D=o?_e(o).trim():i,e.html=this.createLinkHTML(i,D),(s=this.delegate)===null||s===void 0||s.inputControllerWillPaste(e),this.setInputSummary({textAdded:D,didDelete:this.selectionIsExpanded()}),(a=this.responder)===null||a===void 0||a.insertHTML(e.html),this.requestRender(),(l=this.delegate)===null||l===void 0||l.inputControllerDidPaste(e)}else if(Ri(t)){var c,u,b;e.type="text/plain",e.string=t.getData("text/plain"),(c=this.delegate)===null||c===void 0||c.inputControllerWillPaste(e),this.setInputSummary({textAdded:e.string,didDelete:this.selectionIsExpanded()}),(u=this.responder)===null||u===void 0||u.insertString(e.string),this.requestRender(),(b=this.delegate)===null||b===void 0||b.inputControllerDidPaste(e)}else if(r){var A,L,gt;e.type="text/html",e.html=r,(A=this.delegate)===null||A===void 0||A.inputControllerWillPaste(e),(L=this.responder)===null||L===void 0||L.insertHTML(e.html),this.requestRender(),(gt=this.delegate)===null||gt===void 0||gt.inputControllerDidPaste(e)}else if(Array.from(t.types).includes("Files")){var P,it;let D=(P=t.items)===null||P===void 0||(P=P[0])===null||P===void 0||(it=P.getAsFile)===null||it===void 0?void 0:it.call(P);if(D){var mt,ie,ne;let nt=Vn(D);!D.name&&nt&&(D.name="pasted-file-".concat(++qn,".").concat(nt)),e.type="File",e.file=D,(mt=this.delegate)===null||mt===void 0||mt.inputControllerWillAttachFiles(),(ie=this.responder)===null||ie===void 0||ie.insertFile(e.file),this.requestRender(),(ne=this.delegate)===null||ne===void 0||ne.inputControllerDidPaste(e)}}n.preventDefault()},compositionstart(n){return this.getCompositionInput().start(n.data)},compositionupdate(n){return this.getCompositionInput().update(n.data)},compositionend(n){return this.getCompositionInput().end(n.data)},beforeinput(n){this.inputSummary.didInput=!0},input(n){return this.inputSummary.didInput=!0,n.stopPropagation()}}),E(w,"keys",{backspace(n){var t;return(t=this.delegate)===null||t===void 0||t.inputControllerWillPerformTyping(),this.deleteInDirection("backward",n)},delete(n){var t;return(t=this.delegate)===null||t===void 0||t.inputControllerWillPerformTyping(),this.deleteInDirection("forward",n)},return(n){var t,e;return this.setInputSummary({preferDocument:!0}),(t=this.delegate)===null||t===void 0||t.inputControllerWillPerformTyping(),(e=this.responder)===null||e===void 0?void 0:e.insertLineBreak()},tab(n){var t,e;(t=this.responder)!==null&&t!==void 0&&t.canIncreaseNestingLevel()&&((e=this.responder)===null||e===void 0||e.increaseNestingLevel(),this.requestRender(),n.preventDefault())},left(n){var t;if(this.selectionIsInCursorTarget())return n.preventDefault(),(t=this.responder)===null||t===void 0?void 0:t.moveCursorInDirection("backward")},right(n){var t;if(this.selectionIsInCursorTarget())return n.preventDefault(),(t=this.responder)===null||t===void 0?void 0:t.moveCursorInDirection("forward")},control:{d(n){var t;return(t=this.delegate)===null||t===void 0||t.inputControllerWillPerformTyping(),this.deleteInDirection("forward",n)},h(n){var t;return(t=this.delegate)===null||t===void 0||t.inputControllerWillPerformTyping(),this.deleteInDirection("backward",n)},o(n){var t,e;return n.preventDefault(),(t=this.delegate)===null||t===void 0||t.inputControllerWillPerformTyping(),(e=this.responder)===null||e===void 0||e.insertString(` `,{updatePosition:!1}),this.requestRender()}},shift:{return(n){var t,e;(t=this.delegate)===null||t===void 0||t.inputControllerWillPerformTyping(),(e=this.responder)===null||e===void 0||e.insertString(` diff --git a/resources/scripts/components/NavigationBar.tsx b/resources/scripts/components/NavigationBar.tsx index 7372ccbeed..63f49f6f89 100644 --- a/resources/scripts/components/NavigationBar.tsx +++ b/resources/scripts/components/NavigationBar.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { useState } from 'react'; import { Link, NavLink } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faCogs, faLayerGroup, faSignOutAlt } from '@fortawesome/free-solid-svg-icons'; +import { faCogs, faHandSparkles, faLayerGroup, faSignOutAlt } from '@fortawesome/free-solid-svg-icons'; import { useStoreState } from 'easy-peasy'; import { useTranslation } from 'react-i18next'; import { ApplicationStore } from '@/state'; @@ -64,6 +64,11 @@ export default () => { + + + + + ('dashboard')}> diff --git a/resources/views/filament/components/server-console.blade.php b/resources/views/filament/components/server-console.blade.php new file mode 100644 index 0000000000..16e4abd0d1 --- /dev/null +++ b/resources/views/filament/components/server-console.blade.php @@ -0,0 +1,134 @@ + + @assets + + + @endassets + +
+ +
+ +
+ + @script + + @endscript + diff --git a/resources/views/filament/plugins/monaco-editor.blade.php b/resources/views/filament/plugins/monaco-editor.blade.php index 4a8355059d..3980c1bbb9 100644 --- a/resources/views/filament/plugins/monaco-editor.blade.php +++ b/resources/views/filament/plugins/monaco-editor.blade.php @@ -14,6 +14,14 @@ automaticLayout: {{ (int) $getAutomaticLayout() }}, monacoId: $id('monaco-editor'), + toggleFullScreenMode() { + this.fullScreenModeEnabled = !this.fullScreenModeEnabled; + this.fullScreenModeEnabled ? document.body.classList.add('overflow-hidden') + : document.body.classList.remove('overflow-hidden'); + $el.style.width = this.fullScreenModeEnabled ? '100vw' + : $el.parentElement.clientWidth + 'px'; + }, + monacoEditor(editor){ editor.onDidChangeModelContent((e) => { this.monacoContent = editor.getValue(); @@ -45,11 +53,21 @@ monacoEditorAddLoaderScriptToHead() { script = document.createElement('script'); - script.src = 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.39.0/min/vs/loader.min.js'; + script.src = 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.49.0/min/vs/loader.min.js'; document.head.appendChild(script); }, + wrapPreview(value){ + return `{{ $getPreviewHeadEndContent() }}` + + `<body {{ $getPreviewBodyAttributes() }}>` + + `{{ $getPreviewBodyStartContent() }}` + + `${value}` + + `{{ $getPreviewBodyEndContent() }}` + + `</body>`; + }, + }" x-init=" + previewContent = wrapPreview(monacoContent); $el.style.height = '500px'; $watch('fullScreenModeEnabled', value => { if (value) { @@ -67,8 +85,8 @@ if(typeof _amdLoaderGlobal !== 'undefined'){ // Based on https://jsfiddle.net/developit/bwgkr6uq/ which works without needing service worker. Provided by loader.min.js. - require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.39.0/min/vs' }}); - let proxy = URL.createObjectURL(new Blob([` self.MonacoEnvironment = { baseUrl: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.39.0/min' }; importScripts('https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.39.0/min/vs/base/worker/workerMain.min.js');`], { type: 'text/javascript' })); + require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.49.0/min/vs' }}); + let proxy = URL.createObjectURL(new Blob([` self.MonacoEnvironment = { baseUrl: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.49.0/min' }; importScripts('https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.49.0/min/vs/base/worker/workerMain.min.js');`], { type: 'text/javascript' })); window.MonacoEnvironment = { getWorkerUrl: () => proxy }; require(['vs/editor/editor.main'], () => { @@ -83,7 +101,9 @@ language: monacoLanguage, scrollbar: { horizontal: 'auto', - horizontalScrollbarSize: 15 + horizontalScrollbarSize: 15, + vertical: 'auto', + verticalScrollbarSize: 15 }, }); @@ -100,14 +120,20 @@ }, 5); " :id="monacoId" class="fme-wrapper" :class="{ 'fme-full-screen': fullScreenModeEnabled }" x-cloak> -
-
+
+ @if($getShowFullScreenToggle()) + + @endif +
+
-
+
-
diff --git a/resources/views/filament/server-conflict-banner.blade.php b/resources/views/filament/server-conflict-banner.blade.php new file mode 100644 index 0000000000..9bbe493e17 --- /dev/null +++ b/resources/views/filament/server-conflict-banner.blade.php @@ -0,0 +1,19 @@ +@php + $shouldShow = false; + + try { + \Filament\Facades\Filament::getTenant()->validateCurrentState(); + } catch (\App\Exceptions\Http\Server\ServerStateConflictException $exception) { + $shouldShow = true; + $message = $exception->getMessage(); + } +@endphp + +@if ($shouldShow) +
+
+ +

{!! $message !!}

+
+
+@endif \ No newline at end of file diff --git a/resources/views/filament/server/pages/console.blade.php b/resources/views/filament/server/pages/console.blade.php new file mode 100644 index 0000000000..2deb74c686 --- /dev/null +++ b/resources/views/filament/server/pages/console.blade.php @@ -0,0 +1,7 @@ + + + diff --git a/resources/views/filament/server/pages/edit-file.blade.php b/resources/views/filament/server/pages/edit-file.blade.php new file mode 100644 index 0000000000..da43128038 --- /dev/null +++ b/resources/views/filament/server/pages/edit-file.blade.php @@ -0,0 +1,11 @@ + + + {{ $this->form }} + + + + diff --git a/resources/views/filament/server/pages/server-form-page.blade.php b/resources/views/filament/server/pages/server-form-page.blade.php new file mode 100644 index 0000000000..47914b50c9 --- /dev/null +++ b/resources/views/filament/server/pages/server-form-page.blade.php @@ -0,0 +1,9 @@ + + + {{ $this->form }} + + diff --git a/resources/views/tables/columns/server-entry-column.blade.php b/resources/views/tables/columns/server-entry-column.blade.php new file mode 100644 index 0000000000..526e2c82df --- /dev/null +++ b/resources/views/tables/columns/server-entry-column.blade.php @@ -0,0 +1,37 @@ +
+
+ + + + {{ $getRecord()->name }} ({{ $this->uptime($getRecord()) }}) + +
+ +
+
+ Allocation: {{ $getRecord()->allocation->address }} +
+
+ Egg: {{ $getRecord()->egg->name }} +
+
+ Owner: {{ $getRecord()->user->username }} +
+
+ +
+
+ CPU: {{ $this->cpu($getRecord()) }} +
+
+ RAM: {{ $this->memory($getRecord()) }} +
+
+ Disk: {{ $this->disk($getRecord()) }} +
+
+