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=`
-