diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8f0de65 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 + +[docker-compose.yml] +indent_size = 4 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..515b909 --- /dev/null +++ b/.env.example @@ -0,0 +1,66 @@ +APP_NAME=Laravel +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_URL=http://localhost +API_URL=http://localhost/api + +APP_LOCALE=en +APP_FALLBACK_LOCALE=en +APP_FAKER_LOCALE=en_US + +APP_MAINTENANCE_DRIVER=file +# APP_MAINTENANCE_STORE=database + +PHP_CLI_SERVER_WORKERS=4 + +BCRYPT_ROUNDS=12 + +LOG_CHANNEL=stack +LOG_STACK=single +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=mariadb +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=volcerto +DB_USERNAME=root +DB_PASSWORD= + +SESSION_DRIVER=database +SESSION_LIFETIME=120 +SESSION_ENCRYPT=false +SESSION_PATH=/ +SESSION_DOMAIN=null + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=database + +CACHE_STORE=database +# CACHE_PREFIX= + +MEMCACHED_HOST=127.0.0.1 + +REDIS_CLIENT=phpredis +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=log +MAIL_SCHEME=null +MAIL_HOST=127.0.0.1 +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_FROM_ADDRESS="hello@example.com" +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false + +VITE_APP_NAME="${APP_NAME}" diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..fcb21d3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +* text=auto eol=lf + +*.blade.php diff=html +*.css diff=css +*.html diff=html +*.md diff=markdown +*.php diff=php + +/.github export-ignore +CHANGELOG.md export-ignore +.styleci.yml export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b96b021 --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +/.phpunit.cache +/node_modules +/public/build +/public/hot +/public/storage +/storage/*.key +/storage/pail +/vendor +.env +.env.backup +.env.production +.env.testing +.phpactor.json +.phpunit.result.cache +Homestead.json +Homestead.yaml +npm-debug.log +yarn-error.log +/auth.json +/.fleet +/.idea +/.nova +/.vscode +/.zed +lang/vendor/backup/ diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..034e848 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,21 @@ +# Security Policy + +## Supported Versions + +Use this section to tell people about which versions of your project are +currently being supported with security updates. + +| Version | Supported | +| ------- | ------------------ | +| 5.1.x | :white_check_mark: | +| 5.0.x | :x: | +| 4.0.x | :white_check_mark: | +| < 4.0 | :x: | + +## Reporting a Vulnerability + +Use this section to tell people how to report a vulnerability. + +Tell them where to go, how often they can expect to get an update on a +reported vulnerability, what to expect if the vulnerability is accepted or +declined, etc. diff --git a/app/Console/Commands/CleanMinioBackups.php b/app/Console/Commands/CleanMinioBackups.php new file mode 100644 index 0000000..2bce4b6 --- /dev/null +++ b/app/Console/Commands/CleanMinioBackups.php @@ -0,0 +1,111 @@ +info('Connecting to MinIO bucket...'); + + $allFiles = $disk->allFiles($folder); + + if (empty($allFiles)) { + $this->info('No backup files found in the directory.'); + return 0; + } + + $this->info('Found ' . count($allFiles) . ' files. Processing...'); + + $zipFiles = collect($allFiles) + ->filter(fn($file) => str_ends_with($file, '.zip')) + ->values(); + + if ($zipFiles->isEmpty()) { + $this->info('No ZIP backup files found.'); + return 0; + } + + $this->info('Found ' . $zipFiles->count() . ' ZIP files.'); + + $backups = $zipFiles->map(function ($file) use ($disk) { + try { + $lastModified = (int) $disk->lastModified($file); + return [ + 'file' => $file, + 'lastModified' => $lastModified, + 'date' => date('Y-m-d H:i:s', $lastModified), + 'estimated' => false + ]; + } catch (\Exception $e) { + $this->warn("Cannot read metadata for {$file}, using filename for sorting"); + + preg_match('/(\d{4}-\d{2}-\d{2}-\d{2}-\d{2}-\d{2})/', $file, $matches); + + $timestamp = isset($matches[1]) + ? \DateTime::createFromFormat('Y-m-d-H-i-s', $matches[1])->getTimestamp() + : time(); + + return [ + 'file' => $file, + 'lastModified' => $timestamp, + 'date' => date('Y-m-d H:i:s', $timestamp), + 'estimated' => true + ]; + } + }); + + $backups = $backups->sortByDesc('lastModified')->values(); + + $totalBackups = $backups->count(); + $toDelete = $backups->slice($keep); + + $this->info("Valid backups found: {$totalBackups}"); + if ($toDelete->isEmpty()) { + $this->info("Only {$totalBackups} backup(s) found (less than {$keep}), nothing to delete."); + return 0; + } + + $this->info("Keeping the latest {$keep}, deleting {$toDelete->count()} old backups."); + + $this->info("Backups scheduled for deletion:"); + foreach ($toDelete as $item) { + $this->info(" - {$item['file']} ({$item['date']})" . ($item['estimated'] ? ' [estimated]' : '')); + } + + $deletedCount = 0; + foreach ($toDelete as $item) { + try { + $disk->delete($item['file']); + $this->info("✓ Deleted: {$item['file']}" . ($item['estimated'] ? ' [estimated]' : '')); + $deletedCount++; + } catch (\Exception $e) { + $this->error("✗ Failed to delete {$item['file']}: {$e->getMessage()}"); + } + } + + $this->info("Cleanup finished. Deleted {$deletedCount} files. Kept the last {$keep} backups."); + + } catch (\Exception $e) { + $this->error("Failed to access backup directory: {$e->getMessage()}"); + $this->error('Debug info:'); + $this->error('Bucket: ' . env('AWS_BUCKET')); + $this->error('Endpoint: ' . env('AWS_ENDPOINT')); + $this->error('Key: ' . substr(env('AWS_ACCESS_KEY_ID', ''), 0, 5) . '...'); + return 1; + } + + return 0; + } +} diff --git a/app/Console/Commands/SendTestEmail.php b/app/Console/Commands/SendTestEmail.php new file mode 100644 index 0000000..cc2f016 --- /dev/null +++ b/app/Console/Commands/SendTestEmail.php @@ -0,0 +1,31 @@ +sendTestEmail(); + } catch (\Throwable $e) { + $this->error('Erro ao enviar e-mail: ' . $e->getMessage()); + } + } +} diff --git a/app/Exports/ContractsExport.php b/app/Exports/ContractsExport.php new file mode 100644 index 0000000..71bbcfc --- /dev/null +++ b/app/Exports/ContractsExport.php @@ -0,0 +1,52 @@ +get()->map(function ($contract) { + return [ + 'Client' => $contract->client->name ?? '', + 'Seller' => $contract->seller->name ?? '', + 'Code' => $contract->code, + 'Supply Type' => strtoupper($contract->supply_type), + 'Power/CUI' => $contract->supply_type === 'cpe' + ? ($contract->powerTier->name ?? '') + : ($contract->cuiTier->name ?? ''), + 'Consumption' => $contract->annual_consumption ?? '', + 'Contract Type'=> $contract->contractType->description ?? '', + 'PVP' => $contract->contract_value, + 'Commission' => $contract->commission_value, + 'Status' => $contract->status->description ?? '', + 'Activation' => optional($contract->activation_date)->format('d/m/Y'), + 'Validity' => optional($contract->validity)->format('d/m/Y'), + 'Contract End' => optional($contract->contract_end_date)->format('d/m/Y'), + ]; + }); + } + + public function headings(): array + { + return [ + 'Cliente', + 'Vendedor', + 'Código', + 'Tipo Fornecimento', + 'Potência / Escalão', + 'Consumo Anual', + 'Tipo Contrato', + 'PVP', + 'Comissão', + 'Estado', + 'Data Ativação', + 'Validade', + 'Fim de Contrato', + ]; + } +} diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php new file mode 100644 index 0000000..b1186d4 --- /dev/null +++ b/app/Http/Controllers/AdminController.php @@ -0,0 +1,17 @@ +info()); + } + + public function phpInfo(AdminService $admin) + { + return response($admin->phpInfo())->header('Content-Type', 'text/html'); + } +} diff --git a/app/Http/Controllers/AnalyticalController.php b/app/Http/Controllers/AnalyticalController.php new file mode 100644 index 0000000..23f0088 --- /dev/null +++ b/app/Http/Controllers/AnalyticalController.php @@ -0,0 +1,18 @@ +analytics->index($request)); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/AccessController.php b/app/Http/Controllers/Api/AccessController.php new file mode 100644 index 0000000..6198d63 --- /dev/null +++ b/app/Http/Controllers/Api/AccessController.php @@ -0,0 +1,33 @@ +json($access->index()); + } + + public function users(UserAccessService $access) + { + return response()->json($access->index()); + } + + public function updatePermissions(Request $request, Role $role, RolePermissionService $access) + { + return response()->json(['role' => $access->updatePermissions($request, $role)]); + } + + public function updateRoles(Request $request, User $user, UserAccessService $access) + { + return response()->json(['user' => $access->updateRoles($request, $user)]); + } +} diff --git a/app/Http/Controllers/Api/AdminController.php b/app/Http/Controllers/Api/AdminController.php new file mode 100644 index 0000000..115834b --- /dev/null +++ b/app/Http/Controllers/Api/AdminController.php @@ -0,0 +1,36 @@ +json($this->admin->info()); + } + + public function phpInfo() + { + return response($this->admin->phpInfo())->header('Content-Type', 'text/html'); + } + + public function runMigrations() + { + $result = $this->admin->runMigrations(); + return response()->json($result, $result['success'] ? 200 : 500); + } + + public function testEmail(Request $request) + { + $data = $request->validate(['email' => 'required|email']); + return response()->json($this->admin->testEmail($data['email'])); + } +} diff --git a/app/Http/Controllers/Api/AuthController.php b/app/Http/Controllers/Api/AuthController.php new file mode 100644 index 0000000..87e4e29 --- /dev/null +++ b/app/Http/Controllers/Api/AuthController.php @@ -0,0 +1,66 @@ +validate(['email' => 'required|email', 'password' => 'required|string']); + return response()->json($this->authentication->issueToken($this->authentication->authenticate($credentials))); + } + + private function token(Request $request): PersonalAccessToken + { + $token = $request->user()->currentAccessToken(); + abort_unless($token instanceof PersonalAccessToken, 401, 'Token necessario.'); + return $token; + } + + public function refresh(Request $request) + { + return response()->json($this->authentication->refresh($this->token($request))); + } + + public function checkToken(Request $request) + { + return response()->json($this->authentication->check($this->token($request))); + } + + public function logout(Request $request) + { + $this->authentication->revoke($this->token($request)); + return response()->json(['message' => 'Logout realizado com sucesso', 'revoked' => true]); + } + + public function user(Request $request) + { + return response()->json($request->user()->load('roles.permissions')); + } + + public function sendResetLink(Request $request) + { + $credentials = $request->validate(['email' => 'required|email']); + $status = $this->authentication->sendResetLink($credentials); + return response()->json(['message' => __($status)], $status === Password::RESET_LINK_SENT ? 200 : 422); + } + + public function resetPassword(Request $request) + { + $credentials = $request->validate([ + 'token' => 'required|string', 'email' => 'required|email', 'password' => 'required|string|min:3|confirmed', + ]); + $status = $this->authentication->resetPassword($credentials); + return response()->json(['message' => __($status)], $status === Password::PASSWORD_RESET ? 200 : 422); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Api/ClientController.php b/app/Http/Controllers/Api/ClientController.php new file mode 100644 index 0000000..5ed7a61 --- /dev/null +++ b/app/Http/Controllers/Api/ClientController.php @@ -0,0 +1,140 @@ + + * @since 2025/11 + * @version 2025/11 + */ + public function index(Request $request) + { + if ($request->has('per_page')) { + return response()->json(['clients' => $this->clients->listing($request, true)]); + } + $clients = $this->clients->listing($request)->map(function ($client) { + return [ + 'id' => $client->id, + 'type' => $client->type, + 'lead_status_id' => $client->lead_status_id, + 'client_type_id' => $client->client_type_id, + 'name' => $client->name, + 'tax_number' => $client->tax_number, + 'address' => $client->address, + 'phone' => $client->phone, + 'email' => $client->email, + 'seller_id' => $client->seller_id, + 'status' => $client->status, + 'notes' => $client->notes, + 'contact_info' => $client->contact_info, + 'created_at' => $client->created_at, + 'updated_at' => $client->updated_at, + ]; + }); + + return response()->json(['clients' => $clients]); + } + + /** + * Apply filters to the clients query + * + * @author Luis Medon + * @since 2025/11 + * @version 2025/11 + */ + /** + * Show a single client + * + * @author Luis Medon + * @since 2025/11 + * @version 2025/11 + */ + public function show($id) + { + return response()->json($this->clients->find($id)); + } + + /** + * Store a new client + * + * @author Luis Medon + * @since 2025/11 + * @version 2025/11 + */ + public function store(CreateClientRequest $request) + { + $client = $this->clients->create($request->validated()); + + return response()->json([ + 'message' => 'Client created successfully', + 'client' => $client + ], 201); + } + + /** + * Update an existing client + * + * @author Luis Medon + * @since 2025/11 + * @version 2025/11 + */ + public function update(UpdateClientRequest $request, $id) + { + $client = $this->clients->update($id, $request->validated()); + + return response()->json([ + 'message' => 'Client updated successfully', + 'client' => $client + ]); + } + + /** + * Delete a client (soft delete by changing status) + * + * @author Luis Medon + * @since 2025/11 + * @version 2025/11 + */ + public function destroy($id) + { + $this->clients->delete($id); + + return response()->json(['message' => 'Client deleted successfully']); + } + + public function options(Request $request) + { + return response()->json($request->filled('type') + ? $this->clients->form($request->input('type'), $request->user()) + : ['clientTypes' => $this->clients->types()]); + } + + public function detail($id) + { + return response()->json($this->clients->detail($id)); + } + + public function searchName(Request $request) + { + return response()->json($this->clients->searchName($request->input('term', ''))); + } + + public function searchID(Request $request) + { + return response()->json($this->clients->searchID($request->input('id'))); + } +} diff --git a/app/Http/Controllers/Api/ContractController.php b/app/Http/Controllers/Api/ContractController.php new file mode 100644 index 0000000..6189b86 --- /dev/null +++ b/app/Http/Controllers/Api/ContractController.php @@ -0,0 +1,92 @@ +json($this->contracts->index($request)); + } + + public function options(Request $request) + { + return response()->json($this->contracts->create($request)); + } + + public function show(string $id) + { + return response()->json($this->contracts->show($id)); + } + + public function edit(string $id) + { + return response()->json($this->contracts->edit($id)); + } + + public function store(ContractRequest $request) + { + return response()->json(['contract' => $this->contracts->store($request)], 201); + } + + public function update(ContractRequest $request, string $id) + { + return response()->json(['contract' => $this->contracts->update($request, $id)]); + } + + public function renewalOptions(string $id) + { + return response()->json($this->contracts->renewForm($id)); + } + + public function renew(RenewContractRequest $request, $id) + { + return response()->json(['contract' => $this->contracts->renew($request, $id)]); + } + + public function history($id) + { + return response()->json($this->contracts->history($id)); + } + + public function showHistory($id, $historyId) + { + return response()->json($this->contracts->editHistory($id, $historyId)); + } + + public function updateHistory(Request $request, $id, $historyId) + { + return response()->json(['history' => $this->contracts->updateHistory($request, $id, $historyId)]); + } + + public function destroyHistory($id, $historyId) + { + $this->contracts->destroyHistory($id, $historyId); + return response()->json(['message' => 'Registo eliminado com sucesso.']); + } + + public function destroy(string $id) + { + return response()->json($this->contracts->destroy($id)); + } + + public function bulkDestroy(Request $request) + { + return response()->json($this->contracts->bulkDestroy($request)); + } + + public function export(Request $request) + { + return $this->contracts->export($request); + } +} diff --git a/app/Http/Controllers/Api/DashboardController.php b/app/Http/Controllers/Api/DashboardController.php new file mode 100644 index 0000000..7ac0141 --- /dev/null +++ b/app/Http/Controllers/Api/DashboardController.php @@ -0,0 +1,21 @@ +json($dashboard->index()); + } + + public function analytics(Request $request, AnalyticalService $analytics) + { + return response()->json($analytics->index($request)); + } +} diff --git a/app/Http/Controllers/Api/LeadController.php b/app/Http/Controllers/Api/LeadController.php new file mode 100644 index 0000000..1279b56 --- /dev/null +++ b/app/Http/Controllers/Api/LeadController.php @@ -0,0 +1,49 @@ +json($this->leads->list()); + } + + public function options() + { + return response()->json($this->leads->create()); + } + + public function show($id) + { + return response()->json($this->leads->show($id)); + } + + public function store(LeadRequest $request) + { + return response()->json(['lead' => $this->leads->store($request)], 201); + } + + public function update(LeadRequest $request, $id) + { + return response()->json(['lead' => $this->leads->update($request, $id)]); + } + + public function convert($id) + { + return response()->json(['client' => $this->leads->convert($id)]); + } + + public function destroy($id) + { + return response()->json($this->leads->destroy($id)); + } +} diff --git a/app/Http/Controllers/Api/ResourceController.php b/app/Http/Controllers/Api/ResourceController.php new file mode 100644 index 0000000..95019c5 --- /dev/null +++ b/app/Http/Controllers/Api/ResourceController.php @@ -0,0 +1,40 @@ +json(['data' => $this->resources->all($resource)]); + } + + public function show(string $resource, $id) + { + return response()->json(['data' => $this->resources->find($resource, $id)]); + } + + public function store(Request $request, string $resource) + { + return response()->json(['data' => $this->resources->save($resource, $request)], 201); + } + + public function update(Request $request, string $resource, $id) + { + return response()->json(['data' => $this->resources->save($resource, $request, $id)]); + } + + public function destroy(string $resource, $id) + { + $this->resources->delete($resource, $id); + return response()->json(['message' => 'Registo eliminado com sucesso.']); + } +} diff --git a/app/Http/Controllers/Api/UserController.php b/app/Http/Controllers/Api/UserController.php new file mode 100644 index 0000000..fbe47bb --- /dev/null +++ b/app/Http/Controllers/Api/UserController.php @@ -0,0 +1,63 @@ +json($this->users->index()); + } + + public function options() + { + return response()->json($this->users->create()); + } + + public function show(User $user) + { + return response()->json($this->users->edit($user)); + } + + public function store(Request $request) + { + return response()->json(['user' => $this->users->store($request)], 201); + } + + public function update(Request $request, User $user) + { + return response()->json(['user' => $this->users->update($request, $user)]); + } + + public function destroy(User $user) + { + $this->users->destroy($user); + return response()->json(['message' => 'Utilizador removido com sucesso.']); + } + + public function sendPasswordResetLink(User $user) + { + $status = $this->users->sendPasswordResetLink($user); + return response()->json(['message' => __($status)], $status === Password::RESET_LINK_SENT ? 200 : 422); + } + + public function savePin(Request $request) + { + return response()->json($this->users->savePin($request)); + } + + public function checkPin(Request $request) + { + return response()->json($this->users->checkPin($request)); + } +} diff --git a/app/Http/Controllers/Auth/ApiLoginController.php b/app/Http/Controllers/Auth/ApiLoginController.php new file mode 100644 index 0000000..b7a3ac7 --- /dev/null +++ b/app/Http/Controllers/Auth/ApiLoginController.php @@ -0,0 +1,77 @@ + + * @since 2025/11 + * @version 2025/11 + */ + public function showLoginForm() + { + // Prevent proxies/CDN from caching a page with a CSRF token tied to another visitor's session + return response()->view('auth.login') + ->header('Cache-Control', 'no-store, no-cache, must-revalidate, private') + ->header('Pragma', 'no-cache'); + } + + /** + * @author Luis Medon + * @since 2025/11 + * @version 2025/11 + */ + public function login(Request $request) + { + $request->validate([ + 'email' => 'required|email', + 'password' => 'required', + ]); + + try { + $user = $this->authentication->authenticate($request->only('email', 'password')); + } catch (HttpException $exception) { + return back()->withInput($request->only('email'))->with('error', 'Credenciais invalidas.'); + } + + $data = $this->authentication->issueToken($user); + + Auth::login($user); + $request->session()->regenerate(); + + session([ + 'api_token' => $data['token'], + ]); + + return redirect()->route('home'); + } + + + /** + * @author Luis Medon + * @since 2025/11 + * @version 2025/11 + */ + public function logout(Request $request) + { + if ($request->user() && session('api_token')) { + $this->authentication->revoke($this->authentication->sessionToken($request->user(), session('api_token'))); + } + + Auth::logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + return redirect()->route('login'); + } +} diff --git a/app/Http/Controllers/Auth/ConfirmPasswordController.php b/app/Http/Controllers/Auth/ConfirmPasswordController.php new file mode 100644 index 0000000..3559954 --- /dev/null +++ b/app/Http/Controllers/Auth/ConfirmPasswordController.php @@ -0,0 +1,39 @@ +middleware('auth'); + } +} diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php new file mode 100644 index 0000000..b5d0fc6 --- /dev/null +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -0,0 +1,34 @@ +validate(['email' => 'required|email']); + $status = $authentication->sendResetLink($credentials); + return $status === Password::RESET_LINK_SENT + ? back()->with('status', __($status)) + : back()->withErrors(['email' => __($status)]); + } +} diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php new file mode 100644 index 0000000..4e49546 --- /dev/null +++ b/app/Http/Controllers/Auth/LoginController.php @@ -0,0 +1,40 @@ +middleware('guest')->except('logout'); + $this->middleware('auth')->only('logout'); + } +} diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php new file mode 100644 index 0000000..ab7ef63 --- /dev/null +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -0,0 +1,72 @@ +middleware('guest'); + } + + /** + * Get a validator for an incoming registration request. + * + * @param array $data + * @return \Illuminate\Contracts\Validation\Validator + */ + protected function validator(array $data) + { + return Validator::make($data, [ + 'name' => ['required', 'string', 'max:255'], + 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], + 'password' => ['required', 'string', 'min:8', 'confirmed'], + ]); + } + + /** + * Create a new user instance after a valid registration. + * + * @param array $data + * @return \App\Models\User + */ + protected function create(array $data) + { + return User::create([ + 'name' => $data['name'], + 'email' => $data['email'], + 'password' => Hash::make($data['password']), + ]); + } +} diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php new file mode 100644 index 0000000..1a8243a --- /dev/null +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -0,0 +1,50 @@ +validate($this->rules()); + $status = $authentication->resetPassword($credentials); + return $status === Password::PASSWORD_RESET + ? redirect()->route('login')->with('status', __($status)) + : back()->withErrors(['email' => __($status)])->withInput($request->only('email')); + } + + protected function rules() + { + return [ + 'token' => 'required', + 'email' => 'required|email', + 'password' => ['required', 'string', 'min:3', 'confirmed'], + ]; + } +} diff --git a/app/Http/Controllers/Auth/VerificationController.php b/app/Http/Controllers/Auth/VerificationController.php new file mode 100644 index 0000000..23a43a8 --- /dev/null +++ b/app/Http/Controllers/Auth/VerificationController.php @@ -0,0 +1,41 @@ +middleware('auth'); + $this->middleware('signed')->only('verify'); + $this->middleware('throttle:6,1')->only('verify', 'resend'); + } +} diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php new file mode 100644 index 0000000..26f2c8e --- /dev/null +++ b/app/Http/Controllers/ClientController.php @@ -0,0 +1,79 @@ +clients->listing($request, true); + $clientTypes = $this->clients->types(); + + return view('web.clients.list', compact('clients', 'clientTypes')); + } + + public function destroy($id) + { + $this->clients->delete($id); + + return response()->json([ + 'description' => 'Cliente eliminado com sucesso', + 'status' => 'success' + ], 200); + } + + public function add() + { + $clientTypes = $this->clients->types(); + + return view('web.clients.create.add', compact('clientTypes')); + } + + public function add2step(Request $request, $type) + { + return view('web.clients.create.form', $this->clients->form($type, $request->user())); + } + + public function store(CreateClientRequest $request) + { + $client = $this->clients->create($request->validated()); + + return redirect()->route('client.detail', ['id' => $client->id]) + ->with('success', 'Cliente criado com sucesso!'); + } + + public function detail($clientId) + { + return view('web.clients.detail', $this->clients->detail($clientId)); + } + + + public function update(UpdateClientRequest $request, $id) + { + $this->clients->update($id, $request->validated()); + + return redirect()->back()->with('success', 'Cliente atualizado com sucesso!'); + } + + public function searchName(Request $request) + { + return response()->json($this->clients->searchName($request->input('term', ''))); + } + + public function searchID(Request $request) + { + return response()->json($this->clients->searchID($request->input('id'))); + } + + + +} diff --git a/app/Http/Controllers/ContractController.php b/app/Http/Controllers/ContractController.php new file mode 100644 index 0000000..e5a5256 --- /dev/null +++ b/app/Http/Controllers/ContractController.php @@ -0,0 +1,107 @@ +contracts->index($request)); + } + + public function create(Request $request) + { + return view('web.contract.add_edit', $this->contracts->create($request)); + } + + public function store(ContractRequest $request) + { + $contract = $this->contracts->store($request); + return redirect()->route('client.detail', ['id' => $contract->client_id])->with('success', 'Contrato criado com sucesso!'); + } + + public function edit(string $id) + { + return view('web.contract.add_edit', $this->contracts->edit($id)); + } + + public function update(ContractRequest $request, string $id) + { + $this->contracts->update($request, $id); + return redirect()->route('contract.list')->with('success', 'Contrato atualizado com sucesso!'); + } + + public function show(string $id) + { + return view('web.contract.detail', $this->contracts->show($id)); + } + + public function renewForm(string $id) + { + return view('web.contract.renew', $this->contracts->renewForm($id)); + } + + public function renew(RenewContractRequest $request, $id) + { + $contract = $this->contracts->renew($request, $id); + return redirect()->route('contract.edit', ['id' => $contract->id])->with('success', 'Contrato renovado com sucesso!'); + } + + public function history($id) + { + return view('web.contract.history', $this->contracts->history($id)); + } + + public function createHistory($id) + { + return view('web.contract.history_create', $this->contracts->createHistory($id)); + } + + public function storeHistory(Request $request, $id) + { + $this->contracts->storeHistory($request, $id); + return redirect()->route('contract.history', $id)->with('success', 'Registo do histórico criado com sucesso.'); + } + + public function editHistory($id, $historyId) + { + return view('web.contract.history_edit', $this->contracts->editHistory($id, $historyId)); + } + + public function updateHistory(Request $request, $id, $historyId) + { + $this->contracts->updateHistory($request, $id, $historyId); + return redirect()->route('contract.history', $id)->with('success', 'Registo do histórico atualizado com sucesso.'); + } + + public function destroyHistory($id, $historyId) + { + $this->contracts->destroyHistory($id, $historyId); + return redirect()->route('contract.history', $id)->with('success', 'Registo do histórico eliminado com sucesso.'); + } + + public function export(Request $request) + { + return $this->contracts->export($request); + } + + public function destroy(Request $request, string $id) + { + $result = $this->contracts->destroy($id); + return $request->ajax() ? response()->json($result) : back()->with('success', $result['message']); + } + + public function bulkDestroy(Request $request) + { + return response()->json($this->contracts->bulkDestroy($request)); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php new file mode 100644 index 0000000..77ec359 --- /dev/null +++ b/app/Http/Controllers/Controller.php @@ -0,0 +1,12 @@ + 'luismedon@gmail.com', + 'subject' => 'Teste Completo de Envio de E-mail', + 'body' => 'Este é um e-mail de teste completo enviado via Laravel.', + 'status' => 'pendente', + 'error' => null, + 'sent_at' => now()->toDateTimeString(), + ]; + + try { + Mail::raw($emailData['body'], function ($message) use (&$emailData) { + $message->to($emailData['to']) + ->subject($emailData['subject']); + }); + + $emailData['status'] = 'enviado com sucesso'; + } catch (\Exception $e) { + $emailData['status'] = 'falha ao enviar'; + $emailData['error'] = $e->getMessage(); + Log::error('Erro ao enviar e-mail de teste: ' . $e->getMessage()); + } + + $emailData['execution_time'] = round(microtime(true) - $start, 4); + + $emailData['mail_config'] = [ + 'driver' => config('mail.default'), + 'host' => config('mail.mailers.smtp.host'), + 'port' => config('mail.mailers.smtp.port'), + 'encryption' => config('mail.mailers.smtp.encryption'), + 'username' => config('mail.mailers.smtp.username'), + 'from' => config('mail.from.address'), + 'from_name' => config('mail.from.name'), + 'timeout' => config('mail.mailers.smtp.timeout') ?? 'padrão', + ]; + + $emailData['laravel_info'] = [ + 'laravel_version' => app()->version(), + 'php_version' => phpversion(), + 'env' => App::environment(), + 'mailer_class' => get_class(app()->make('mailer')->getSymfonyTransport()), + ]; + + return view('emails.test-status', compact('emailData')); + } +} diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php new file mode 100644 index 0000000..0e531dc --- /dev/null +++ b/app/Http/Controllers/HomeController.php @@ -0,0 +1,17 @@ +dashboard->index()); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/LeadController.php b/app/Http/Controllers/LeadController.php new file mode 100644 index 0000000..9918415 --- /dev/null +++ b/app/Http/Controllers/LeadController.php @@ -0,0 +1,56 @@ +leads->list()); + } + + public function show($id) + { + return view('web.lead.show', $this->leads->show($id)); + } + + public function create() + { + return view('web.lead.add_edit', $this->leads->create()); + } + + public function edit($id) + { + return view('web.lead.add_edit', $this->leads->edit($id)); + } + + public function store(LeadRequest $request) + { + $this->leads->store($request); + return redirect()->route('lead.list')->with('success', 'Lead criado com sucesso!'); + } + + public function update(LeadRequest $request, $id) + { + $this->leads->update($request, $id); + return redirect()->route('lead.list')->with('success', 'Lead atualizado com sucesso!'); + } + + public function convert($id) + { + $this->leads->convert($id); + return redirect()->route('lead.list')->with('success', 'Lead successfully converted to client!'); + } + + public function destroy($id) + { + return response()->json($this->leads->destroy($id)); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Resources/ContractStatusController.php b/app/Http/Controllers/Resources/ContractStatusController.php new file mode 100644 index 0000000..2e92aa3 --- /dev/null +++ b/app/Http/Controllers/Resources/ContractStatusController.php @@ -0,0 +1,11 @@ +viewPath . '.index', [$this->collectionName => $this->resources->all($this->resource)]); + } + + public function create() + { + return view($this->viewPath . '.add_edit'); + } + + public function show($id) + { + return $this->edit($id); + } + + public function edit($id) + { + return view($this->viewPath . '.add_edit', [$this->itemName => $this->resources->find($this->resource, $id)]); + } + + public function store(Request $request) + { + $this->resources->save($this->resource, $request); + return redirect()->route($this->resource . '.index')->with('success', 'Registo criado com sucesso.'); + } + + public function update(Request $request, $id) + { + $this->resources->save($this->resource, $request, $id); + return redirect()->route($this->resource . '.index')->with('success', 'Registo atualizado com sucesso.'); + } + + public function destroy($id) + { + $this->resources->delete($this->resource, $id); + return redirect()->route($this->resource . '.index')->with('success', 'Registo eliminado com sucesso.'); + } +} diff --git a/app/Http/Controllers/Resources/SupplierController.php b/app/Http/Controllers/Resources/SupplierController.php new file mode 100644 index 0000000..5a2d1c7 --- /dev/null +++ b/app/Http/Controllers/Resources/SupplierController.php @@ -0,0 +1,11 @@ +access->index()); + } + + public function updatePermissions(Request $request, Role $role) + { + $this->access->updatePermissions($request, $role); + return back()->with('success', 'Permissoes atualizadas.'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/UserAccessController.php b/app/Http/Controllers/UserAccessController.php new file mode 100644 index 0000000..c744e9c --- /dev/null +++ b/app/Http/Controllers/UserAccessController.php @@ -0,0 +1,25 @@ +access->index()); + } + + public function updateRoles(Request $request, User $user) + { + $this->access->updateRoles($request, $user); + return back()->with('success', 'Roles atualizadas.'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php new file mode 100644 index 0000000..8b216e4 --- /dev/null +++ b/app/Http/Controllers/UserController.php @@ -0,0 +1,65 @@ +users->index()); + } + + public function create() + { + return view('auth.register', $this->users->create()); + } + + public function store(Request $request) + { + $this->users->store($request); + return redirect()->route('users.index')->with('success', 'Utilizador criado com sucesso.'); + } + + public function edit(User $user) + { + return view('web.admin.user.add_edit', $this->users->edit($user)); + } + + public function update(Request $request, User $user) + { + $this->users->update($request, $user); + return redirect()->route('users.index')->with('success', 'Utilizador atualizado com sucesso.'); + } + + public function destroy(User $user) + { + $this->users->destroy($user); + return redirect()->route('users.index')->with('success', 'Utilizador removido com sucesso.'); + } + + public function sendPasswordResetLink(User $user) + { + $status = $this->users->sendPasswordResetLink($user); + return redirect()->route('users.edit', $user)->with($status === Password::RESET_LINK_SENT ? 'success' : 'error', __($status)); + } + + public function savePin(Request $request) + { + $result = $this->users->savePin($request); + return back()->with('success', $result['message']); + } + + public function checkPin(Request $request) + { + return response()->json($this->users->checkPin($request)); + } +} \ No newline at end of file diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php new file mode 100644 index 0000000..28bda63 --- /dev/null +++ b/app/Http/Kernel.php @@ -0,0 +1,40 @@ + [ + \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, + \Illuminate\Session\Middleware\StartSession::class, + \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \Illuminate\Routing\Middleware\SubstituteBindings::class + ], + + + 'api' => [ + \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, + \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', + \Illuminate\Routing\Middleware\SubstituteBindings::class, + ], + ]; + + protected $middlewareAliases = [ + 'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class, + 'role' => \Spatie\Permission\Middleware\RoleMiddleware::class, + 'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class, + 'can' => \Illuminate\Auth\Middleware\Authorize::class, + 'auth.session' => \App\Http\Middleware\AuthSession::class + ]; +} diff --git a/app/Http/Middleware/ApiResponse.php b/app/Http/Middleware/ApiResponse.php new file mode 100644 index 0000000..9b8e4b1 --- /dev/null +++ b/app/Http/Middleware/ApiResponse.php @@ -0,0 +1,45 @@ +headers->set('Accept', 'application/json'); + $response = $next($request); + if ($response instanceof JsonResponse && $request->is('api/contracts*', 'api/clients*', 'api/dashboard', 'api/analytics', 'api/leads*') + && $request->user() && !$request->user()->can('view_contract_summary')) { + $response->setData($this->withoutFinancials($response->getData(true))); + } + $response->headers->set('Cache-Control', 'no-store, private'); + return $response; + } + + private function withoutFinancials($data) + { + if (!is_array($data)) { + return $data; + } + foreach ($data as $key => $value) { + if (in_array($key, self::FINANCIAL_FIELDS, true)) { + unset($data[$key]); + } else { + $data[$key] = $this->withoutFinancials($value); + } + } + return $data; + } +} diff --git a/app/Http/Middleware/AuthSession.php b/app/Http/Middleware/AuthSession.php new file mode 100644 index 0000000..d9c52ab --- /dev/null +++ b/app/Http/Middleware/AuthSession.php @@ -0,0 +1,31 @@ +user(); + $plainText = $request->session()->get('api_token'); + $token = $user && $plainText ? $this->authentication->sessionToken($user, $plainText) : null; + if (!$token) { + Auth::logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + return redirect()->route('login'); + } + $result = $this->authentication->refresh($token); + $request->session()->put('token_expires_at', $result['expires_at']); + return $next($request); + } +} \ No newline at end of file diff --git a/app/Http/Middleware/EnsureApiUser.php b/app/Http/Middleware/EnsureApiUser.php new file mode 100644 index 0000000..3d12cf6 --- /dev/null +++ b/app/Http/Middleware/EnsureApiUser.php @@ -0,0 +1,15 @@ +user()->can_login === false, 401, 'Conta desativada.'); + return $next($request); + } +} diff --git a/app/Http/Requests/ContractRequest.php b/app/Http/Requests/ContractRequest.php new file mode 100644 index 0000000..4af543f --- /dev/null +++ b/app/Http/Requests/ContractRequest.php @@ -0,0 +1,196 @@ +bound('translator')) { + return __($key, [], app()->getLocale()) ?: $fallback; + } + + return $fallback; + } + + public function authorize(): bool + { + return true; + } + + protected function prepareForValidation(): void + { + foreach (['validity', 'contract_end_date', 'contract_date', 'activation_date', 'chargeback_date', 'payment_date', 'renewal_date'] as $field) { + $value = $this->input($field); + + if ($value) { + try { + $date = str_contains((string) $value, '/') + ? Carbon::createFromFormat('d/m/Y', $value) + : Carbon::parse($value); + $this->merge([$field => $date->format('Y-m-d')]); + } catch (\Throwable) { + // Mantém o valor original para o validador apresentar a mensagem adequada. + } + } + } + + if ($this->filled('chargeback_value')) { + $this->merge(['chargeback' => true]); + } + } + + public function rules(): array + { + $rules = [ + 'client_id' => ['required', 'exists:clients,id'], + 'contract_value' => ['nullable', 'numeric', 'min:0'], + 'commission_value' => ['nullable', 'numeric',], + 'profit_value' => ['nullable', 'numeric'], + 'seller_id' => ['nullable', 'exists:users,id'], + 'supply_type' => ['required', 'in:cpe,cui'], + 'supply_address' => ['nullable', 'string', 'max:255'], + 'annual_consumption' => ['nullable', 'numeric', 'min:0'], + 'code' => ['required', 'string', 'max:255'], + 'contract_type_id' => ['required', 'exists:contract_types,id'], + 'validity' => ['nullable', 'date'], + 'contract_end_date' => ['nullable', 'date'], + 'contract_date' => ['nullable', 'date'], + 'activation_date' => ['nullable', 'date'], + 'status_id' => ['required', 'exists:contract_status,id'], + 'commission_rate' => ['nullable', 'numeric', 'between:0,100'], + 'notes' => ['nullable', 'string'], + 'power_tier_id' => ['nullable', 'exists:power_tiers,id'], + 'payment_method_id' => ['required', 'exists:payment_methods,id'], + 'delivery_method' => ['required', 'in:correio,email'], + 'delivery_email' => ['nullable', 'email', 'max:255'], + 'previous_supplier_id' => ['nullable', 'exists:suppliers,id'], + 'new_supplier_id' => ['nullable', 'exists:suppliers,id'], + 'typology_id' => ['nullable', 'exists:typologies,id'], + 'cui_tier_id' => ['nullable', 'exists:cui_tiers,id'], + 'go_ki' => ['required', 'numeric'], + 'paid' => ['nullable', 'boolean'], + 'chargeback' => ['nullable', 'boolean'], + 'chargeback_value' => ['required_if:chargeback,1', 'nullable', 'numeric', 'max:-0.01'], + 'chargeback_date' => ['required_if:chargeback,1', 'nullable', 'date'], + + // Parcelas + 'installments.*.due_date' => ['nullable', 'date'], + 'installments.*.amount' => ['nullable', 'numeric', 'min:0'], + 'installments.*.paid' => ['nullable', 'boolean'], + ]; + + if (! $this->user()?->can('view_contract_summary')) { + foreach (['contract_value', 'commission_value', 'profit_value', 'paid', 'chargeback', 'chargeback_value', 'chargeback_date', 'installments.*.due_date', 'installments.*.amount', 'installments.*.paid'] as $field) { + unset($rules[$field]); + } + } + + return $rules; + } + + public function withValidator(Validator $validator) + { + $validator->after(function ($validator) { + if (! $this->user()?->can('view_contract_summary')) { + return; + } + + $installments = $this->input('installments', []); + $validity = $this->input('validity'); + + $previousDate = null; + foreach ($installments as $index => $installment) { + if (!empty($installment['due_date'])) { + $dueDate = Carbon::parse($installment['due_date']); + + // Data da parcela não pode ser superior à validade do contrato + // if (!empty($validity)) { + // $validityDate = Carbon::createFromFormat('d/m/Y', $validity); + // if ($dueDate->gt($validityDate)) { + // $validator->errors()->add( + // "installments.$index.due_date", + // "A data da parcela $index não pode ser superior à data de renovação do contrato." + // ); + // } + // } + + // Data da parcela deve ser superior à anterior + if ($previousDate && $dueDate->lte($previousDate)) { + $validator->errors()->add( + "installments.$index.due_date", + "A data da parcela $index deve ser superior à parcela anterior." + ); + } + + $previousDate = $dueDate; + } + } + }); + } + + public function messages(): array + { + return [ + 'cui_tier_id.exists' => $this->localizedMessage('validation.custom.cui_tier_id.exists', 'O escalão CUI selecionado não é válido.'), + 'client_id.required' => $this->localizedMessage('validation.custom.client_id.required', 'O cliente é obrigatório.'), + 'client_id.exists' => $this->localizedMessage('validation.custom.client_id.exists', 'O cliente selecionado não é válido.'), + 'contract_value.numeric' => $this->localizedMessage('validation.custom.contract_value.numeric', 'O valor do contrato deve ser um número.'), + 'contract_value.min' => $this->localizedMessage('validation.custom.contract_value.min', 'O valor do contrato não pode ser negativo.'), + 'go_ki.required' => $this->localizedMessage('validation.custom.go_ki.required', 'O campo GO/KI é obrigatório.'), + 'go_ki.numeric' => $this->localizedMessage('validation.custom.go_ki.numeric', 'O campo GO/KI deve ser numérico.'), + 'commission_value.numeric' => $this->localizedMessage('validation.custom.commission_value.numeric', 'O valor da comissão deve ser um número.'), + 'profit_value.numeric' => $this->localizedMessage('validation.custom.profit_value.numeric', 'O lucro deve ser um número.'), + 'seller_id.exists' => $this->localizedMessage('validation.custom.seller_id.exists', 'O vendedor selecionado não é válido.'), + 'supply_type.required' => $this->localizedMessage('validation.custom.supply_type.required', 'O tipo de fornecimento é obrigatório.'), + 'supply_type.in' => $this->localizedMessage('validation.custom.supply_type.in', 'O tipo de fornecimento deve ser CPE ou cui.'), + 'supply_address.string' => $this->localizedMessage('validation.custom.supply_address.string', 'O endereço de fornecimento deve ser texto.'), + 'supply_address.max' => $this->localizedMessage('validation.custom.supply_address.max', 'O endereço de fornecimento não pode exceder 255 caracteres.'), + 'annual_consumption.numeric' => $this->localizedMessage('validation.custom.annual_consumption.numeric', 'O consumo anual deve ser numérico.'), + 'annual_consumption.min' => $this->localizedMessage('validation.custom.annual_consumption.min', 'O consumo anual não pode ser negativo.'), + 'contract_type_id.required' => $this->localizedMessage('validation.custom.contract_type_id.required', 'O tipo de contrato é obrigatório.'), + 'contract_type_id.exists' => $this->localizedMessage('validation.custom.contract_type_id.exists', 'O tipo de contrato selecionado não é válido.'), + 'validity.date' => $this->localizedMessage('validation.custom.validity.date', 'A validade deve ser uma data válida.'), + 'validity.date_format' => $this->localizedMessage('validation.custom.validity.date_format', 'A validade deve estar no formato DD/MM/AAAA.'), + 'contract_end_date.date' => $this->localizedMessage('validation.custom.contract_end_date.date', 'A data de fim do contrato deve ser válida.'), + 'contract_end_date.date_format' => $this->localizedMessage('validation.custom.contract_end_date.date_format', 'A data de fim de contrato deve estar no formato DD/MM/AAAA.'), + 'contract_date.date' => $this->localizedMessage('validation.custom.contract_date.date', 'A data do contrato deve ser válida.'), + 'contract_date.date_format' => $this->localizedMessage('validation.custom.contract_date.date_format', 'A data do contrato deve estar no formato DD/MM/AAAA.'), + 'activation_date.date' => $this->localizedMessage('validation.custom.activation_date.date', 'A data de ativação deve ser válida.'), + 'activation_date.date_format' => $this->localizedMessage('validation.custom.activation_date.date_format', 'A data de ativação deve estar no formato DD/MM/AAAA.'), + 'status_id.required' => $this->localizedMessage('validation.custom.status_id.required', 'O estado do contrato é obrigatório.'), + 'status_id.exists' => $this->localizedMessage('validation.custom.status_id.exists', 'O estado do contrato selecionado não é válido.'), + 'commission_rate.numeric' => $this->localizedMessage('validation.custom.commission_rate.numeric', 'A percentagem da comissão deve ser um número.'), + 'commission_rate.between' => $this->localizedMessage('validation.custom.commission_rate.between', 'A percentagem da comissão deve estar entre 0 e 100.'), + 'notes.string' => $this->localizedMessage('validation.custom.notes.string', 'As notas devem ser texto.'), + 'power_tier_id.exists' => $this->localizedMessage('validation.custom.power_tier_id.exists', 'O escalão de potência selecionado não é válido.'), + 'payment_method_id.required' => $this->localizedMessage('validation.custom.payment_method_id.required', 'O método de pagamento é obrigatório.'), + 'payment_method_id.exists' => $this->localizedMessage('validation.custom.payment_method_id.exists', 'O método de pagamento selecionado não é válido.'), + 'delivery_method.required' => $this->localizedMessage('validation.custom.delivery_method.required', 'O método de envio é obrigatório.'), + 'delivery_method.in' => $this->localizedMessage('validation.custom.delivery_method.in', 'O método de envio deve ser "correio" ou "email".'), + 'delivery_email.email' => $this->localizedMessage('validation.custom.delivery_email.email', 'O e-mail de envio deve ser válido.'), + 'delivery_email.max' => $this->localizedMessage('validation.custom.delivery_email.max', 'O e-mail de envio não pode exceder 255 caracteres.'), + 'previous_supplier_id.exists' => $this->localizedMessage('validation.custom.previous_supplier_id.exists', 'O fornecedor anterior selecionado não é válido.'), + 'new_supplier_id.exists' => $this->localizedMessage('validation.custom.new_supplier_id.exists', 'O novo fornecedor selecionado não é válido.'), + 'paid.required' => $this->localizedMessage('validation.custom.paid.required', 'O campo "Pago" é obrigatório.'), + 'paid.boolean' => $this->localizedMessage('validation.custom.paid.boolean', 'O campo "Pago" deve ser verdadeiro ou falso.'), + 'chargeback.boolean' => $this->localizedMessage('validation.custom.chargeback.boolean', 'O campo "Chargeback" deve ser verdadeiro ou falso.'), + 'chargeback_value.required_if' => $this->localizedMessage('validation.custom.chargeback_value.required_if', 'O valor do chargeback é obrigatório.'), + 'chargeback_value.numeric' => $this->localizedMessage('validation.custom.chargeback_value.numeric', 'O valor do chargeback deve ser numérico.'), + 'chargeback_value.max' => $this->localizedMessage('validation.custom.chargeback_value.max', 'O valor do chargeback deve ser negativo.'), + 'chargeback_date.required_if' => $this->localizedMessage('validation.custom.chargeback_date.required_if', 'A data de chargeback é obrigatória.'), + 'chargeback_date.date' => $this->localizedMessage('validation.custom.chargeback_date.date', 'A data de chargeback deve ser uma data válida.'), + 'chargeback_date.date_format' => $this->localizedMessage('validation.custom.chargeback_date.date_format', 'A data de chargeback deve estar no formato DD/MM/AAAA.'), + 'installments.*.due_date.required_with' => $this->localizedMessage('validation.custom.installments_due_date.required_with', 'A data da parcela é obrigatória quando o valor está preenchido.'), + 'installments.*.due_date.date' => $this->localizedMessage('validation.custom.installments_due_date.date', 'A data da parcela deve ser uma data válida.'), + 'installments.*.due_date.date_format' => $this->localizedMessage('validation.custom.installments_due_date.date_format', 'A data da parcela deve estar no formato DD/MM/AAAA.'), + 'installments.*.amount.required_with' => $this->localizedMessage('validation.custom.installments_amount.required_with', 'O valor da parcela é obrigatório quando a data está preenchida.'), + 'installments.*.amount.numeric' => $this->localizedMessage('validation.custom.installments_amount.numeric', 'O valor da parcela deve ser numérico.'), + 'installments.*.amount.min' => $this->localizedMessage('validation.custom.installments_amount.min', 'O valor da parcela não pode ser negativo.'), + ]; + } +} diff --git a/app/Http/Requests/CreateClientRequest.php b/app/Http/Requests/CreateClientRequest.php new file mode 100644 index 0000000..031c1b5 --- /dev/null +++ b/app/Http/Requests/CreateClientRequest.php @@ -0,0 +1,81 @@ +bound('translator')) { + return __($key, [], app()->getLocale()) ?: $fallback; + } + + return $fallback; + } + + /** + * Determine if the user is authorized to make this request. + */ + public function authorize(): bool + { + return true; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array|string> + */ + public function rules(): array + { + return [ + 'name' => 'required|string|max:255', + 'tax_number' => 'required|digits:9|unique:clients,tax_number', + 'email' => 'required|email', + 'phone' => 'required|string|max:20', + 'address' => 'required|string|max:255', + 'contact_info' => 'nullable|string|max:255', + 'notes' => 'nullable|string|max:500', + 'client_type_id' => 'required|exists:client_types,id', + 'seller_id' => 'required|exists:users,id', + 'locality' => 'nullable|string|max:255' + ]; + } + + /** + * Get custom error messages for validation rules. + * + * @return array + */ + public function messages(): array + { + return [ + 'name.required' => $this->localizedMessage('validation.custom.name.required', 'O nome é obrigatório.'), + 'name.string' => $this->localizedMessage('validation.custom.name.string', 'O nome deve ser texto.'), + 'name.max' => $this->localizedMessage('validation.custom.name.max', 'O nome não pode ter mais de 255 caracteres.'), + 'tax_number.required' => $this->localizedMessage('validation.custom.tax_number.required', 'O NIF é obrigatório.'), + 'tax_number.digits' => $this->localizedMessage('validation.custom.tax_number.digits', 'O NIF deve ter 9 dígitos.'), + 'tax_number.unique' => $this->localizedMessage('validation.custom.tax_number.unique', 'Já existe um cliente com este NIF.'), + 'email.required' => $this->localizedMessage('validation.custom.email.required', 'O e-mail é obrigatório.'), + 'email.email' => $this->localizedMessage('validation.custom.email.email', 'O e-mail deve ser válido.'), + 'phone.required' => $this->localizedMessage('validation.custom.phone.required', 'O telefone é obrigatório.'), + 'phone.string' => $this->localizedMessage('validation.custom.phone.string', 'O telefone deve ser texto.'), + 'phone.max' => $this->localizedMessage('validation.custom.phone.max', 'O telefone não pode ter mais de 20 caracteres.'), + 'address.required' => $this->localizedMessage('validation.custom.address.required', 'A morada é obrigatória.'), + 'address.string' => $this->localizedMessage('validation.custom.address.string', 'A morada deve ser texto.'), + 'address.max' => $this->localizedMessage('validation.custom.address.max', 'A morada não pode ter mais de 255 caracteres.'), + 'contact_info.string' => $this->localizedMessage('validation.custom.contact_info.string', 'As informações de contacto devem ser texto.'), + 'contact_info.max' => $this->localizedMessage('validation.custom.contact_info.max', 'As informações de contacto não podem exceder 255 caracteres.'), + 'notes.string' => $this->localizedMessage('validation.custom.notes.string', 'As notas devem ser texto.'), + 'notes.max' => $this->localizedMessage('validation.custom.notes.max', 'As notas não podem exceder 500 caracteres.'), + 'client_type_id.required' => $this->localizedMessage('validation.custom.client_type_id.required', 'O tipo de cliente é obrigatório.'), + 'client_type_id.exists' => $this->localizedMessage('validation.custom.client_type_id.exists', 'O tipo de cliente selecionado não é válido.'), + 'seller_id.required' => $this->localizedMessage('validation.custom.seller_id.required', 'O vendedor é obrigatório.'), + 'seller_id.exists' => $this->localizedMessage('validation.custom.seller_id.exists', 'O vendedor selecionado não é válido.'), + 'locality.string' => $this->localizedMessage('validation.custom.locality.string', 'A localidade deve ser texto.'), + 'locality.max' => $this->localizedMessage('validation.custom.locality.max', 'A localidade não pode ter mais de 255 caracteres.'), + ]; + } +} diff --git a/app/Http/Requests/LeadRequest.php b/app/Http/Requests/LeadRequest.php new file mode 100644 index 0000000..f9e77f5 --- /dev/null +++ b/app/Http/Requests/LeadRequest.php @@ -0,0 +1,72 @@ +bound('translator')) { + return __($key, [], app()->getLocale()) ?: $fallback; + } + + return $fallback; + } + + /** + * Determine if the user is authorized to make this request. + */ + public function authorize(): bool + { + return true; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array|string> + */ + public function rules(): array + { + return [ + 'name' => 'required|string|max:255', + 'email' => 'nullable|email|max:255', + 'phone' => 'nullable|string|max:20', + 'lead_status_id' => 'nullable|exists:lead_status,id', + 'notes' => 'nullable|string', + 'contact_info' => 'nullable|string', + 'address' => 'nullable|string|max:255', + 'contact_date' => 'nullable|date_format:d/m/Y', + 'contract_end_date' => 'nullable|date_format:d/m/Y|after_or_equal:contact_date', + 'contract_type' => 'nullable|in:CPE,CUI', + 'delivery_point_code' => 'nullable' + ]; + } + + public function messages(): array + { + return [ + 'name.required' => $this->localizedMessage('validation.custom.name.required', 'O nome é obrigatório.'), + 'name.string' => $this->localizedMessage('validation.custom.name.string', 'O nome deve ser texto.'), + 'name.max' => $this->localizedMessage('validation.custom.name.max', 'O nome não pode ter mais de 255 caracteres.'), + 'email.email' => $this->localizedMessage('validation.custom.email.email', 'O e-mail deve ser válido.'), + 'email.max' => $this->localizedMessage('validation.custom.email.max', 'O e-mail não pode ter mais de 255 caracteres.'), + 'phone.string' => $this->localizedMessage('validation.custom.phone.string', 'O telefone deve ser texto.'), + 'phone.max' => $this->localizedMessage('validation.custom.phone.max', 'O telefone não pode ter mais de 20 caracteres.'), + 'lead_status_id.exists' => $this->localizedMessage('validation.custom.lead_status_id.exists', 'O estado do lead selecionado não é válido.'), + 'notes.string' => $this->localizedMessage('validation.custom.notes.string', 'As notas devem ser texto.'), + 'contact_info.string' => $this->localizedMessage('validation.custom.contact_info.string', 'As informações de contacto devem ser texto.'), + 'contact_info.max' => $this->localizedMessage('validation.custom.contact_info.max', 'As informações de contacto não podem exceder 255 caracteres.'), + 'address.string' => $this->localizedMessage('validation.custom.address.string', 'A morada deve ser texto.'), + 'address.max' => $this->localizedMessage('validation.custom.address.max', 'A morada não pode ter mais de 255 caracteres.'), + 'contact_date.date' => $this->localizedMessage('validation.custom.contact_date.date', 'A data de contacto deve ser válida.'), + 'contact_date.date_format' => $this->localizedMessage('validation.custom.contact_date.date_format', 'A data de contacto deve estar no formato DD/MM/AAAA.'), + 'contract_end_date.date' => $this->localizedMessage('validation.custom.contract_end_date.date', 'A data de fim do contrato deve ser válida.'), + 'contract_end_date.after_or_equal' => $this->localizedMessage('validation.custom.contract_end_date.after_or_equal', 'A data de fim de contrato deve ser igual ou posterior à data de contacto.'), + 'contract_end_date.date_format' => $this->localizedMessage('validation.custom.contract_end_date.date_format', 'A data de fim de contrato deve estar no formato DD/MM/AAAA.'), + 'contract_type.in' => $this->localizedMessage('validation.custom.contract_type.in', 'O tipo de contrato deve ser CPE ou CUI.'), + ]; + } +} diff --git a/app/Http/Requests/RenewContractRequest.php b/app/Http/Requests/RenewContractRequest.php new file mode 100644 index 0000000..2b734fd --- /dev/null +++ b/app/Http/Requests/RenewContractRequest.php @@ -0,0 +1,83 @@ +bound('translator')) { + return __($key, [], app()->getLocale()) ?: $fallback; + } + + return $fallback; + } + + public function authorize(): bool + { + return true; + } + + protected function prepareForValidation(): void + { + foreach (['next_due_date', 'contract_date', 'activation_date'] as $field) { + $value = $this->input($field); + + if ($value && str_contains($value, '/')) { + try { + $this->merge([ + $field => Carbon::createFromFormat('d/m/Y', $value)->format('Y-m-d'), + ]); + } catch (\Throwable) { + // Mantém o valor original para o validator apresentar a mensagem adequada. + } + } + } + } + + public function rules(): array + { + $rules = [ + 'next_due_date' => ['required', 'date_format:Y-m-d'], + 'annual_consumption' => ['nullable', 'numeric'], + 'contract_type_id' => ['required', 'exists:contract_types,id'], + 'typology_id' => ['nullable', 'exists:typologies,id'], + 'contract_date' => ['nullable', 'date_format:Y-m-d'], + 'activation_date' => ['nullable', 'date_format:Y-m-d'], + 'renewal_type' => ['required', Rule::exists('renewal_types', 'value')], + 'new_supplier_id' => ['required_if:change_supplier,1', 'nullable', 'exists:suppliers,id'], + ]; + + if ($this->user()?->can('view_contract_summary')) { + $rules['amount_paid'] = ['required', 'numeric']; + $rules['commission_value'] = ['nullable', 'numeric']; + } + + return $rules; + } + + public function messages(): array + { + return [ + 'amount_paid.required' => $this->localizedMessage('validation.custom.amount_paid.required', 'O valor do contrato é obrigatório.'), + 'amount_paid.numeric' => $this->localizedMessage('validation.custom.amount_paid.numeric', 'O valor do contrato deve ser um número.'), + 'commission_value.numeric' => $this->localizedMessage('validation.custom.commission_value.numeric', 'A comissão deve ser um número.'), + 'next_due_date.required' => $this->localizedMessage('validation.custom.next_due_date.required', 'A próxima renovação é obrigatória.'), + 'next_due_date.date_format' => $this->localizedMessage('validation.custom.next_due_date.date_format', 'A próxima renovação deve estar no formato DD/MM/AAAA.'), + 'renewal_type.required' => $this->localizedMessage('validation.custom.renewal_type.required', 'O tipo de renovação é obrigatório.'), + 'renewal_type.exists' => $this->localizedMessage('validation.custom.renewal_type.exists', 'O tipo de renovação selecionado não é válido.'), + 'annual_consumption.numeric' => $this->localizedMessage('validation.custom.annual_consumption.numeric', 'O consumo anual deve ser numérico.'), + 'contract_type_id.required' => $this->localizedMessage('validation.custom.contract_type_id.required', 'O tipo de contrato é obrigatório.'), + 'contract_type_id.exists' => $this->localizedMessage('validation.custom.contract_type_id.exists', 'O tipo de contrato selecionado não é válido.'), + 'typology_id.exists' => $this->localizedMessage('validation.custom.typology_id.exists', 'A tipologia selecionada não é válida.'), + 'contract_date.date_format' => $this->localizedMessage('validation.custom.contract_date.date_format', 'A data do contrato deve estar no formato DD/MM/AAAA.'), + 'activation_date.date_format' => $this->localizedMessage('validation.custom.activation_date.date_format', 'A data de ativação deve estar no formato DD/MM/AAAA.'), + 'new_supplier_id.required_if' => $this->localizedMessage('validation.custom.new_supplier_id.required_if', 'O novo fornecedor é obrigatório quando a alteração está ativa.'), + 'new_supplier_id.exists' => $this->localizedMessage('validation.custom.new_supplier_id.exists', 'O novo fornecedor selecionado não é válido.'), + ]; + } +} diff --git a/app/Http/Requests/UpdateClientRequest.php b/app/Http/Requests/UpdateClientRequest.php new file mode 100644 index 0000000..e52186f --- /dev/null +++ b/app/Http/Requests/UpdateClientRequest.php @@ -0,0 +1,83 @@ +bound('translator')) { + return __($key, [], app()->getLocale()) ?: $fallback; + } + + return $fallback; + } + + /** + * Determine if the user is authorized to make this request. + * + * @return bool + */ + public function authorize(): bool + { + return true; + } + + /** + * Get the validation rules that apply to the request. + * + * @return array|string> + */ + public function rules(): array + { + return [ + 'name' => 'required|string|max:255', + 'tax_number' => 'required|digits:9|unique:clients,tax_number,' . $this->route('id'), + 'email' => 'required|email', + 'phone' => 'required|string|max:20', + 'address' => 'required|string|max:255', + 'contact_info' => 'nullable|string|max:255', + 'notes' => 'nullable|string|max:500', + 'seller_id' => 'required|exists:users,id', + 'client_type_id' => 'required|exists:client_types,id', + 'locality' => 'nullable|string|max:255' + ]; + } + + /** + * Get custom error messages for validation rules. + * + * @return array + */ + public function messages(): array + { + return [ + 'name.required' => $this->localizedMessage('validation.custom.name.required', 'O nome é obrigatório.'), + 'name.string' => $this->localizedMessage('validation.custom.name.string', 'O nome deve ser texto.'), + 'name.max' => $this->localizedMessage('validation.custom.name.max', 'O nome não pode ter mais de 255 caracteres.'), + 'tax_number.required' => $this->localizedMessage('validation.custom.tax_number.required', 'O NIF é obrigatório.'), + 'tax_number.digits' => $this->localizedMessage('validation.custom.tax_number.digits', 'O NIF deve ter 9 dígitos.'), + 'tax_number.unique' => $this->localizedMessage('validation.custom.tax_number.unique', 'Já existe um cliente com este NIF.'), + 'email.required' => $this->localizedMessage('validation.custom.email.required', 'O e-mail é obrigatório.'), + 'email.email' => $this->localizedMessage('validation.custom.email.email', 'O e-mail deve ser válido.'), + 'phone.required' => $this->localizedMessage('validation.custom.phone.required', 'O telefone é obrigatório.'), + 'phone.string' => $this->localizedMessage('validation.custom.phone.string', 'O telefone deve ser texto.'), + 'phone.max' => $this->localizedMessage('validation.custom.phone.max', 'O telefone não pode ter mais de 20 caracteres.'), + 'address.required' => $this->localizedMessage('validation.custom.address.required', 'A morada é obrigatória.'), + 'address.string' => $this->localizedMessage('validation.custom.address.string', 'A morada deve ser texto.'), + 'address.max' => $this->localizedMessage('validation.custom.address.max', 'A morada não pode ter mais de 255 caracteres.'), + 'contact_info.string' => $this->localizedMessage('validation.custom.contact_info.string', 'As informações de contacto devem ser texto.'), + 'contact_info.max' => $this->localizedMessage('validation.custom.contact_info.max', 'As informações de contacto não podem exceder 255 caracteres.'), + 'notes.string' => $this->localizedMessage('validation.custom.notes.string', 'As notas devem ser texto.'), + 'notes.max' => $this->localizedMessage('validation.custom.notes.max', 'As notas não podem exceder 500 caracteres.'), + 'seller_id.required' => $this->localizedMessage('validation.custom.seller_id.required', 'O vendedor é obrigatório.'), + 'seller_id.exists' => $this->localizedMessage('validation.custom.seller_id.exists', 'O vendedor selecionado não é válido.'), + 'client_type_id.required' => $this->localizedMessage('validation.custom.client_type_id.required', 'O tipo de cliente é obrigatório.'), + 'client_type_id.exists' => $this->localizedMessage('validation.custom.client_type_id.exists', 'O tipo de cliente selecionado não é válido.'), + 'locality.string' => $this->localizedMessage('validation.custom.locality.string', 'A localidade deve ser texto.'), + 'locality.max' => $this->localizedMessage('validation.custom.locality.max', 'A localidade não pode ter mais de 255 caracteres.'), + ]; + } +} diff --git a/app/Mail/NewUserWelcome.php b/app/Mail/NewUserWelcome.php new file mode 100644 index 0000000..4f5662e --- /dev/null +++ b/app/Mail/NewUserWelcome.php @@ -0,0 +1,28 @@ +user = $user; + $this->password = $password; + } + + public function build() + { + return $this->subject('Conta criada com sucesso') + ->view('emails.new_user_welcome'); + } +} diff --git a/app/Models/CPE.php b/app/Models/CPE.php new file mode 100644 index 0000000..d6626b6 --- /dev/null +++ b/app/Models/CPE.php @@ -0,0 +1,87 @@ + + */ + protected $hidden = [ + 'id' + ]; + + public function client() + { + return $this->belongsTo(Clients::class, 'client_id'); + } + + public function contractType() + { + return $this->belongsTo(ContractType::class, 'contract_type_id'); + } + + public function status() + { + return $this->belongsTo(ContractStatus::class, 'status_id'); + } + + public function payments() + { + return $this->hasMany(CpePayment::class, 'cpe_id'); + } + + + public function totalPaid() + { + return $this->payments()->where('status', 'paid')->sum('amount'); + } + + public function isPaid() + { + return $this->totalPaid() >= $this->pvp; + } + + public function isCurrentRenewalPaid() + { + return $this->payments() + ->where('reference_period', $this->renewal_date?->format('Y-m-d')) + ->where('status', 'paid') + ->exists(); + } + + +} diff --git a/app/Models/ClientType.php b/app/Models/ClientType.php new file mode 100644 index 0000000..ab1ff8c --- /dev/null +++ b/app/Models/ClientType.php @@ -0,0 +1,15 @@ +hasMany(Clients::class); + } +} diff --git a/app/Models/Clients.php b/app/Models/Clients.php new file mode 100644 index 0000000..433e88f --- /dev/null +++ b/app/Models/Clients.php @@ -0,0 +1,71 @@ + + */ + protected $hidden = [ + ]; + + + public function contracts() + { + return $this->hasMany(Contract::class, 'client_id'); + } + + + public function seller(): BelongsTo { + return $this->belongsTo(User::class, 'seller_id'); + } + + public function cpes() + { + return $this->hasMany(Cpe::class); + } + + public function hasUnpaidCpes() + { + return $this->cpes->contains(function ($cpe) { + return !$cpe->isPaid(); + }); + } + + public function clientType() + { + return $this->belongsTo(ClientType::class, 'client_type_id'); + } + + public function leadStatus() + { + return $this->belongsTo(LeadStatus::class, 'lead_status_id'); + } + + public function leadDetail() + { + return $this->hasOne(LeadDetail::class, 'client_id', 'id'); + } +} diff --git a/app/Models/Contract.php b/app/Models/Contract.php new file mode 100644 index 0000000..7dc3f66 --- /dev/null +++ b/app/Models/Contract.php @@ -0,0 +1,224 @@ +hasMany(ContractHistory::class)->orderBy('created_at', 'desc'); + } + + public function client(): BelongsTo + { + return $this->belongsTo(Clients::class); + } + + public function contractType(): BelongsTo + { + return $this->belongsTo(ContractType::class); + } + + public function status(): BelongsTo + { + return $this->belongsTo(ContractStatus::class); + } + + public function payments(): HasMany + { + return $this->hasMany(Payment::class); + } + + public function powerTier(): BelongsTo + { + return $this->belongsTo(PowerTier::class); + } + + public function cuiTier(): BelongsTo + { + return $this->belongsTo(CuiTier::class); + } + + public function paymentMethod(): BelongsTo + { + return $this->belongsTo(PaymentMethod::class); + } + + public function previousSupplier(): BelongsTo + { + return $this->belongsTo(Supplier::class, 'previous_supplier_id'); + } + + public function newSupplier(): BelongsTo + { + return $this->belongsTo(Supplier::class, 'new_supplier_id'); + } + + public function typology() + { + return $this->belongsTo(Typology::class); + } + + public function installments() + { + return $this->hasMany(ContractInstallment::class); + } + + // Gerar parcelas automaticamente + public function createInstallments() + { + $amount = $this->contract_value / $this->installment_count; + for ($i = 1; $i <= $this->installment_count; $i++) { + $this->installments()->create([ + 'installment_number' => $i, + 'amount' => $amount, + 'due_date' => now()->addMonths($i - 1), + ]); + } + } + + + // Scopes + public function scopeCpe($query) + { + return $query->where('type', 'cpe'); + } + + public function scopeCpi($query) + { + return $query->where('type', 'cpi'); + } + + public function seller() + { + return $this->belongsTo(User::class, 'seller_id'); + } + + public function scopeBetweenDates($query, $from, $to) + { + return $query->when($from, fn($q) => $q->where('contract_date', '>=', $from)) + ->when($to, fn($q) => $q->where('contract_date', '<=', $to)); + } + + public static function getMonthlyGrowth($from = null, $to = null) + { + $driver = \Illuminate\Support\Facades\DB::getDriverName(); + $monthExpression = $driver === 'sqlite' + ? "strftime('%Y-%m', contract_date)" + : "DATE_FORMAT(contract_date, '%Y-%m')"; + + return self::query() + ->betweenDates($from, $to) + ->selectRaw($monthExpression . ' as mes, SUM(contract_value) as total') + ->groupByRaw($monthExpression) + ->orderByRaw($monthExpression) + ->get(); + } + + // Mutators & Accessors + protected function activationDate(): Attribute + { + return Attribute::make( + // Getter: returns a Carbon instance or null + get: fn ($value) => $value ? Carbon::parse($value) : null, + + // Setter: accepts 'd/m/Y' from form, converts to 'Y-m-d' for DB + set: fn ($value) => $this->convertDateToDbFormat($value) + ); + } + + protected function contractDate(): Attribute + { + return Attribute::make( + // Getter: returns a Carbon instance or null + get: fn ($value) => $value ? Carbon::parse($value) : null, + + // Setter: accepts 'd/m/Y' from form, converts to 'Y-m-d' for DB + set: fn ($value) => $this->convertDateToDbFormat($value) + ); + } + + protected function validity(): Attribute + { + return Attribute::make( + // Getter: returns a Carbon instance or null + get: fn ($value) => $value ? Carbon::parse($value) : null, + + // Setter: accepts 'd/m/Y' from form, converts to 'Y-m-d' for DB + set: fn ($value) => $this->convertDateToDbFormat($value) + ); + } + + protected function contractEndDate(): Attribute + { + return Attribute::make( + get: fn ($value) => $value ? Carbon::parse($value) : null, + set: fn ($value) => $this->convertDateToDbFormat($value) + ); + } + + /** + * Converts a date string from 'd/m/Y' or other formats to 'Y-m-d' for DB storage. + * + * @param string|null $value + * @return string|null + */ + private function convertDateToDbFormat($value) + { + $value = trim($value); + if (!$value) return null; + + try { + // Try parsing d/m/Y format + return Carbon::createFromFormat('d/m/Y', $value)->format('Y-m-d'); + } catch (\Exception $e) { + try { + // Fallback: parse standard date formats (e.g., Y-m-d) + return Carbon::parse($value)->format('Y-m-d'); + } catch (\Exception $e) { + // If parsing fails, store null + return null; + } + } + } + +} diff --git a/app/Models/ContractHistory.php b/app/Models/ContractHistory.php new file mode 100644 index 0000000..2639482 --- /dev/null +++ b/app/Models/ContractHistory.php @@ -0,0 +1,116 @@ +belongsTo(Contract::class); + } + + public function previousSupplier() + { + return $this->belongsTo(Supplier::class, 'previous_supplier_id'); + } + + public function currentSupplier() + { + return $this->belongsTo(Supplier::class, 'current_supplier_id'); + } + + public function seller() + { + return $this->belongsTo(User::class, 'seller_id'); + } + + public function contractType() + { + return $this->belongsTo(ContractType::class); + } + + + + + protected function validity(): Attribute + { + return Attribute::make( + // Getter: returns a Carbon instance or null + get: fn ($value) => $value ? Carbon::parse($value) : null, + + // Setter: accepts 'd/m/Y' from form, converts to 'Y-m-d' for DB + set: fn ($value) => $this->convertDateToDbFormat($value) + ); + } + + protected function chargebackDate(): Attribute + { + return Attribute::make( + get: fn ($value) => $value ? Carbon::parse($value) : null, + set: fn ($value) => $this->convertDateToDbFormat($value) + ); + } + + /** + * Converts a date string from 'd/m/Y' or other formats to 'Y-m-d' for DB storage. + * + * @param string|null $value + * @return string|null + */ + private function convertDateToDbFormat($value) + { + $value = trim($value); + if (!$value) return null; + + try { + // Try parsing d/m/Y format + return Carbon::createFromFormat('d/m/Y', $value)->format('Y-m-d'); + } catch (\Exception $e) { + try { + // Fallback: parse standard date formats (e.g., Y-m-d) + return Carbon::parse($value)->format('Y-m-d'); + } catch (\Exception $e) { + // If parsing fails, store null + return null; + } + } + } +} diff --git a/app/Models/ContractInstallment.php b/app/Models/ContractInstallment.php new file mode 100644 index 0000000..5bc273a --- /dev/null +++ b/app/Models/ContractInstallment.php @@ -0,0 +1,22 @@ +belongsTo(Contract::class); + } +} diff --git a/app/Models/ContractStatus.php b/app/Models/ContractStatus.php new file mode 100644 index 0000000..c2c5d19 --- /dev/null +++ b/app/Models/ContractStatus.php @@ -0,0 +1,25 @@ + + */ + protected $hidden = [ + 'id' + ]; +} diff --git a/app/Models/ContractType.php b/app/Models/ContractType.php new file mode 100644 index 0000000..02bd900 --- /dev/null +++ b/app/Models/ContractType.php @@ -0,0 +1,25 @@ + + */ + protected $hidden = [ + 'id' + ]; +} diff --git a/app/Models/CpePayment.php b/app/Models/CpePayment.php new file mode 100644 index 0000000..1320f25 --- /dev/null +++ b/app/Models/CpePayment.php @@ -0,0 +1,21 @@ +belongsTo(CPE::class); + } +} diff --git a/app/Models/CuiTier.php b/app/Models/CuiTier.php new file mode 100644 index 0000000..5705348 --- /dev/null +++ b/app/Models/CuiTier.php @@ -0,0 +1,13 @@ +belongsTo(Clients::class); + } + + + + /** + * Accessor - quando for buscar do BD converte para d/m/Y + */ + public function getContactDateAttribute($value) + { + return $value ? Carbon::parse($value)->format('d/m/Y') : null; + } + + public function getContractEndDateAttribute($value) + { + return $value ? Carbon::parse($value)->format('d/m/Y') : null; + } + + + public function setContactDateAttribute($value) + { + $this->attributes['contact_date'] = $value + ? Carbon::createFromFormat('d/m/Y', $value)->format('Y-m-d') + : null; + } + + public function setContractEndDateAttribute($value) + { + $this->attributes['contract_end_date'] = $value + ? Carbon::createFromFormat('d/m/Y', $value)->format('Y-m-d') + : null; + } +} diff --git a/app/Models/LeadStatus.php b/app/Models/LeadStatus.php new file mode 100644 index 0000000..b09b71e --- /dev/null +++ b/app/Models/LeadStatus.php @@ -0,0 +1,20 @@ +hasMany(Clients::class, 'lead_status_id'); + } +} diff --git a/app/Models/Payment.php b/app/Models/Payment.php new file mode 100644 index 0000000..6db2c88 --- /dev/null +++ b/app/Models/Payment.php @@ -0,0 +1,15 @@ +belongsTo(Contract::class); + } +} diff --git a/app/Models/PaymentMethod.php b/app/Models/PaymentMethod.php new file mode 100644 index 0000000..c70a1ab --- /dev/null +++ b/app/Models/PaymentMethod.php @@ -0,0 +1,21 @@ +hasMany(cpe::class); + } +} diff --git a/app/Models/PowerTier.php b/app/Models/PowerTier.php new file mode 100644 index 0000000..19f5226 --- /dev/null +++ b/app/Models/PowerTier.php @@ -0,0 +1,10 @@ +hasMany(Contract::class, 'previous_supplier_id'); + } + + public function newContracts() + { + return $this->hasMany(Contract::class, 'new_supplier_id'); + } +} diff --git a/app/Models/Typology.php b/app/Models/Typology.php new file mode 100644 index 0000000..86533e8 --- /dev/null +++ b/app/Models/Typology.php @@ -0,0 +1,23 @@ + + */ + protected $hidden = [ + 'id' + ]; +} diff --git a/app/Models/User.php b/app/Models/User.php new file mode 100644 index 0000000..6424da4 --- /dev/null +++ b/app/Models/User.php @@ -0,0 +1,55 @@ + */ + use HasApiTokens, HasFactory, Notifiable, HasRoles; + + /** + * The attributes that are mass assignable. + * + * @var list + */ + protected $fillable = [ + 'name', + 'email', + 'password', + 'pin', + 'can_login', + ]; + + /** + * The attributes that should be hidden for serialization. + * + * @var list + */ + protected $hidden = [ + 'password', + 'remember_token', + 'pin', + ]; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + 'can_login' => 'boolean', + ]; + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php new file mode 100644 index 0000000..3c484c5 --- /dev/null +++ b/app/Providers/AppServiceProvider.php @@ -0,0 +1,38 @@ +routes(function () { + + Route::prefix('api') + ->middleware('api') + ->group(base_path('routes/api.php')); + + Route::middleware('web') + ->group(base_path('routes/web.php')); + }); + } +} diff --git a/app/Services/AdminService.php b/app/Services/AdminService.php new file mode 100644 index 0000000..743a518 --- /dev/null +++ b/app/Services/AdminService.php @@ -0,0 +1,53 @@ +getDriverName() === 'mysql' + ? DB::select('SELECT VERSION() as version')[0]->version + : DB::connection()->getDriverName(); + try { + $redisVersion = Redis::connection()->client()->info()['redis_version'] ?? 'N/A'; + } catch (Throwable $exception) { + $redisVersion = 'N/A'; + } + return [ + 'php_version' => PHP_VERSION, 'php_sapi' => PHP_SAPI, 'laravel_version' => app()->version(), + 'environment' => app()->environment(), 'debug_mode' => config('app.debug'), + 'database_driver' => config('database.default'), 'database_version' => $databaseVersion, + 'redis_version' => $redisVersion, 'redis_database' => config('database.redis.cache.database'), + 'cache_driver' => config('cache.default'), 'queue_driver' => config('queue.default'), + 'session_driver' => config('session.driver'), 'memory_limit' => ini_get('memory_limit'), 'system' => php_uname(), + ]; + } + + public function phpInfo(): string + { + ob_start(); + phpinfo(); + return ob_get_clean(); + } + + public function runMigrations(): array + { + $exitCode = Artisan::call('migrate', ['--force' => true]); + return ['success' => $exitCode === 0, 'exit_code' => $exitCode, 'output' => trim(Artisan::output())]; + } + + public function testEmail(string $recipient): array + { + Mail::raw('Teste de envio de email.', function ($message) use ($recipient) { + $message->to($recipient)->subject('Teste de envio de email'); + }); + return ['success' => true, 'message' => 'Email de teste enviado com sucesso.']; + } +} diff --git a/app/Services/AnalyticalService.php b/app/Services/AnalyticalService.php new file mode 100644 index 0000000..9af3c54 --- /dev/null +++ b/app/Services/AnalyticalService.php @@ -0,0 +1,283 @@ + + * @version 2026/03 + */ + public function index(Request $request) + { + $from = $this->parseDate($request->validity_from ?? $request->from ?? null); + $to = $this->parseDate($request->validity_to ?? $request->to ?? null); + + $baseContractQuery = $this->applyFilters(Contract::query(), $request, 'contract_date'); + $baseHistoryQuery = $this->applyFilters(ContractHistory::query(), $request, 'contract_date'); + + $contractTotals = (clone $baseContractQuery) + ->selectRaw('COALESCE(SUM(contract_value), 0) as total_vendas, COALESCE(SUM(profit_value), 0) as total_lucro, COALESCE(SUM(commission_value), 0) as total_comissao, COUNT(*) as contagem, COUNT(DISTINCT client_id) as total_clients') + ->first(); + + $historyTotals = (clone $baseHistoryQuery) + ->selectRaw('COALESCE(SUM(contract_value), 0) as total_vendas, COALESCE(SUM(profit_value), 0) as total_lucro, COALESCE(SUM(commission_value), 0) as total_comissao, COUNT(*) as contagem, COUNT(DISTINCT contract_id) as total_clients') + ->first(); + + $totalVendas = (float) ($contractTotals->total_vendas ?? 0) + (float) ($historyTotals->total_vendas ?? 0); + $totalLucro = (float) ($contractTotals->total_lucro ?? 0) + (float) ($historyTotals->total_lucro ?? 0); + $totalComissao = (float) ($contractTotals->total_comissao ?? 0) + (float) ($historyTotals->total_comissao ?? 0); + $contagem = (int) (($contractTotals->contagem ?? 0) + ($historyTotals->contagem ?? 0)); + $totalClients = (int) max($contractTotals->total_clients ?? 0, $historyTotals->total_clients ?? 0); + + $stats = [ + 'total_vendas' => $totalVendas, + 'total_lucro' => $totalLucro, + 'total_comissao' => $totalComissao, + 'contagem' => $contagem, + 'total_clients' => $totalClients, + ]; + + $vendasMensais = $this->buildMonthlyGrowth($request); + + $vendasPorTipo = $this->buildClientTypeBreakdown($request); + $totaisPorAno = $this->buildYearBreakdown($request); + $totaisPorComercializadora = $this->buildSupplierBreakdown($request); + + return compact('stats', 'vendasMensais', 'vendasPorTipo', 'totaisPorAno', 'totaisPorComercializadora'); + } + + private function applyFilters($query, Request $request, string $dateField = 'contract_date') + { + if (!str_contains($dateField, '.')) { + $dateField = $query->getModel()->getTable() . '.' . $dateField; + } + + $from = $this->parseDate($request->validity_from ?? $request->from ?? null); + $to = $this->parseDate($request->validity_to ?? $request->to ?? null); + + if ($from) { + $query->whereDate($dateField, '>=', $from); + } + + if ($to) { + $query->whereDate($dateField, '<=', $to); + } + + foreach (['status_id', 'seller_id', 'supply_type', 'contract_type_id', 'year'] as $field) { + $value = $request->input($field); + if ($value === null || $value === '' || $value === 'all') { + continue; + } + + switch ($field) { + case 'status_id': + $query->where('status_id', $value); + break; + case 'seller_id': + $query->where('seller_id', $value); + break; + case 'supply_type': + $query->where('supply_type', $value); + break; + case 'contract_type_id': + $query->where('contract_type_id', $value); + break; + case 'year': + $query->whereRaw($this->yearExpression($dateField) . ' = ?', [(int) $value]); + break; + } + } + + if ($request->filled('client_type_id')) { + $query->whereHas('client', fn ($q) => $q->where('client_type_id', $request->client_type_id)); + } + + if ($request->filled('supplier_id')) { + $query->where(function ($q) use ($request) { + $q->where('new_supplier_id', $request->supplier_id) + ->orWhere('previous_supplier_id', $request->supplier_id); + }); + } + + return $query; + } + + private function buildMonthlyGrowth(Request $request) + { + $from = $this->parseDate($request->validity_from ?? $request->from ?? null); + $to = $this->parseDate($request->validity_to ?? $request->to ?? null); + + $contractSeries = Contract::query(); + $historySeries = ContractHistory::query(); + + $this->applyFilters($contractSeries, $request, 'contract_date'); + $this->applyFilters($historySeries, $request, 'contract_date'); + + $monthExpression = $this->monthExpression('contract_date'); + + $contractTotals = (clone $contractSeries) + ->selectRaw($monthExpression . ' as mes, SUM(contract_value) as total') + ->whereNotNull('contract_date') + ->groupByRaw($monthExpression) + ->orderByRaw($monthExpression) + ->get(); + + $historyTotals = (clone $historySeries) + ->selectRaw($monthExpression . ' as mes, SUM(contract_value) as total') + ->whereNotNull('contract_date') + ->groupByRaw($monthExpression) + ->orderByRaw($monthExpression) + ->get(); + + $merged = []; + foreach ($contractTotals as $row) { + $merged[$row->mes] = (float) ($row->total ?? 0); + } + + foreach ($historyTotals as $row) { + $merged[$row->mes] = ($merged[$row->mes] ?? 0) + (float) ($row->total ?? 0); + } + + ksort($merged); + + return collect(array_map(fn ($month, $total) => ['mes' => $month, 'total' => $total], array_keys($merged), array_values($merged))); + } + + private function buildClientTypeBreakdown(Request $request) + { + $contractBreakdown = (clone $this->applyFilters(Contract::query(), $request, 'contract_date')) + ->join('clients', 'contracts.client_id', '=', 'clients.id') + ->join('client_types', 'clients.client_type_id', '=', 'client_types.id') + ->selectRaw('client_types.description as tipo, SUM(contracts.contract_value) as total') + ->groupBy('client_types.description') + ->get(); + + $historyBreakdown = (clone $this->applyFilters(ContractHistory::query(), $request, 'contract_date')) + ->join('contracts', 'contract_histories.contract_id', '=', 'contracts.id') + ->join('clients', 'contracts.client_id', '=', 'clients.id') + ->join('client_types', 'clients.client_type_id', '=', 'client_types.id') + ->selectRaw('client_types.description as tipo, SUM(contract_histories.contract_value) as total') + ->groupBy('client_types.description') + ->get(); + + $merged = []; + foreach ($contractBreakdown as $row) { + $merged[$row->tipo] = (float) ($row->total ?? 0); + } + foreach ($historyBreakdown as $row) { + $key = $row->tipo ?? 'Sem tipo'; + $merged[$key] = ($merged[$key] ?? 0) + (float) ($row->total ?? 0); + } + + return collect(array_map(fn ($tipo, $total) => ['tipo' => $tipo, 'total' => $total], array_keys($merged), array_values($merged))); + } + + private function buildYearBreakdown(Request $request) + { + $yearExpression = $this->yearExpression('contract_date'); + + $contractYears = (clone $this->applyFilters(Contract::query(), $request, 'contract_date')) + ->selectRaw($yearExpression . ' as ano, SUM(contract_value) as total') + ->whereNotNull('contract_date') + ->groupByRaw($yearExpression) + ->orderByRaw($yearExpression) + ->get(); + + $historyYears = (clone $this->applyFilters(ContractHistory::query(), $request, 'contract_date')) + ->selectRaw($yearExpression . ' as ano, SUM(contract_value) as total') + ->whereNotNull('contract_date') + ->groupByRaw($yearExpression) + ->orderByRaw($yearExpression) + ->get(); + + $merged = []; + foreach ($contractYears as $row) { + $merged[(string) $row->ano] = (float) ($row->total ?? 0); + } + foreach ($historyYears as $row) { + $key = (string) ($row->ano ?? ''); + $merged[$key] = ($merged[$key] ?? 0) + (float) ($row->total ?? 0); + } + + ksort($merged); + + return collect(array_map(fn ($ano, $total) => ['ano' => $ano, 'total' => $total], array_keys($merged), array_values($merged))); + } + + private function buildSupplierBreakdown(Request $request) + { + $contractSuppliers = (clone $this->applyFilters(Contract::query(), $request, 'contract_date')) + ->join('suppliers', 'contracts.new_supplier_id', '=', 'suppliers.id') + ->selectRaw('suppliers.name as fornecedor, SUM(contracts.contract_value) as total') + ->groupBy('suppliers.name') + ->orderBy('total', 'desc') + ->get(); + + $historySuppliers = (clone $this->applyFilters(ContractHistory::query(), $request, 'contract_date')) + ->join('suppliers', 'contract_histories.current_supplier_id', '=', 'suppliers.id') + ->selectRaw('suppliers.name as fornecedor, SUM(contract_histories.contract_value) as total') + ->groupBy('suppliers.name') + ->orderBy('total', 'desc') + ->get(); + + $merged = []; + foreach ($contractSuppliers as $row) { + $merged[$row->fornecedor] = (float) ($row->total ?? 0); + } + foreach ($historySuppliers as $row) { + $key = $row->fornecedor ?? 'Sem fornecedor'; + $merged[$key] = ($merged[$key] ?? 0) + (float) ($row->total ?? 0); + } + + return collect(array_map(fn ($fornecedor, $total) => ['fornecedor' => $fornecedor, 'total' => $total], array_keys($merged), array_values($merged))) + ->sortByDesc('total')->values(); + } + + private function yearExpression(string $column): string + { + if (DB::getDriverName() === 'sqlite') { + return "CAST(strftime('%Y', {$column}) AS INTEGER)"; + } + + return "YEAR({$column})"; + } + + private function monthExpression(string $column): string + { + if (DB::getDriverName() === 'sqlite') { + return "strftime('%Y-%m', {$column})"; + } + + return "DATE_FORMAT({$column}, '%Y-%m')"; + } + + private function parseDate($date) + { + if ($date === null || $date === '') { + return null; + } + + $date = trim((string) $date); + + try { + if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) { + return Carbon::createFromFormat('Y-m-d', $date)->format('Y-m-d'); + } + + if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $date)) { + return Carbon::createFromFormat('d/m/Y', $date)->format('Y-m-d'); + } + + return Carbon::parse($date)->format('Y-m-d'); + } catch (\Exception $e) { + return null; + } + } +} diff --git a/app/Services/AuthService.php b/app/Services/AuthService.php new file mode 100644 index 0000000..65cac1e --- /dev/null +++ b/app/Services/AuthService.php @@ -0,0 +1,73 @@ +first(); + abort_unless($user && Hash::check($credentials['password'], $user->password) && $user->can_login !== false, 401, 'Credenciais invalidas.'); + return $user; + } + + public function issueToken(User $user): array + { + $token = $user->createToken('api-token', ['*'], now()->addMinutes(20)); + return ['token' => $token->plainTextToken, 'user' => $user->only(['id', 'name', 'email'])]; + } + + public function sessionToken(User $user, string $plainText): ?PersonalAccessToken + { + $token = PersonalAccessToken::findToken($plainText); + if (!$token || $token->tokenable_type !== $user->getMorphClass() || (int) $token->tokenable_id !== (int) $user->id + || ($token->expires_at && $token->expires_at->isPast()) || $user->can_login === false) { + return null; + } + return $token; + } + + public function refresh(PersonalAccessToken $token): array + { + abort_if($token->expires_at && $token->expires_at->isPast(), 401, 'Token expirado.'); + $token->update(['expires_at' => now()->addMinutes(20)]); + return [ + 'message' => 'Token renovado com sucesso', + 'expires_at' => $token->expires_at->toISOString(), + 'user' => $token->tokenable->only(['id', 'name', 'email']), + ]; + } + + public function check(PersonalAccessToken $token): array + { + $valid = !$token->expires_at || $token->expires_at->isFuture(); + $seconds = $valid && $token->expires_at ? max(0, now()->diffInSeconds($token->expires_at, false)) : 0; + return ['valid' => $valid, 'expires_at' => $token->expires_at?->toISOString(), 'expires_in' => $seconds, 'expires_in_minutes' => ceil($seconds / 60)]; + } + + public function revoke(?PersonalAccessToken $token): void + { + $token?->delete(); + } + + public function sendResetLink(array $credentials): string + { + return Password::sendResetLink($credentials); + } + + public function resetPassword(array $credentials): string + { + return Password::reset($credentials, function (User $user, string $password) { + $user->forceFill(['password' => Hash::make($password), 'remember_token' => Str::random(60)])->save(); + $user->tokens()->delete(); + event(new PasswordReset($user)); + }); + } +} diff --git a/app/Services/ClientService.php b/app/Services/ClientService.php new file mode 100644 index 0000000..3908fb0 --- /dev/null +++ b/app/Services/ClientService.php @@ -0,0 +1,95 @@ +where('status', 'A'); + if ($paginated) { + $query->where('type', 'client'); + } + foreach (['name', 'tax_number', 'email'] as $field) { + if ($request->filled($field)) { + $query->where($field, 'like', '%' . $request->input($field) . '%'); + } + } + if ($request->filled('client_type_id')) { + $query->where('client_type_id', $request->input('client_type_id')); + } + if ($request->filled('contract_code')) { + $query->whereHas('contracts', fn ($contracts) => $contracts->where('code', 'like', '%' . $request->input('contract_code') . '%')); + } + return $paginated + ? $query->orderByDesc('id')->paginate(max(1, min(100, (int) $request->input('per_page', 10))))->appends($request->query()) + : $query->orderBy('id')->get(); + } + + public function types() + { + return ClientType::all(); + } + + public function form($type, User $user): array + { + return ['type' => ClientType::findOrFail($type), 'sellers' => $user->id === 1 ? User::all() : $this->_getSellers()]; + } + + public function find($id) + { + return Clients::with('contracts')->findOrFail($id); + } + + public function detail($id): array + { + $contracts = Contract::with(['contractType', 'status'])->where('client_id', $id)->orderByDesc('activation_date')->get(); + return [ + 'client' => $this->find($id), + 'contractsByStatus' => $contracts->groupBy(fn ($contract) => $contract->status->description ?? 'Sem status'), + 'clientTypes' => $this->types(), + 'sellers' => $this->_getSellers(), + ]; + } + + public function create(array $data) + { + return Clients::create($data); + } + + public function update($id, array $data) + { + $client = $this->find($id); + $client->update($data); + return $client; + } + + public function delete($id): void + { + $client = $this->find($id); + $client->status = 'I'; + $client->save(); + } + + public function searchName(string $term) + { + return Clients::with('clientType')->where('type', 'client')->where('status', 'A') + ->where('name', 'like', '%' . $term . '%')->orderBy('name')->limit(10)->get() + ->map(fn ($client) => ['id' => $client->id, 'label' => $client->name . ' (' . optional($client->clientType)->description . ')']); + } + + public function searchID($id) + { + abort_unless(ctype_digit((string) $id), 400, 'ID invalido'); + return Clients::where('type', 'client')->where('status', 'A')->findOrFail((int) $id); + } +} diff --git a/app/Services/ContractService.php b/app/Services/ContractService.php new file mode 100644 index 0000000..e219f18 --- /dev/null +++ b/app/Services/ContractService.php @@ -0,0 +1,735 @@ + + * @version 2025/06 + * @since 2025/06 + */ + public function index(Request $request) + { + $perPage = max(1, min(100, (int) $request->get('per_page', 10))); + + $query = Contract::query(); + $this->_applyFilters($query, $request); + + $filteredQuery = clone $query; + $contracts = $query->paginate($perPage)->appends($request->query()); + + # Values for the full filtered set, not only the current page + $totalPvp = (float) $filteredQuery->sum('contract_value'); + $totalCommission = (float) $filteredQuery->sum('commission_value'); + $totalChargeback = (float) $filteredQuery->sum('chargeback_value'); + $totalMargin = $totalPvp - $totalCommission + $totalChargeback; + + return [ + 'contracts' => $contracts, + 'statuses' => $this->_getContractStatuses(), + 'contractTypes' => $this->_getContractTypes(), + 'sellers' => $this->_getSellers(), + 'totalPvp' => $totalPvp, + 'totalCommission' => $totalCommission, + 'totalChargeback' => $totalChargeback, + 'totalMargin' => $totalMargin, + 'suppliers' => $this->_getSuppliers(), + 'clientTypes' => ClientType::orderBy('description')->get(), + ]; + } + + /** + * Applies filter parameters to the contract query. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param Request $request + * + * @return void + * + * @author Luis Medon + */ + private function _applyFilters($query, Request $request) + { + $filters = [ + 'contract_id' => fn($q, $v) => $q->where('id', $v), + 'contract_code' => fn($q, $v) => $q->where('code', 'like', "%$v%"), + 'status' => fn($q, $v) => $q->where('status_id', $v), + 'contract_type' => fn($q, $v) => $q->where('contract_type_id', $v), + 'client_type_id' => fn($q, $v) => $q->whereHas( + 'client', + fn($clientQuery) => $clientQuery->where('client_type_id', $v) + ), + 'supply_type' => fn($q, $v) => $q->where('supply_type', $v), + 'validity_from' => fn($q, $v) => $q->whereDate('contract_date', '>=', $this->normalizeDate($v)), + 'validity_to' => fn($q, $v) => $q->whereDate('contract_date', '<=', $this->normalizeDate($v)), + 'activation_from' => fn($q, $v) => $q->whereDate('activation_date', '>=', $this->normalizeDate($v)), + 'activation_to' => fn($q, $v) => $q->whereDate('activation_date', '<=', $this->normalizeDate($v)), + 'renewal_from' => fn($q, $v) => $q->whereDate('validity', '>=', $this->normalizeDate($v)), + 'renewal_to' => fn($q, $v) => $q->whereDate('validity', '<=', $this->normalizeDate($v)), + 'seller_id' => fn($q, $v) => $q->where('seller_id', $v), + 'supplier_id' => fn($q, $v) => $q->where('new_supplier_id', $v), + ]; + + foreach ($filters as $key => $callback) { + if ($request->filled($key)) { + $callback($query, $request->input($key)); + } + } + + if ($request->filled('client_name')) { + $query->whereHas('client', fn($q) => $q->where('name', 'like', '%' . $request->input('client_name') . '%')); + } + + if ($request->filled('sort_by')) { + $allowedSortColumns = [ + 'id', 'code', 'status_id', 'contract_type_id', 'supply_type', + 'validity', 'activation_date', 'renewal_date', 'seller_id' + ]; + $sortBy = $request->input('sort_by'); + if (in_array($sortBy, $allowedSortColumns)) { + $order = strtolower($request->input('order', 'desc')); + $order = in_array($order, ['asc', 'desc']) ? $order : 'desc'; + $query->orderBy($sortBy, $order); + } else { + // Fallback to default sorting if sort_by is invalid + $query->orderBy('activation_date', 'desc'); + } + } else { + // Always apply default sorting when sort_by is not provided + // Last added contracts first + $query->orderBy('id', 'desc'); + } + } + + /** + * Exports filtered contracts to Excel. + * + * @param Request $request + * + * @return \Symfony\Component\HttpFoundation\BinaryFileResponse + * + * @author Luis Medon + */ + public function export(Request $request) + { + $filename = 'contratos_' . now()->format('Ymd_His') . '.xlsx'; + return Excel::download(new ContractsExport($request), $filename); + } + + /** + * Shows the contract creation form. + * + * @param Request $request + * + * @return \Illuminate\View\View + * + * @author Luis Medon + */ + public function create(Request $request) + { + return [ + 'clientId' => $request->query('client_id'), + 'contract' => null, + 'paymentMethods' => $this->_getPaymentMethods(), + 'contractTypes' => $this->_getContractTypes(), + 'contractStatus' => $this->_getContractStatuses(), + 'powerTiers' => $this->_getPowerTiers(), + 'cui_tiers' => $this->_getCuiTiers(), + 'suppliers' => $this->_getSuppliers(), + 'typology' => $this->_getTypologies(), + 'sellers' => $this->_getSellers(), + 'installments_count' => 12, + ]; + } + + /** + * Stores a newly created contract. + * + * @param ContractRequest $request + * + * @return \Illuminate\Http\RedirectResponse + * + * @author Luis Medon + */ + public function store(ContractRequest $request) + { + $data = $request->validated(); + + if (! $request->user()?->can('view_contract_summary')) { + foreach (['contract_value', 'commission_value', 'profit_value', 'paid', 'chargeback', 'chargeback_value', 'chargeback_date'] as $field) { + unset($data[$field]); + } + $installmentsInput = []; + } else { + $installmentsInput = $request->input('installments', []); + } + + foreach (['contract_date', 'activation_date', 'validity', 'contract_end_date', 'renewal_date', 'payment_date', 'chargeback_date'] as $field) { + if (!empty($data[$field])) { + $data[$field] = $this->normalizeDate($data[$field]); + } + } + + if (($data['delivery_method'] ?? null) !== 'email') { + $data['delivery_email'] = null; + } + + if (empty($data['chargeback'])) { + $data['chargeback_value'] = null; + $data['chargeback_date'] = null; + } + + if ($request->user()?->can('view_contract_summary')) { + $data['profit_value'] = (float) ($data['contract_value'] ?? 0) + - abs((float) ($data['commission_value'] ?? 0)) + + (float) ($data['chargeback_value'] ?? 0); + } + + $contract = Contract::create($data); + + foreach ($installmentsInput as $i => $installment) { + if (!empty($installment['due_date']) && !empty($installment['amount'])) { + $dueDate = $this->normalizeDate($installment['due_date']); + if ($dueDate === null) { + continue; + } + + $contract->installments()->create([ + 'installment_number' => $i, + 'due_date' => $dueDate, + 'amount' => $installment['amount'], + 'paid' => isset($installment['paid']) && $installment['paid'] ? 1 : 0, + ]); + } + } + + return $contract; + } + + + /** + * Shows the contract editing form. + * + * @param string $id + * + * @return \Illuminate\View\View + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * + * @author Luis Medon + */ + public function edit(string $id) + { + $contract = Contract::findOrFail($id); + + $suppliers = $this->includeCurrentOption($this->_getSuppliers(), $contract->previousSupplier); + $suppliers = $this->includeCurrentOption($suppliers, $contract->newSupplier); + + return [ + 'contract' => $contract, + 'clientId' => $contract->client_id, + 'paymentMethods' => $this->includeCurrentOption($this->_getPaymentMethods(), $contract->paymentMethod), + 'contractTypes' => $this->includeCurrentOption($this->_getContractTypes(), $contract->contractType), + 'contractStatus' => $this->_getContractStatuses(), + 'powerTiers' => $this->includeCurrentOption($this->_getPowerTiers(), $contract->powerTier), + 'cui_tiers' => $this->includeCurrentOption($this->_getCuiTiers(), $contract->cuiTier), + 'suppliers' => $suppliers, + 'typology' => $this->includeCurrentOption($this->_getTypologies(), $contract->typology), + 'sellers' => $this->includeCurrentOption($this->_getSellers(), $contract->seller), + 'installments_count' => 12, + ]; + } + + private function includeCurrentOption(Collection $options, ?Model $current): Collection + { + $options = clone $options; + + if ($current && ! $options->contains(fn (Model $option) => $option->is($current))) { + $options->prepend($current); + } + + return $options; + } + + /** + * Updates an existing contract. + * + * @param ContractRequest $request + * @param string $id + * + * @return \Illuminate\Http\RedirectResponse + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * + * @author Luis Medon + */ + public function update(ContractRequest $request, string $id) + { + $contract = Contract::findOrFail($id); + $data = $request->validated(); + + if (! $request->user()?->can('view_contract_summary')) { + foreach (['contract_value', 'commission_value', 'profit_value', 'paid', 'chargeback', 'chargeback_value', 'chargeback_date'] as $field) { + unset($data[$field]); + } + $installmentsInput = []; + } else { + $installmentsInput = $request->input('installments', []); + } + + // Campos de data do contrato + foreach (['contract_date', 'activation_date', 'validity', 'contract_end_date', 'renewal_date', 'payment_date', 'chargeback_date'] as $field) { + if (!empty($data[$field])) { + $data[$field] = $this->normalizeDate($data[$field]); + } + } + + if (($data['delivery_method'] ?? null) !== 'email') { + $data['delivery_email'] = null; + } + + if ($request->user()?->can('view_contract_summary') && empty($data['chargeback'])) { + $data['chargeback_value'] = null; + $data['chargeback_date'] = null; + } + + if ($request->user()?->can('view_contract_summary')) { + $data['profit_value'] = (float) ($data['contract_value'] ?? 0) + - abs((float) ($data['commission_value'] ?? 0)) + + (float) ($data['chargeback_value'] ?? 0); + } + + if (! $contract->update($data)) { + throw \Illuminate\Validation\ValidationException::withMessages([ + 'contract' => 'O contrato não foi atualizado. Reveja os dados e tente novamente.', + ]); + } + + // Parcelas + $processedIds = []; + + foreach ($installmentsInput as $i => $installment) { + $dueDateRaw = trim($installment['due_date'] ?? ''); + $amount = $installment['amount'] ?? null; + + if ($dueDateRaw !== '' && $amount !== null) { + $dueDate = $this->normalizeDate($dueDateRaw); + if ($dueDate === null) { + continue; + } + + $payload = [ + 'installment_number' => $i, + 'due_date' => $dueDate, + 'amount' => $amount, + 'paid' => isset($installment['paid']) && $installment['paid'] ? 1 : 0, + ]; + + $existing = $contract->installments()->where('installment_number', $i)->first(); + + if ($existing) { + $existing->update($payload); + $processedIds[] = $existing->id; + } else { + $new = $contract->installments()->create($payload); + $processedIds[] = $new->id; + } + } + } + + // Deleta parcelas não enviadas + if ($request->user()?->can('view_contract_summary')) { + $contract->installments()->whereNotIn('id', $processedIds)->delete(); + } + + return $contract; + } + + + + + /** + * Shows contract details including financial summary. + * + * @param string $id + * + * @return \Illuminate\View\View + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * + * @author Luis Medon + */ + public function show(string $id) + { + $contract = Contract::with('payments')->findOrFail($id); + $lastRef = $contract->payments()->orderByDesc('reference_period')->value('reference_period'); + + $totalReceived = $totalPending = $commission = $profit = 0; + + if ($lastRef) { + $payments = $contract->payments()->whereDate('reference_period', $lastRef)->get(); + $totalReceived = $payments->where('status', 'paid')->sum('amount'); + $totalPending = $payments->where('status', 'pending')->sum('amount'); + $commission = $contract->pvp * ($contract->commission_rate / 100); + $profit = ($contract->pvp - $commission) - $contract->net + + (float) ($contract->chargeback_value ?? 0); + } + + return [ + 'contract' => $contract, + 'contractTypes' => $this->_getContractTypes(), + 'statuses' => $this->_getContractStatuses(), + 'totalReceived' => $totalReceived, + 'totalPending' => $totalPending, + 'commission' => $commission, + 'profit' => $profit, + ]; + } + + /** + * Displays the contract renewal form. + * + * @param string $id + * + * @return \Illuminate\View\View + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * + * @author Luis Medon + */ + public function renewForm(string $id) + { + $contract = Contract::findOrFail($id); + return [ + 'contract' => $contract, + 'renewalTypes' => RenewalType::orderBy('id')->get(), + 'suppliers' => $this->_getSuppliers(), + 'contractTypes' => $this->_getContractTypes(), + 'typology' => $this->_getTypologies(), + ]; + } + + /** + * Performs contract renewal and creates payment. + * + * @param string $id + * + * @return \Illuminate\Http\RedirectResponse + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * + * @author Luis Medon + */ + public function renew(RenewContractRequest $request, $id) + { + # Obtain contract information + $contract = Contract::findOrFail($id); + + # Obtain contract installemnts + $installments = $contract->installments()->get(); + $totalInstallments = $installments->count(); + $totalPaidInstallments = $installments->where('paid', true)->count(); + $canViewFinancials = $request->user()?->can('view_contract_summary') ?? false; + $currentSupplierId = $request->boolean('change_supplier') + ? $request->new_supplier_id + : $contract->new_supplier_id; + + # Create Contract History Record + $historyData = [ + 'contract_id' => $contract->id, + 'previous_supplier_id' => $contract->new_supplier_id, + 'current_supplier_id' => $currentSupplierId, + 'seller_id' => $contract->seller_id, + 'contract_type_id' => $request->contract_type_id, + 'typology_id' => $request->typology_id, + 'contract_date' => $contract->contract_date, + 'activation_date' => $contract->activation_date, + 'renewal_date' => $contract->validity, + 'renewal_type' => $request->renewal_type, + 'go_ki' => $contract->go_ki, + 'validity' => $contract->validity, + 'contract_value' => $contract->contract_value, + 'commission_value' => $contract->commission_value, + 'profit_value' => $contract->profit_value, + 'annual_consumption' => $contract->annual_consumption, + 'total_installments' => $totalInstallments, + 'paid_installments' => $totalPaidInstallments, + 'notes' => 'Renovação automática', + 'contract_snapshot' => $contract->toJson(), + ]; + + if ($canViewFinancials) { + $historyData['chargeback'] = (bool) $contract->chargeback; + $historyData['chargeback_value'] = $contract->chargeback_value; + $historyData['chargeback_date'] = $contract->chargeback_date; + } + + ContractHistory::create($historyData); + + # Update current contract data + $contractData = [ + 'annual_consumption' => $request->annual_consumption, + 'contract_date' => $request->contract_date, + 'activation_date' => $request->activation_date, + 'contract_end_date' => $request->contract_end_date, + 'validity' => $request->next_due_date, + 'contract_type_id' => $request->contract_type_id, + 'typology_id' => $request->typology_id, + 'go_ki' => $request->go_ki, + 'paid' => true, + 'previous_supplier_id' => $contract->new_supplier_id, + ]; + + if ($canViewFinancials) { + $contractData['contract_value'] = $request->amount_paid; + $contractData['commission_value'] = $request->commission_value; + $contractData['profit_value'] = (float) $request->amount_paid - abs((float) $request->commission_value) + (float) ($contract->chargeback_value ?? 0); + } + + if ($request->boolean('change_supplier')) { + $contractData['new_supplier_id'] = $request->new_supplier_id; + } + + $contract->update($contractData); + + return $contract; + } + + + public function history($id) + { + $contract = Contract::findOrFail($id); + + $histories = ContractHistory::with(['previousSupplier', 'currentSupplier', 'seller', 'contractType']) + ->where('contract_id', $contract->id) + ->orderByRaw('COALESCE(validity, contract_date, created_at) ASC') + ->paginate(10); + + $totals = ContractHistory::where('contract_id', $contract->id) + ->selectRaw('COUNT(*) as renewals_count') + ->selectRaw('COALESCE(SUM(total_installments), 0) as total_installments') + ->selectRaw('COALESCE(SUM(paid_installments), 0) as paid_installments') + ->selectRaw('COALESCE(SUM(contract_value), 0) as contract_value') + ->selectRaw('COALESCE(SUM(commission_value), 0) as commission_value') + ->selectRaw('COALESCE(SUM(chargeback_value), 0) as chargeback_value') + ->selectRaw('COALESCE(SUM(profit_value), 0) as profit_value') + ->first(); + + return compact('histories', 'totals', 'contract'); + } + + public function createHistory($id) + { + $contract = Contract::findOrFail($id); + + return [ + 'contract' => $contract, + 'history' => null, + 'suppliers' => $this->_getSuppliers(), + ]; + } + + public function storeHistory(Request $request, $id) + { + $contract = Contract::findOrFail($id); + + $rules = [ + 'previous_supplier_id' => ['nullable', 'exists:suppliers,id'], + 'current_supplier_id' => ['nullable', 'exists:suppliers,id'], + 'validity' => ['nullable', 'date'], + 'annual_consumption' => ['nullable', 'numeric'], + 'seller_id' => ['nullable', 'exists:users,id'], + 'contract_type_id' => ['nullable', 'exists:contract_types,id'], + 'typology_id' => ['nullable', 'exists:typologies,id'], + 'contract_date' => ['nullable', 'date'], + 'activation_date' => ['nullable', 'date'], + 'renewal_date' => ['nullable', 'date'], + 'renewal_type' => ['nullable', 'string'], + 'go_ki' => ['nullable', 'numeric'], + 'contract_value' => ['nullable', 'numeric'], + 'commission_value' => ['nullable', 'numeric'], + 'profit_value' => ['nullable', 'numeric'], + 'chargeback' => ['nullable', 'boolean'], + 'chargeback_value' => ['nullable', 'numeric', 'max:-0.01'], + 'chargeback_date' => ['nullable', 'date'], + 'notes' => ['nullable', 'string'], + ]; + + if (! $request->user()?->can('view_contract_summary')) { + foreach (['contract_value', 'commission_value', 'profit_value', 'chargeback', 'chargeback_value', 'chargeback_date'] as $field) { + unset($rules[$field]); + } + } + + $data = $request->validate($rules); + + foreach (['validity', 'contract_date', 'activation_date', 'renewal_date', 'chargeback_date'] as $field) { + if (! empty($data[$field])) { + $data[$field] = $this->normalizeDate($data[$field]); + } + } + + if (empty($data['chargeback'] ?? null)) { + $data['chargeback'] = false; + $data['chargeback_value'] = null; + $data['chargeback_date'] = null; + } + + $data['contract_id'] = $contract->id; + + if ($request->user()?->can('view_contract_summary') && ! empty($data['contract_value']) && ! empty($data['commission_value'])) { + $data['profit_value'] = (float) ($data['contract_value'] ?? 0) + - abs((float) ($data['commission_value'] ?? 0)) + + (float) ($data['chargeback_value'] ?? 0); + } + + return ContractHistory::create($data); + } + + public function editHistory($id, $historyId) + { + $contract = Contract::findOrFail($id); + $history = ContractHistory::where('contract_id', $contract->id)->findOrFail($historyId); + + return [ + 'contract' => $contract, + 'history' => $history, + 'suppliers' => $this->_getSuppliers(), + ]; + } + + private function normalizeDate($value): ?string + { + if ($value === null || $value === '') { + return null; + } + + $value = trim((string) $value); + + try { + if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { + return Carbon::createFromFormat('Y-m-d', $value)->format('Y-m-d'); + } + + if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $value)) { + return Carbon::createFromFormat('d/m/Y', $value)->format('Y-m-d'); + } + + return Carbon::parse($value)->format('Y-m-d'); + } catch (\Exception $e) { + return null; + } + } + + public function updateHistory(Request $request, $id, $historyId) + { + $contract = Contract::findOrFail($id); + $history = ContractHistory::where('contract_id', $contract->id)->findOrFail($historyId); + + $data = $request->validate($this->getHistoryUpdateRules($request)); + + if (! $request->user()?->can('view_contract_summary')) { + foreach (['contract_value', 'commission_value', 'profit_value', 'chargeback', 'chargeback_value', 'chargeback_date'] as $field) { + unset($data[$field]); + } + } + + $history->update($data); + + return $history; + } + + protected function getHistoryUpdateRules(Request $request): array + { + $rules = [ + 'previous_supplier_id' => ['nullable', 'exists:suppliers,id'], + 'validity' => ['nullable', 'date'], + 'annual_consumption' => ['nullable', 'numeric'], + 'notes' => ['nullable', 'string'], + ]; + + if ($request->user()?->can('view_contract_summary')) { + $rules['contract_value'] = ['required', 'numeric']; + $rules['commission_value'] = ['nullable', 'numeric']; + $rules['profit_value'] = ['nullable', 'numeric']; + $rules['chargeback'] = ['nullable', 'boolean']; + $rules['chargeback_value'] = ['nullable', 'numeric', 'max:-0.01']; + $rules['chargeback_date'] = ['nullable', 'date']; + } + + return $rules; + } + + public function destroyHistory($id, $historyId) + { + $contract = Contract::findOrFail($id); + $history = ContractHistory::where('contract_id', $contract->id)->findOrFail($historyId); + $history->delete(); + + return $history; + } + + + /** + * Deletes a contract from the system. + * + * @param string $id + * + * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException + * + * @author Luis Medon + */ + public function destroy(string $id) + { + $contract = Contract::findOrFail($id); + $contract->delete(); + + return ['success' => true, 'message' => 'Contrato removido com sucesso.', 'icon' => 'success']; + } + + public function bulkDestroy(Request $request) + { + $data = $request->validate([ + 'ids' => ['required', 'array', 'min:1'], + 'ids.*' => ['integer', 'distinct', 'exists:contracts,id'], + ]); + + DB::transaction(function () use ($data) { + Contract::whereIn('id', $data['ids'])->get()->each->delete(); + }); + + return [ + 'success' => true, + 'message' => count($data['ids']) === 1 + ? 'Contrato removido com sucesso.' + : 'Contratos removidos com sucesso.', + 'icon' => 'success', + ]; + } +} diff --git a/app/Services/HomeService.php b/app/Services/HomeService.php new file mode 100644 index 0000000..c007422 --- /dev/null +++ b/app/Services/HomeService.php @@ -0,0 +1,79 @@ +addDays(60); + + $activeStatus = 1; + $pendingStatus = 3; + + // === Contracts grouped by client type (for the chart) === + $contractsByClientType = Contract::with('client.clientType') + ->where('status_id', $activeStatus) + ->get() + ->groupBy(function ($contract) { + return $contract->client->clientType->description ?? 'Undefined'; + }) + ->map(function ($group) { + return $group->count(); + }); + + $clientLabels = $contractsByClientType->keys(); + $clientData = $contractsByClientType->values(); + + // === Pending Contracts === + $pendingContracts = Contract::with(['client', 'contractType']) + ->where('status_id', $pendingStatus) + ->orderBy('id') + ->take(5) + ->get(); + + // === Active Contracts === + $activeContracts = Contract::with(['client', 'contractType']) + ->where('status_id', $activeStatus) + ->orderByDesc('id') + ->take(5) + ->get(); + + // === Upcoming Renewals (next 2 month) === + $upcomingRenewals = Contract::with(['client', 'contractType', 'seller', 'installments' => function ($query) use ($today, $next60Days) { + $query->whereBetween('due_date', [$today, $next60Days]) + ->orderBy('due_date'); + }]) + ->where('status_id', $activeStatus) + ->whereBetween('validity', [$today, $next60Days]) + ->orderByDesc('contracts.id') + ->take(5) + ->get(); + + return [ + 'clientLabels' => $clientLabels, + 'clientData' => $clientData, + 'activeContracts' => $activeContracts, + 'pendingContracts' => $pendingContracts, + 'upcomingRenewals' => $upcomingRenewals + ]; + } + +} diff --git a/app/Services/LeadService.php b/app/Services/LeadService.php new file mode 100644 index 0000000..e0f4e81 --- /dev/null +++ b/app/Services/LeadService.php @@ -0,0 +1,133 @@ +where('type', 'lead') + ->orderBy('created_at', 'desc') + ->paginate(10); + + return compact('leads'); + } + + /** + * Display a specific lead. + */ + public function show($id) + { + // Fetch a single lead with its leadStatus + $lead = Client::with(['leadStatus', 'leadDetail'])->where('type', 'lead')->findOrFail($id); + + return compact('lead'); + } + + /** + * Show the form for creating a new lead. + */ + public function create() + { + // Use unified add_edit view + return ['leadStatuses' => LeadStatus::all()]; + } + + /** + * Store a newly created lead in storage. + */ + public function store(LeadRequest $request) + { + $validated = $request->validated(); + $validated['type'] = 'lead'; + $validated['seller_id'] = $request->user()->id; + + $client = Client::create($validated); + + // Save lead details + LeadDetail::create([ + 'client_id' => $client->id, + 'contact_date' => $request->contact_date, + 'contract_end_date' => $request->contract_end_date, + 'contract_type' => $request->contract_type, + 'delivery_point_code' => $request->delivery_point_code, + ]); + + return $client->load('leadDetail'); + } + + /** + * Show the form for editing the specified lead. + */ + public function edit($id) + { + // Find lead by id + $lead = Client::with('leadDetail')->where('type', 'lead')->findOrFail($id); + + // Use unified add_edit view and pass the lead + return ['lead' => $lead, 'leadStatuses' => LeadStatus::all()]; + } + + /** + * Update the specified lead in storage. + */ + public function update(LeadRequest $request, $id) + { + $lead = Client::where('type', 'lead')->findOrFail($id); + + $lead->update($request->validated()); + + // Update or create lead details + $lead->leadDetail()->updateOrCreate( + ['client_id' => $lead->id], + [ + 'contact_date' => $request->contact_date, + 'contract_end_date' => $request->contract_end_date, + 'contract_type' => $request->contract_type, + 'delivery_point_code' => $request->delivery_point_code, + ] + ); + + return $lead->load('leadDetail'); + } + + /** + * Convert a lead into a client. + */ + public function convert($id) + { + $lead = Client::where('type', 'lead')->findOrFail($id); + + $lead->update([ + 'type' => 'client', + 'lead_status_id' => null, + 'status' => 'A', + ]); + + return $lead; + } + + /** + * Remove the specified lead from storage. + */ + public function destroy($id) + { + $lead = Client::where('type', 'lead')->findOrFail($id); + $lead->delete(); + + return [ + 'status' => 'success', + 'message' => 'Lead removed successfully!' + ]; + } +} diff --git a/app/Services/ResourceService.php b/app/Services/ResourceService.php new file mode 100644 index 0000000..4bc2d20 --- /dev/null +++ b/app/Services/ResourceService.php @@ -0,0 +1,78 @@ + PowerTier::class, + 'contract_types' => ContractType::class, + 'payment_methods' => PaymentMethod::class, + 'typologies' => Typology::class, + 'cui_tiers' => CuiTier::class, + 'suppliers' => Supplier::class, + 'contract-statuses' => ContractStatus::class, + ]; + + private function model(string $resource): string + { + abort_unless(isset(self::MODELS[$resource]), 404); + return self::MODELS[$resource]; + } + + public function all(string $resource) + { + return $this->model($resource)::orderBy('id')->get(); + } + + public function find(string $resource, $id): Model + { + $model = $this->model($resource)::findOrFail($id); + if ($resource === 'suppliers') { + abort_unless($model->status === 'A', 403, 'Este fornecedor esta inativo.'); + } + return $model; + } + + public function save(string $resource, Request $request, $id = null): Model + { + $modelClass = $this->model($resource); + $model = $id === null ? new $modelClass() : $this->find($resource, $id); + $rules = match ($resource) { + 'contract_types', 'typologies' => ['description' => 'required|string|max:255'], + 'payment_methods' => ['name' => 'required|string|max:255', 'icon' => 'required|string|max:255'], + 'suppliers' => ['name' => 'required|string|max:255', 'color' => 'nullable|string|max:20'], + 'contract-statuses' => [ + 'code' => ['required', 'string', 'max:10', Rule::unique($model->getTable(), 'code')->ignore($model->getKey())], + 'description' => 'required|string|max:255', + 'color' => ['nullable', 'string', 'regex:/^#([A-Fa-f0-9]{6})$/'], + ], + default => ['name' => 'required|string|max:255'], + }; + $model->fill($request->validate($rules)); + if ($resource === 'suppliers' && $id === null) { + $model->status = 'A'; + } + $model->save(); + $this->invalidate($resource); + return $model; + } + + public function delete(string $resource, $id): void + { + $model = $this->model($resource)::findOrFail($id); + $resource === 'contract-statuses' ? $model->delete() : $model->update(['status' => 'I']); + $this->invalidate($resource); + } + + private function invalidate(string $resource): void + { + Cache::forget($resource === 'contract-statuses' ? 'contract_statuses' : $resource); + } +} diff --git a/app/Services/RolePermissionService.php b/app/Services/RolePermissionService.php new file mode 100644 index 0000000..6f1d7c9 --- /dev/null +++ b/app/Services/RolePermissionService.php @@ -0,0 +1,25 @@ + Role::with('permissions')->get(), + 'permissions' => Permission::all(), + ]; + } + + public function updatePermissions(Request $request, Role $role) + { + $request->validate(['permissions' => 'sometimes|array', 'permissions.*' => 'exists:permissions,name']); + $role->syncPermissions($request->input('permissions', [])); + return $role->load('permissions'); + } +} diff --git a/app/Services/UserAccessService.php b/app/Services/UserAccessService.php new file mode 100644 index 0000000..b5402f4 --- /dev/null +++ b/app/Services/UserAccessService.php @@ -0,0 +1,25 @@ + User::with('roles')->get(), + 'roles' => Role::all(), + ]; + } + + public function updateRoles(Request $request, User $user) + { + $request->validate(['roles' => 'sometimes|array', 'roles.*' => 'exists:roles,name']); + $user->syncRoles($request->input('roles', [])); + return $user->load('roles'); + } +} diff --git a/app/Services/UserService.php b/app/Services/UserService.php new file mode 100644 index 0000000..ae5075a --- /dev/null +++ b/app/Services/UserService.php @@ -0,0 +1,139 @@ +paginate(20); + return compact('users'); + } + + public function create() + { + $roles = Role::where('id', '!=', 1)->get(); + return compact('roles'); + } + + public function store(Request $request) + { + $validator = Validator::make($request->all(), [ + 'name' => 'required|string|max:255', + 'email' => 'required|email|unique:users,email', + 'roles' => 'array|nullable', + 'roles.*' => 'exists:roles,name', + ]); + + $validator->validate(); + + $canLogin = $request->boolean('can_login'); + $password = Str::random(12); + + $user = User::create([ + 'name' => $request->name, + 'email' => $request->email, + 'password' => Hash::make($password), + 'can_login' => $canLogin, + ]); + + if ($request->filled('roles')) { + $user->syncRoles($request->roles); + } + + if ($canLogin) { + Mail::to($user->email)->send(new NewUserWelcome($user, $password)); + } + + Cache::forget('sellers'); + return $user; + } + + public function edit(User $user) + { + $roles = Role::where('id', '!=', 1)->get(); + return compact('user', 'roles'); + } + + public function update(Request $request, User $user) + { + $validator = Validator::make($request->all(), [ + 'name' => 'required|string|max:255', + 'email' => 'required|email|unique:users,email,' . $user->id, + 'roles' => 'array|nullable', + 'roles.*' => 'exists:roles,name', + ]); + + $validator->validate(); + + $user->update([ + 'name' => $request->name, + 'email' => $request->email, + 'can_login' => $request->boolean('can_login'), + ]); + + if ($request->has('roles')) { + $user->syncRoles($request->input('roles', [])); + } + + Cache::forget('sellers'); + return $user; + } + + public function sendPasswordResetLink(User $user) + { + $status = $this->authentication->sendResetLink(['email' => $user->email]); + + return $status; + } + + public function savePin(Request $request) + { + $request->validate([ + 'pin' => ['required', 'digits:4'], + ]); + + $user = $request->user(); + + /** @var User $user */ + $user->pin = Hash::make($request->pin); + $user->save(); + + return ['message' => 'PIN saved successfully.']; + } + + public function checkPin(Request $request) + { + $request->validate([ + 'pin' => ['required', 'digits:4'] + ]); + + $user = $request->user(); + if ($user->pin && Hash::check($request->pin, $user->pin)) { + return ['message' => 'PIN valid']; + } + + throw \Illuminate\Validation\ValidationException::withMessages(['pin' => 'Invalid PIN']); + } + + public function destroy(User $user): void + { + $user->tokens()->delete(); + $user->delete(); + Cache::forget('sellers'); + } +} diff --git a/app/Traits/ResourcesCache.php b/app/Traits/ResourcesCache.php new file mode 100644 index 0000000..5d310eb --- /dev/null +++ b/app/Traits/ResourcesCache.php @@ -0,0 +1,130 @@ +cacheTime(), + fn() => ContractStatus::all() + ); + } + + /** + * Get active contract types, cached. + */ + public function _getContractTypes() + { + return Cache::remember( + 'contract_types', + $this->cacheTime(), + fn() => ContractType::where('status', 'A')->get() + ); + } + + /** + * Get active payment methods, cached. + */ + public function _getPaymentMethods() + { + return Cache::remember( + 'payment_methods', + $this->cacheTime(), + fn() => PaymentMethod::where('status', 'A')->get() + ); + } + + /** + * Get active power tiers, cached. + */ + public function _getPowerTiers() + { + return Cache::remember( + 'power_tiers', + $this->cacheTime(), + fn() => PowerTier::where('status', 'A')->get() + ); + } + + /** + * Get active CUI tiers, cached. + */ + public function _getCuiTiers() + { + return Cache::remember( + 'cui_tiers', + $this->cacheTime(), + fn() => CuiTier::where('status', 'A')->get() + ); + } + + /** + * Get active suppliers, cached. + */ + public function _getSuppliers() + { + return Cache::remember( + 'suppliers', + $this->cacheTime(), + fn() => Supplier::where('status', 'A')->get() + ); + } + + /** + * Get active typologies, cached. + */ + public function _getTypologies() + { + return Cache::remember( + 'typologies', + $this->cacheTime(), + fn() => Typology::where('status', 'A')->get() + ); + } + + /** + * Get all sellers except the one with ID = 1, cached. + */ + public function _getSellers() + { + return Cache::remember( + 'sellers', + $this->cacheTime(), + fn() => User::where('id', '!=', 1)->get() + ); + } +} diff --git a/artisan b/artisan new file mode 100644 index 0000000..c35e31d --- /dev/null +++ b/artisan @@ -0,0 +1,18 @@ +#!/usr/bin/env php +handleCommand(new ArgvInput); + +exit($status); diff --git a/bootstrap/app.php b/bootstrap/app.php new file mode 100644 index 0000000..cdbc7e7 --- /dev/null +++ b/bootstrap/app.php @@ -0,0 +1,79 @@ +withRouting( + web: __DIR__.'/../routes/web.php', + api: __DIR__.'/../routes/api.php', + commands: __DIR__.'/../routes/console.php', + health: '/up', + ) + ->withMiddleware(function (Middleware $middleware) { + + $middleware->api(prepend: [\App\Http\Middleware\ApiResponse::class]); + + # Register Middleware + $middleware->alias([ + 'auth.session' => \App\Http\Middleware\AuthSession::class, + ]); + + }) + ->withExceptions(function (Exceptions $exceptions) { + $exceptions->reportable(function (Throwable $e) { + + }); + + $exceptions->render(function (Throwable $e, $request) { + if ($request->is('api/*') || $request->expectsJson()) { + $status = 500; + $message = $e->getMessage() ?: 'Erro interno do servidor'; + + if ($e instanceof \Illuminate\Validation\ValidationException) { + return response()->json([ + 'message' => 'Erro de validação.', + 'errors' => $e->errors(), + ], 422); + } + + if ($e instanceof \Illuminate\Auth\AuthenticationException) { + return response()->json(['message' => 'Nao autenticado.'], 401); + } + + if ($e instanceof \Illuminate\Auth\Access\AuthorizationException) { + return response()->json(['message' => 'Acesso negado.'], 403); + } + + if ($e instanceof \Illuminate\Database\Eloquent\ModelNotFoundException) { + return response()->json(['message' => 'Registo nao encontrado.'], 404); + } + + if ($e instanceof \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface) { + $status = $e->getStatusCode(); + $message = $e->getMessage() ?: 'Erro HTTP'; + } + + return response()->json([ + 'message' => $status >= 500 && app()->environment('production') ? 'Erro interno do servidor.' : $message, + 'exception' => app()->environment('production') ? null : get_class($e), + ], $status); + } + + return null; + }); + }) + ->withSchedule(function (Schedule $schedule) { + // $schedule->command('backup:run')->dailyAt('13:00'); + // $schedule->command('backup:clean-minio')->dailyAt('13:30'); + $schedule->command('sanctum:prune-expired --hours=24')->dailyAt('05:00'); + }) + ->booted(function () { + if (config('app.force_ssl')) { + URL::forceScheme('https'); + } + }) + ->create(); diff --git a/bootstrap/cache/.gitignore b/bootstrap/cache/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/bootstrap/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/bootstrap/providers.php b/bootstrap/providers.php new file mode 100644 index 0000000..d544739 --- /dev/null +++ b/bootstrap/providers.php @@ -0,0 +1,6 @@ +=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5", + "yoast/phpunit-polyfills": "^1.0" + }, + "suggest": { + "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality." + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" + } + ], + "description": "AWS Common Runtime for PHP", + "homepage": "https://github.com/awslabs/aws-crt-php", + "keywords": [ + "amazon", + "aws", + "crt", + "sdk" + ], + "support": { + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.7" + }, + "time": "2024-10-18T22:15:13+00:00" + }, + { + "name": "aws/aws-sdk-php", + "version": "3.371.5", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "d40b962154a146901f71561519f9d9c5a3863a6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d40b962154a146901f71561519f9d9c5a3863a6e", + "reference": "d40b962154a146901f71561519f9d9c5a3863a6e", + "shasum": "" + }, + "require": { + "aws/aws-crt-php": "^1.2.3", + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/promises": "^2.0", + "guzzlehttp/psr7": "^2.4.5", + "mtdowling/jmespath.php": "^2.8.0", + "php": ">=8.1", + "psr/http-message": "^1.0 || ^2.0", + "symfony/filesystem": "^v5.4.45 || ^v6.4.3 || ^v7.1.0 || ^v8.0.0" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "composer/composer": "^2.7.8", + "dms/phpunit-arraysubset-asserts": "^0.4.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-sockets": "*", + "phpunit/phpunit": "^9.6", + "psr/cache": "^2.0 || ^3.0", + "psr/simple-cache": "^2.0 || ^3.0", + "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0", + "yoast/phpunit-polyfills": "^2.0" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-pcntl": "To use client-side monitoring", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Aws\\": "src/" + }, + "exclude-from-classmap": [ + "src/data/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "https://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "https://aws.amazon.com/sdk-for-php", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "support": { + "forum": "https://github.com/aws/aws-sdk-php/discussions", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.371.5" + }, + "time": "2026-03-04T19:06:59+00:00" + }, + { + "name": "brick/math", + "version": "0.14.8", + "source": { + "type": "git", + "url": "https://github.com/brick/math.git", + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629", + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629", + "shasum": "" + }, + "require": { + "php": "^8.2" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpstan/phpstan": "2.1.22", + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Brick\\Math\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Arbitrary-precision arithmetic library", + "keywords": [ + "Arbitrary-precision", + "BigInteger", + "BigRational", + "arithmetic", + "bigdecimal", + "bignum", + "bignumber", + "brick", + "decimal", + "integer", + "math", + "mathematics", + "rational" + ], + "support": { + "issues": "https://github.com/brick/math/issues", + "source": "https://github.com/brick/math/tree/0.14.8" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + } + ], + "time": "2026-02-10T14:33:43+00:00" + }, + { + "name": "carbonphp/carbon-doctrine-types", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git", + "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/18ba5ddfec8976260ead6e866180bd5d2f71aa1d", + "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "conflict": { + "doctrine/dbal": "<4.0.0 || >=5.0.0" + }, + "require-dev": { + "doctrine/dbal": "^4.0.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Types to use Carbon in Doctrine", + "keywords": [ + "carbon", + "date", + "datetime", + "doctrine", + "time" + ], + "support": { + "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2024-02-09T16:56:22+00:00" + }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, + { + "name": "composer/semver", + "version": "3.4.4", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.4" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + } + ], + "time": "2025-08-20T19:15:30+00:00" + }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3" + }, + "time": "2024-07-08T12:26:09+00:00" + }, + { + "name": "doctrine/dbal", + "version": "4.4.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "476f7f0fa6ea4aa5364926db7fabdf6049075722" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/476f7f0fa6ea4aa5364926db7fabdf6049075722", + "reference": "476f7f0fa6ea4aa5364926db7fabdf6049075722", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.1.5", + "php": "^8.2", + "psr/cache": "^1|^2|^3", + "psr/log": "^1|^2|^3" + }, + "require-dev": { + "doctrine/coding-standard": "14.0.0", + "fig/log-test": "^1", + "jetbrains/phpstorm-stubs": "2023.2", + "phpstan/phpstan": "2.1.30", + "phpstan/phpstan-phpunit": "2.0.7", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "11.5.50", + "slevomat/coding-standard": "8.27.1", + "squizlabs/php_codesniffer": "4.0.1", + "symfony/cache": "^6.3.8|^7.0|^8.0", + "symfony/console": "^5.4|^6.3|^7.0|^8.0" + }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\DBAL\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.", + "homepage": "https://www.doctrine-project.org/projects/dbal.html", + "keywords": [ + "abstraction", + "database", + "db2", + "dbal", + "mariadb", + "mssql", + "mysql", + "oci8", + "oracle", + "pdo", + "pgsql", + "postgresql", + "queryobject", + "sasql", + "sql", + "sqlite", + "sqlserver", + "sqlsrv" + ], + "support": { + "issues": "https://github.com/doctrine/dbal/issues", + "source": "https://github.com/doctrine/dbal/tree/4.4.2" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal", + "type": "tidelift" + } + ], + "time": "2026-02-26T12:12:19+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "1.1.6", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=14" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^12 || ^14", + "phpstan/phpstan": "1.4.10 || 2.1.30", + "phpstan/phpstan-phpunit": "^1.0 || ^2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0", + "psr/log": "^1 || ^2 || ^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.6" + }, + "time": "2026-02-07T07:09:04+00:00" + }, + { + "name": "doctrine/inflector", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^12.0 || ^13.0", + "phpstan/phpstan": "^1.12 || ^2.0", + "phpstan/phpstan-phpunit": "^1.4 || ^2.0", + "phpstan/phpstan-strict-rules": "^1.6 || ^2.0", + "phpunit/phpunit": "^8.5 || ^12.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.1.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2025-08-10T19:31:58+00:00" + }, + { + "name": "doctrine/lexer", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2024-02-05T11:56:58+00:00" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/d61a8a9604ec1f8c3d150d09db6ce98b32675013", + "reference": "d61a8a9604ec1f8c3d150d09db6ce98b32675013", + "shasum": "" + }, + "require": { + "php": "^8.2|^8.3|^8.4|^8.5" + }, + "replace": { + "mtdowling/cron-expression": "^1.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.32|^2.1.31", + "phpunit/phpunit": "^8.5.48|^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "time": "2025-10-31T18:51:33+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2025-03-06T22:45:56+00:00" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.19.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/b287d2a16aceffbf6e0295559b39662612b77fcf", + "reference": "b287d2a16aceffbf6e0295559b39662612b77fcf", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.19.0" + }, + "time": "2025-10-17T16:34:55+00:00" + }, + { + "name": "fruitcake/php-cors", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/fruitcake/php-cors.git", + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", + "reference": "38aaa6c3fd4c157ffe2a4d10aa8b9b16ba8de379", + "shasum": "" + }, + "require": { + "php": "^8.1", + "symfony/http-foundation": "^5.4|^6.4|^7.3|^8" + }, + "require-dev": { + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^9", + "squizlabs/php_codesniffer": "^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Fruitcake\\Cors\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fruitcake", + "homepage": "https://fruitcake.nl" + }, + { + "name": "Barryvdh", + "email": "barryvdh@gmail.com" + } + ], + "description": "Cross-origin resource sharing library for the Symfony HttpFoundation", + "homepage": "https://github.com/fruitcake/php-cors", + "keywords": [ + "cors", + "laravel", + "symfony" + ], + "support": { + "issues": "https://github.com/fruitcake/php-cors/issues", + "source": "https://github.com/fruitcake/php-cors/tree/v1.4.0" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2025-12-03T09:33:47+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.4", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/e01f4a821471308ba86aa202fed6698b6b695e3b", + "reference": "e01f4a821471308ba86aa202fed6698b6b695e3b", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.41 || ^9.6.22 || ^10.5.45 || ^11.5.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:43:20+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.10.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.10.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2025-08-23T22:36:01+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "481557b130ef3790cf82b713667b43030dc9c957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2025-08-22T14:34:08+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "21dc724a0583619cd1652f673303492272778051" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.8.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2025-08-23T21:21:41+00:00" + }, + { + "name": "guzzlehttp/uri-template", + "version": "v1.0.5", + "source": { + "type": "git", + "url": "https://github.com/guzzle/uri-template.git", + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/4f4bbd4e7172148801e76e3decc1e559bdee34e1", + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25", + "uri-template/tests": "1.0.0" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\UriTemplate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + } + ], + "description": "A polyfill class for uri_template of PHP", + "keywords": [ + "guzzlehttp", + "uri-template" + ], + "support": { + "issues": "https://github.com/guzzle/uri-template/issues", + "source": "https://github.com/guzzle/uri-template/tree/v1.0.5" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/uri-template", + "type": "tidelift" + } + ], + "time": "2025-08-22T14:27:06+00:00" + }, + { + "name": "laravel/framework", + "version": "v12.53.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "f57f035c0d34503d9ff30be76159bb35a003cd1f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/f57f035c0d34503d9ff30be76159bb35a003cd1f", + "reference": "f57f035c0d34503d9ff30be76159bb35a003cd1f", + "shasum": "" + }, + "require": { + "brick/math": "^0.11|^0.12|^0.13|^0.14", + "composer-runtime-api": "^2.2", + "doctrine/inflector": "^2.0.5", + "dragonmantank/cron-expression": "^3.4", + "egulias/email-validator": "^3.2.1|^4.0", + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-session": "*", + "ext-tokenizer": "*", + "fruitcake/php-cors": "^1.3", + "guzzlehttp/guzzle": "^7.8.2", + "guzzlehttp/uri-template": "^1.0", + "laravel/prompts": "^0.3.0", + "laravel/serializable-closure": "^1.3|^2.0", + "league/commonmark": "^2.7", + "league/flysystem": "^3.25.1", + "league/flysystem-local": "^3.25.1", + "league/uri": "^7.5.1", + "monolog/monolog": "^3.0", + "nesbot/carbon": "^3.8.4", + "nunomaduro/termwind": "^2.0", + "php": "^8.2", + "psr/container": "^1.1.1|^2.0.1", + "psr/log": "^1.0|^2.0|^3.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "ramsey/uuid": "^4.7", + "symfony/console": "^7.2.0", + "symfony/error-handler": "^7.2.0", + "symfony/finder": "^7.2.0", + "symfony/http-foundation": "^7.2.0", + "symfony/http-kernel": "^7.2.0", + "symfony/mailer": "^7.2.0", + "symfony/mime": "^7.2.0", + "symfony/polyfill-php83": "^1.33", + "symfony/polyfill-php84": "^1.33", + "symfony/polyfill-php85": "^1.33", + "symfony/process": "^7.2.0", + "symfony/routing": "^7.2.0", + "symfony/uid": "^7.2.0", + "symfony/var-dumper": "^7.2.0", + "tijsverkoyen/css-to-inline-styles": "^2.2.5", + "vlucas/phpdotenv": "^5.6.1", + "voku/portable-ascii": "^2.0.2" + }, + "conflict": { + "tightenco/collect": "<5.5.33" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "psr/log-implementation": "1.0|2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0" + }, + "replace": { + "illuminate/auth": "self.version", + "illuminate/broadcasting": "self.version", + "illuminate/bus": "self.version", + "illuminate/cache": "self.version", + "illuminate/collections": "self.version", + "illuminate/concurrency": "self.version", + "illuminate/conditionable": "self.version", + "illuminate/config": "self.version", + "illuminate/console": "self.version", + "illuminate/container": "self.version", + "illuminate/contracts": "self.version", + "illuminate/cookie": "self.version", + "illuminate/database": "self.version", + "illuminate/encryption": "self.version", + "illuminate/events": "self.version", + "illuminate/filesystem": "self.version", + "illuminate/hashing": "self.version", + "illuminate/http": "self.version", + "illuminate/json-schema": "self.version", + "illuminate/log": "self.version", + "illuminate/macroable": "self.version", + "illuminate/mail": "self.version", + "illuminate/notifications": "self.version", + "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", + "illuminate/process": "self.version", + "illuminate/queue": "self.version", + "illuminate/redis": "self.version", + "illuminate/reflection": "self.version", + "illuminate/routing": "self.version", + "illuminate/session": "self.version", + "illuminate/support": "self.version", + "illuminate/testing": "self.version", + "illuminate/translation": "self.version", + "illuminate/validation": "self.version", + "illuminate/view": "self.version", + "spatie/once": "*" + }, + "require-dev": { + "ably/ably-php": "^1.0", + "aws/aws-sdk-php": "^3.322.9", + "ext-gmp": "*", + "fakerphp/faker": "^1.24", + "guzzlehttp/promises": "^2.0.3", + "guzzlehttp/psr7": "^2.4", + "laravel/pint": "^1.18", + "league/flysystem-aws-s3-v3": "^3.25.1", + "league/flysystem-ftp": "^3.25.1", + "league/flysystem-path-prefixing": "^3.25.1", + "league/flysystem-read-only": "^3.25.1", + "league/flysystem-sftp-v3": "^3.25.1", + "mockery/mockery": "^1.6.10", + "opis/json-schema": "^2.4.1", + "orchestra/testbench-core": "^10.9.0", + "pda/pheanstalk": "^5.0.6|^7.0.0", + "php-http/discovery": "^1.15", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", + "predis/predis": "^2.3|^3.0", + "resend/resend-php": "^0.10.0|^1.0", + "symfony/cache": "^7.2.0", + "symfony/http-client": "^7.2.0", + "symfony/psr-http-message-bridge": "^7.2.0", + "symfony/translation": "^7.2.0" + }, + "suggest": { + "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.322.9).", + "brianium/paratest": "Required to run tests in parallel (^7.0|^8.0).", + "ext-apcu": "Required to use the APC cache driver.", + "ext-fileinfo": "Required to use the Filesystem class.", + "ext-ftp": "Required to use the Flysystem FTP driver.", + "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", + "ext-memcached": "Required to use the memcache cache driver.", + "ext-pcntl": "Required to use all features of the queue worker and console signal trapping.", + "ext-pdo": "Required to use all database features.", + "ext-posix": "Required to use all features of the queue worker.", + "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0|^6.0).", + "fakerphp/faker": "Required to generate fake data using the fake() helper (^1.23).", + "filp/whoops": "Required for friendly error pages in development (^2.14.3).", + "laravel/tinker": "Required to use the tinker console command (^2.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).", + "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.25.1).", + "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.25.1).", + "league/flysystem-read-only": "Required to use read-only disks (^3.25.1)", + "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.25.1).", + "mockery/mockery": "Required to use mocking (^1.6).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", + "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", + "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.5.3|^12.0.1).", + "predis/predis": "Required to use the predis connector (^2.3|^3.0).", + "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", + "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0|^1.0).", + "symfony/cache": "Required to PSR-6 cache bridge (^7.2).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).", + "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.2).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.2).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.2).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.2)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "12.x-dev" + } + }, + "autoload": { + "files": [ + "src/Illuminate/Collections/functions.php", + "src/Illuminate/Collections/helpers.php", + "src/Illuminate/Events/functions.php", + "src/Illuminate/Filesystem/functions.php", + "src/Illuminate/Foundation/helpers.php", + "src/Illuminate/Log/functions.php", + "src/Illuminate/Reflection/helpers.php", + "src/Illuminate/Support/functions.php", + "src/Illuminate/Support/helpers.php" + ], + "psr-4": { + "Illuminate\\": "src/Illuminate/", + "Illuminate\\Support\\": [ + "src/Illuminate/Macroable/", + "src/Illuminate/Collections/", + "src/Illuminate/Conditionable/", + "src/Illuminate/Reflection/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Laravel Framework.", + "homepage": "https://laravel.com", + "keywords": [ + "framework", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2026-02-24T14:35:15+00:00" + }, + { + "name": "laravel/prompts", + "version": "v0.3.13", + "source": { + "type": "git", + "url": "https://github.com/laravel/prompts.git", + "reference": "ed8c466571b37e977532fb2fd3c272c784d7050d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/prompts/zipball/ed8c466571b37e977532fb2fd3c272c784d7050d", + "reference": "ed8c466571b37e977532fb2fd3c272c784d7050d", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.2", + "ext-mbstring": "*", + "php": "^8.1", + "symfony/console": "^6.2|^7.0|^8.0" + }, + "conflict": { + "illuminate/console": ">=10.17.0 <10.25.0", + "laravel/framework": ">=10.17.0 <10.25.0" + }, + "require-dev": { + "illuminate/collections": "^10.0|^11.0|^12.0|^13.0", + "mockery/mockery": "^1.5", + "pestphp/pest": "^2.3|^3.4|^4.0", + "phpstan/phpstan": "^1.12.28", + "phpstan/phpstan-mockery": "^1.1.3" + }, + "suggest": { + "ext-pcntl": "Required for the spinner to be animated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.3.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Laravel\\Prompts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Add beautiful and user-friendly forms to your command-line applications.", + "support": { + "issues": "https://github.com/laravel/prompts/issues", + "source": "https://github.com/laravel/prompts/tree/v0.3.13" + }, + "time": "2026-02-06T12:17:10+00:00" + }, + { + "name": "laravel/sanctum", + "version": "v4.3.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/sanctum.git", + "reference": "e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76", + "reference": "e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/console": "^11.0|^12.0|^13.0", + "illuminate/contracts": "^11.0|^12.0|^13.0", + "illuminate/database": "^11.0|^12.0|^13.0", + "illuminate/support": "^11.0|^12.0|^13.0", + "php": "^8.2", + "symfony/console": "^7.0|^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.6", + "orchestra/testbench": "^9.15|^10.8|^11.0", + "phpstan/phpstan": "^1.10" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sanctum\\SanctumServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sanctum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.", + "keywords": [ + "auth", + "laravel", + "sanctum" + ], + "support": { + "issues": "https://github.com/laravel/sanctum/issues", + "source": "https://github.com/laravel/sanctum" + }, + "time": "2026-02-07T17:19:31+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v2.0.10", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "870fc81d2f879903dfc5b60bf8a0f94a1609e669" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/870fc81d2f879903dfc5b60bf8a0f94a1609e669", + "reference": "870fc81d2f879903dfc5b60bf8a0f94a1609e669", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0|^11.0|^12.0|^13.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0|^4.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0|^8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2026-02-20T19:59:49+00:00" + }, + { + "name": "laravel/tinker", + "version": "v2.11.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/c9f80cc835649b5c1842898fb043f8cc098dd741", + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741", + "shasum": "" + }, + "require": { + "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "php": "^7.2.5|^8.0", + "psy/psysh": "^0.11.1|^0.12.0", + "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0|^8.0" + }, + "require-dev": { + "mockery/mockery": "~1.3.3|^1.4.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.5.8|^9.3.3|^10.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0)." + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Tinker\\TinkerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Tinker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Powerful REPL for the Laravel framework.", + "keywords": [ + "REPL", + "Tinker", + "laravel", + "psysh" + ], + "support": { + "issues": "https://github.com/laravel/tinker/issues", + "source": "https://github.com/laravel/tinker/tree/v2.11.1" + }, + "time": "2026-02-06T14:12:35+00:00" + }, + { + "name": "laravel/ui", + "version": "v4.6.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/ui.git", + "reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/ui/zipball/7d6ffa38d79f19c9b3e70a751a9af845e8f41d88", + "reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88", + "shasum": "" + }, + "require": { + "illuminate/console": "^9.21|^10.0|^11.0|^12.0", + "illuminate/filesystem": "^9.21|^10.0|^11.0|^12.0", + "illuminate/support": "^9.21|^10.0|^11.0|^12.0", + "illuminate/validation": "^9.21|^10.0|^11.0|^12.0", + "php": "^8.0", + "symfony/console": "^6.0|^7.0" + }, + "require-dev": { + "orchestra/testbench": "^7.35|^8.15|^9.0|^10.0", + "phpunit/phpunit": "^9.3|^10.4|^11.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Ui\\UiServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Ui\\": "src/", + "Illuminate\\Foundation\\Auth\\": "auth-backend/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel UI utilities and presets.", + "keywords": [ + "laravel", + "ui" + ], + "support": { + "source": "https://github.com/laravel/ui/tree/v4.6.1" + }, + "time": "2025-01-28T15:15:29+00:00" + }, + { + "name": "league/commonmark", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/4efa10c1e56488e658d10adf7b7b7dcd19940bfb", + "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.31.1", + "commonmark/commonmark.js": "0.31.1", + "composer/package-versions-deprecated": "^1.8", + "embed/embed": "^4.4", + "erusev/parsedown": "^1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "^1.4 || ^2.0", + "nyholm/psr7": "^1.5", + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", + "scrutinizer/ocular": "^1.8.1", + "symfony/finder": "^5.3 | ^6.0 | ^7.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", + "unleashedtech/php-coding-standard": "^3.1.1", + "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.9-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "support": { + "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", + "issues": "https://github.com/thephpleague/commonmark/issues", + "rss": "https://github.com/thephpleague/commonmark/releases.atom", + "source": "https://github.com/thephpleague/commonmark" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/commonmark", + "type": "tidelift" + } + ], + "time": "2025-11-26T21:48:24+00:00" + }, + { + "name": "league/config", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/config.git", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/config/zipball/754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "time": "2022-12-11T20:36:23+00:00" + }, + { + "name": "league/flysystem", + "version": "3.32.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "254b1595b16b22dbddaaef9ed6ca9fdac4956725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/254b1595b16b22dbddaaef9ed6ca9fdac4956725", + "reference": "254b1595b16b22dbddaaef9ed6ca9fdac4956725", + "shasum": "" + }, + "require": { + "league/flysystem-local": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "async-aws/core": "<1.19.0", + "async-aws/s3": "<1.14.0", + "aws/aws-sdk-php": "3.209.31 || 3.210.0", + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1", + "phpseclib/phpseclib": "3.0.15", + "symfony/http-client": "<5.2" + }, + "require-dev": { + "async-aws/s3": "^1.5 || ^2.0", + "async-aws/simple-s3": "^1.1 || ^2.0", + "aws/aws-sdk-php": "^3.295.10", + "composer/semver": "^3.0", + "ext-fileinfo": "*", + "ext-ftp": "*", + "ext-mongodb": "^1.3|^2", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.5", + "google/cloud-storage": "^1.23", + "guzzlehttp/psr7": "^2.6", + "microsoft/azure-storage-blob": "^1.1", + "mongodb/mongodb": "^1.2|^2", + "phpseclib/phpseclib": "^3.0.36", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.11|^10.0", + "sabre/dav": "^4.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "File storage abstraction for PHP", + "keywords": [ + "WebDAV", + "aws", + "cloud", + "file", + "files", + "filesystem", + "filesystems", + "ftp", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/3.32.0" + }, + "time": "2026-02-25T17:01:41+00:00" + }, + { + "name": "league/flysystem-aws-s3-v3", + "version": "3.32.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", + "reference": "a1979df7c9784d334ea6df356aed3d18ac6673d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/a1979df7c9784d334ea6df356aed3d18ac6673d0", + "reference": "a1979df7c9784d334ea6df356aed3d18ac6673d0", + "shasum": "" + }, + "require": { + "aws/aws-sdk-php": "^3.295.10", + "league/flysystem": "^3.10.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\AwsS3V3\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "AWS S3 filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "aws", + "file", + "files", + "filesystem", + "s3", + "storage" + ], + "support": { + "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.32.0" + }, + "time": "2026-02-25T16:46:44+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.31.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/2f669db18a4c20c755c2bb7d3a7b0b2340488079", + "reference": "2f669db18a4c20c755c2bb7d3a7b0b2340488079", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "source": "https://github.com/thephpleague/flysystem-local/tree/3.31.0" + }, + "time": "2026-01-23T15:30:45+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.16.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2024-09-21T08:32:55+00:00" + }, + { + "name": "league/uri", + "version": "7.8.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "4436c6ec8d458e4244448b069cc572d088230b76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76", + "reference": "4436c6ec8d458e4244448b069cc572d088230b76", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.8", + "php": "^8.1", + "psr/http-factory": "^1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-dom": "to convert the URI into an HTML anchor tag", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "ext-uri": "to use the PHP native URI class", + "jeremykendall/php-domain-parser": "to further parse the URI host and resolve its Public Suffix and Top Level Domain", + "league/uri-components": "to provide additional tools to manipulate URI objects components", + "league/uri-polyfill": "to backport the PHP URI extension for older versions of PHP", + "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "URN", + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc2141", + "rfc3986", + "rfc3987", + "rfc6570", + "rfc8141", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri/tree/7.8.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2026-01-14T17:24:56+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "7.8.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4", + "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.1", + "psr/http-message": "^1.1 || ^2.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "php-64bit": "to improve IPV4 host parsing", + "rowbot/url": "to handle URLs using the WHATWG URL Living Standard specification", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common tools for parsing and resolving RFC3987/RFC3986 URI", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2026-01-15T06:54:53+00:00" + }, + { + "name": "maatwebsite/excel", + "version": "3.1.67", + "source": { + "type": "git", + "url": "https://github.com/SpartnerNL/Laravel-Excel.git", + "reference": "e508e34a502a3acc3329b464dad257378a7edb4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/e508e34a502a3acc3329b464dad257378a7edb4d", + "reference": "e508e34a502a3acc3329b464dad257378a7edb4d", + "shasum": "" + }, + "require": { + "composer/semver": "^3.3", + "ext-json": "*", + "illuminate/support": "5.8.*||^6.0||^7.0||^8.0||^9.0||^10.0||^11.0||^12.0", + "php": "^7.0||^8.0", + "phpoffice/phpspreadsheet": "^1.30.0", + "psr/simple-cache": "^1.0||^2.0||^3.0" + }, + "require-dev": { + "laravel/scout": "^7.0||^8.0||^9.0||^10.0", + "orchestra/testbench": "^6.0||^7.0||^8.0||^9.0||^10.0", + "predis/predis": "^1.1" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Excel": "Maatwebsite\\Excel\\Facades\\Excel" + }, + "providers": [ + "Maatwebsite\\Excel\\ExcelServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Maatwebsite\\Excel\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Patrick Brouwers", + "email": "patrick@spartner.nl" + } + ], + "description": "Supercharged Excel exports and imports in Laravel", + "keywords": [ + "PHPExcel", + "batch", + "csv", + "excel", + "export", + "import", + "laravel", + "php", + "phpspreadsheet" + ], + "support": { + "issues": "https://github.com/SpartnerNL/Laravel-Excel/issues", + "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.67" + }, + "funding": [ + { + "url": "https://laravel-excel.com/commercial-support", + "type": "custom" + }, + { + "url": "https://github.com/patrickbrouwers", + "type": "github" + } + ], + "time": "2025-08-26T09:13:16+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "682f1098a8fddbaf43edac2306a691c7ad508ec5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/682f1098a8fddbaf43edac2306a691c7ad508ec5", + "reference": "682f1098a8fddbaf43edac2306a691c7ad508ec5", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-zlib": "*", + "php-64bit": "^8.3" + }, + "require-dev": { + "brianium/paratest": "^7.7", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.86", + "guzzlehttp/guzzle": "^7.5", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.5", + "phpunit/phpunit": "^12.0", + "vimeo/psalm": "^6.0" + }, + "suggest": { + "guzzlehttp/psr7": "^2.4", + "psr/http-message": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + } + ], + "time": "2025-12-10T09:58:31+00:00" + }, + { + "name": "markbaker/complex", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" + }, + "time": "2022-12-06T16:21:08+00:00" + }, + { + "name": "markbaker/matrix", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" + }, + "time": "2022-12-02T22:17:43+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.10.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8 || ^2.0", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", + "predis/predis": "^1.1 || ^2", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/3.10.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2026-01-02T08:56:05+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0" + }, + "time": "2024-09-04T18:46:31+00:00" + }, + { + "name": "nesbot/carbon", + "version": "3.11.1", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "f438fcc98f92babee98381d399c65336f3a3827f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/f438fcc98f92babee98381d399c65336f3a3827f", + "reference": "f438fcc98f92babee98381d399c65336f3a3827f", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "<100.0", + "ext-json": "*", + "php": "^8.1", + "psr/clock": "^1.0", + "symfony/clock": "^6.3.12 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0 || ^8.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "doctrine/dbal": "^3.6.3 || ^4.0", + "doctrine/orm": "^2.15.2 || ^3.0", + "friendsofphp/php-cs-fixer": "^v3.87.1", + "kylekatarnls/multi-tester": "^2.5.3", + "phpmd/phpmd": "^2.15.0", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.22", + "phpunit/phpunit": "^10.5.53", + "squizlabs/php_codesniffer": "^3.13.4 || ^4.0.0" + }, + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbonphp.github.io/carbon/", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbonphp.github.io/carbon/guide/getting-started/introduction.html", + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon" + }, + "funding": [ + { + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", + "type": "tidelift" + } + ], + "time": "2026-01-29T09:26:29+00:00" + }, + { + "name": "nette/schema", + "version": "v1.3.5", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002", + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002", + "shasum": "" + }, + "require": { + "nette/utils": "^4.0", + "php": "8.1 - 8.5" + }, + "require-dev": { + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.6", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1.39@stable", + "tracy/tracy": "^2.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.3.5" + }, + "time": "2026-02-23T03:47:12+00:00" + }, + { + "name": "nette/utils", + "version": "v4.1.3", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe", + "shasum": "" + }, + "require": { + "php": "8.2 - 8.5" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.5", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.1.3" + }, + "time": "2026-02-13T03:05:33+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.7.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" + }, + "time": "2025-12-06T11:56:16+00:00" + }, + { + "name": "nunomaduro/termwind", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/termwind.git", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^8.2", + "symfony/console": "^7.4.4 || ^8.0.4" + }, + "require-dev": { + "illuminate/console": "^11.47.0", + "laravel/pint": "^1.27.1", + "mockery/mockery": "^1.6.12", + "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2", + "phpstan/phpstan": "^1.12.32", + "phpstan/phpstan-strict-rules": "^1.6.2", + "symfony/var-dumper": "^7.3.5 || ^8.0.4", + "thecodingmachine/phpstan-strict-rules": "^1.0.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Termwind\\Laravel\\TermwindServiceProvider" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/Functions.php" + ], + "psr-4": { + "Termwind\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "It's like Tailwind CSS, but for the console.", + "keywords": [ + "cli", + "console", + "css", + "package", + "php", + "style" + ], + "support": { + "issues": "https://github.com/nunomaduro/termwind/issues", + "source": "https://github.com/nunomaduro/termwind/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://github.com/xiCO2k", + "type": "github" + } + ], + "time": "2026-02-16T23:10:27+00:00" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.30.2", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "09cdde5e2f078b9a3358dd217e2c8cb4dac84be2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/09cdde5e2f078b9a3358dd217e2c8cb4dac84be2", + "reference": "09cdde5e2f078b9a3358dd217e2c8cb4dac84be2", + "shasum": "" + }, + "require": { + "composer/pcre": "^1||^2||^3", + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.15", + "maennchen/zipstream-php": "^2.1 || ^3.0", + "markbaker/complex": "^3.0", + "markbaker/matrix": "^3.0", + "php": ">=7.4.0 <8.5.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-main", + "doctrine/instantiator": "^1.5", + "dompdf/dompdf": "^1.0 || ^2.0 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.2", + "mitoteam/jpgraph": "^10.3", + "mpdf/mpdf": "^8.1.1", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^8.5 || ^9.0", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "ext-intl": "PHP Internationalization Functions", + "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + }, + { + "name": "Owen Leibman" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.30.2" + }, + "time": "2026-01-11T05:58:24+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.5", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/75365b91986c2405cf5e1e012c5595cd487a98be", + "reference": "75365b91986c2405cf5e1e012c5595cd487a98be", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.5" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:41:33+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, + { + "name": "psy/psysh", + "version": "v0.12.20", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/19678eb6b952a03b8a1d96ecee9edba518bb0373", + "reference": "19678eb6b952a03b8a1d96ecee9edba518bb0373", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "nikic/php-parser": "^5.0 || ^4.0", + "php": "^8.0 || ^7.4", + "symfony/console": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^8.0 || ^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" + }, + "conflict": { + "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", + "composer/class-map-generator": "^1.6" + }, + "suggest": { + "composer/class-map-generator": "Improved tab completion performance with better class discovery.", + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": false, + "forward-command": false + }, + "branch-alias": { + "dev-main": "0.12.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "https://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "support": { + "issues": "https://github.com/bobthecow/psysh/issues", + "source": "https://github.com/bobthecow/psysh/tree/v0.12.20" + }, + "time": "2026-02-11T15:05:28+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "ramsey/collection", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.45", + "fakerphp/faker": "^1.24", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^2.1", + "mockery/mockery": "^1.6", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpspec/prophecy-phpunit": "^2.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5", + "ramsey/coding-standard": "^2.3", + "ramsey/conventional-commits": "^1.6", + "roave/security-advisories": "dev-latest" + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/2.1.1" + }, + "time": "2025-03-22T05:38:12+00:00" + }, + { + "name": "ramsey/uuid", + "version": "4.9.2", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "8429c78ca35a09f27565311b98101e2826affde0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0", + "reference": "8429c78ca35a09f27565311b98101e2826affde0", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.25", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "ergebnis/composer-normalize": "^2.47", + "mockery/mockery": "^1.6", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.6", + "php-mock/php-mock-mockery": "^1.5", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpbench/phpbench": "^1.2.14", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6", + "slevomat/coding-standard": "^8.18", + "squizlabs/php_codesniffer": "^3.13" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.9.2" + }, + "time": "2025-12-14T04:43:48+00:00" + }, + { + "name": "spatie/db-dumper", + "version": "3.8.3", + "source": { + "type": "git", + "url": "https://github.com/spatie/db-dumper.git", + "reference": "eac3221fbe27fac51f388600d27b67b1b079406e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/db-dumper/zipball/eac3221fbe27fac51f388600d27b67b1b079406e", + "reference": "eac3221fbe27fac51f388600d27b67b1b079406e", + "shasum": "" + }, + "require": { + "php": "^8.0", + "symfony/process": "^5.0|^6.0|^7.0|^8.0" + }, + "require-dev": { + "pestphp/pest": "^1.22" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\DbDumper\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Dump databases", + "homepage": "https://github.com/spatie/db-dumper", + "keywords": [ + "database", + "db-dumper", + "dump", + "mysqldump", + "spatie" + ], + "support": { + "source": "https://github.com/spatie/db-dumper/tree/3.8.3" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2026-01-05T16:26:03+00:00" + }, + { + "name": "spatie/laravel-backup", + "version": "9.4.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-backup.git", + "reference": "0dff805039617b4a6f48291cef0697a73bc0392e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-backup/zipball/0dff805039617b4a6f48291cef0697a73bc0392e", + "reference": "0dff805039617b4a6f48291cef0697a73bc0392e", + "shasum": "" + }, + "require": { + "ext-zip": "^1.14.0", + "illuminate/console": "^12.40", + "illuminate/contracts": "^12.40", + "illuminate/events": "^12.40", + "illuminate/filesystem": "^12.40", + "illuminate/notifications": "^12.40", + "illuminate/support": "^12.40", + "league/flysystem": "^3.30.2", + "php": "^8.3", + "spatie/db-dumper": "^3.8.1", + "spatie/laravel-package-tools": "^1.92.7", + "spatie/laravel-signal-aware-command": "^2.1", + "spatie/temporary-directory": "^2.3", + "symfony/console": "^7.3.6|^8.0", + "symfony/finder": "^7.3.5|^8.0" + }, + "require-dev": { + "composer-runtime-api": "^2.0", + "ext-pcntl": "*", + "larastan/larastan": "^3.8", + "laravel/slack-notification-channel": "^3.7", + "league/flysystem-aws-s3-v3": "^3.30.1", + "mockery/mockery": "^1.6.12", + "orchestra/testbench": "^10.8", + "pestphp/pest": "^4.1.5", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.8", + "rector/rector": "^2.2.8" + }, + "suggest": { + "laravel/slack-notification-channel": "Required for sending notifications via Slack" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\Backup\\BackupServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/Helpers/functions.php" + ], + "psr-4": { + "Spatie\\Backup\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "A Laravel package to backup your application", + "homepage": "https://github.com/spatie/laravel-backup", + "keywords": [ + "backup", + "database", + "laravel-backup", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-backup/issues", + "source": "https://github.com/spatie/laravel-backup/tree/9.4.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/spatie", + "type": "github" + }, + { + "url": "https://spatie.be/open-source/support-us", + "type": "other" + } + ], + "time": "2026-02-15T19:05:20+00:00" + }, + { + "name": "spatie/laravel-package-tools", + "version": "1.93.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-package-tools.git", + "reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/0d097bce95b2bf6802fb1d83e1e753b0f5a948e7", + "reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^10.0|^11.0|^12.0|^13.0", + "php": "^8.1" + }, + "require-dev": { + "mockery/mockery": "^1.5", + "orchestra/testbench": "^8.0|^9.2|^10.0|^11.0", + "pestphp/pest": "^2.1|^3.1|^4.0", + "phpunit/php-code-coverage": "^10.0|^11.0|^12.0", + "phpunit/phpunit": "^10.5|^11.5|^12.5", + "spatie/pest-plugin-test-time": "^2.2|^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\LaravelPackageTools\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Tools for creating Laravel packages", + "homepage": "https://github.com/spatie/laravel-package-tools", + "keywords": [ + "laravel-package-tools", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-package-tools/issues", + "source": "https://github.com/spatie/laravel-package-tools/tree/1.93.0" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2026-02-21T12:49:54+00:00" + }, + { + "name": "spatie/laravel-permission", + "version": "6.24.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-permission.git", + "reference": "eefc9d17eba80d023d6bff313f882cb2bcd691a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/eefc9d17eba80d023d6bff313f882cb2bcd691a3", + "reference": "eefc9d17eba80d023d6bff313f882cb2bcd691a3", + "shasum": "" + }, + "require": { + "illuminate/auth": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/container": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^8.12|^9.0|^10.0|^11.0|^12.0", + "illuminate/database": "^8.12|^9.0|^10.0|^11.0|^12.0", + "php": "^8.0" + }, + "require-dev": { + "laravel/passport": "^11.0|^12.0", + "laravel/pint": "^1.0", + "orchestra/testbench": "^6.23|^7.0|^8.0|^9.0|^10.0", + "phpunit/phpunit": "^9.4|^10.1|^11.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\Permission\\PermissionServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "6.x-dev", + "dev-master": "6.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Spatie\\Permission\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Permission handling for Laravel 8.0 and up", + "homepage": "https://github.com/spatie/laravel-permission", + "keywords": [ + "acl", + "laravel", + "permission", + "permissions", + "rbac", + "roles", + "security", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-permission/issues", + "source": "https://github.com/spatie/laravel-permission/tree/6.24.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2026-02-09T21:10:03+00:00" + }, + { + "name": "spatie/laravel-signal-aware-command", + "version": "2.1.2", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-signal-aware-command.git", + "reference": "54dcc1efd152bfb3eb0faf56a5fc28569b864b5d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-signal-aware-command/zipball/54dcc1efd152bfb3eb0faf56a5fc28569b864b5d", + "reference": "54dcc1efd152bfb3eb0faf56a5fc28569b864b5d", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^11.0|^12.0|^13.0", + "php": "^8.2", + "spatie/laravel-package-tools": "^1.4.3", + "symfony/console": "^7.0|^8.0" + }, + "require-dev": { + "brianium/paratest": "^6.2|^7.0", + "ext-pcntl": "*", + "nunomaduro/collision": "^5.3|^6.0|^7.0|^8.0", + "orchestra/testbench": "^9.0|^10.0", + "pestphp/pest-plugin-laravel": "^1.3|^2.0|^3.0", + "phpunit/phpunit": "^9.5|^10|^11", + "spatie/laravel-ray": "^1.17" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Signal": "Spatie\\SignalAwareCommand\\Facades\\Signal" + }, + "providers": [ + "Spatie\\SignalAwareCommand\\SignalAwareCommandServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\SignalAwareCommand\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Handle signals in artisan commands", + "homepage": "https://github.com/spatie/laravel-signal-aware-command", + "keywords": [ + "laravel", + "laravel-signal-aware-command", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-signal-aware-command/issues", + "source": "https://github.com/spatie/laravel-signal-aware-command/tree/2.1.2" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2026-02-22T08:16:31+00:00" + }, + { + "name": "spatie/temporary-directory", + "version": "2.3.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/temporary-directory.git", + "reference": "662e481d6ec07ef29fd05010433428851a42cd07" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/662e481d6ec07ef29fd05010433428851a42cd07", + "reference": "662e481d6ec07ef29fd05010433428851a42cd07", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\TemporaryDirectory\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alex Vanderbist", + "email": "alex@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Easily create, use and destroy temporary directories", + "homepage": "https://github.com/spatie/temporary-directory", + "keywords": [ + "php", + "spatie", + "temporary-directory" + ], + "support": { + "issues": "https://github.com/spatie/temporary-directory/issues", + "source": "https://github.com/spatie/temporary-directory/tree/2.3.1" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2026-01-12T07:42:22+00:00" + }, + { + "name": "symfony/clock", + "version": "v7.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110", + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v7.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-11-12T15:39:26+00:00" + }, + { + "name": "symfony/console", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "6d643a93b47398599124022eb24d97c153c12f27" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/6d643a93b47398599124022eb24d97c153c12f27", + "reference": "6d643a93b47398599124022eb24d97c153c12f27", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.2|^8.0" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-25T17:02:47+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "2e7c52c647b406e2107dd867db424a4dbac91864" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/2e7c52c647b406e2107dd867db424a4dbac91864", + "reference": "2e7c52c647b406e2107dd867db424a4dbac91864", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-17T07:53:42+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v7.4.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "8da531f364ddfee53e36092a7eebbbd0b775f6b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/8da531f364ddfee53e36092a7eebbbd0b775f6b8", + "reference": "8da531f364ddfee53e36092a7eebbbd0b775f6b8", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/polyfill-php85": "^1.32", + "symfony/var-dumper": "^6.4|^7.0|^8.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/webpack-encore-bundle": "^1.0|^2.0" + }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v7.4.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-20T16:42:42+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.4.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "dc2c0eba1af673e736bb851d747d266108aea746" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dc2c0eba1af673e736bb851d747d266108aea746", + "reference": "dc2c0eba1af673e736bb851d747d266108aea746", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-05T11:45:34+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3ebc794fa5315e59fd122561623c2e2e4280538e", + "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-25T16:50:00+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "reference": "8655bf1076b7a3a346cb11413ffdabff50c7ffcf", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-29T09:40:50+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "fd97d5e926e988a363cef56fbbf88c5c528e9065" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/fd97d5e926e988a363cef56fbbf88c5c528e9065", + "reference": "fd97d5e926e988a363cef56fbbf88c5c528e9065", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "^1.1" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" + }, + "require-dev": { + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.4.12|^7.1.5|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-21T16:25:55+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "002ac0cf4cd972a7fd0912dcd513a95e8a81ce83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/002ac0cf4cd972a7fd0912dcd513a95e8a81ce83", + "reference": "002ac0cf4cd972a7fd0912dcd513a95e8a81ce83", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^7.3|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/browser-kit": "<6.4", + "symfony/cache": "<6.4", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/flex": "<2.10", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.4", + "symfony/validator": "<6.4", + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.12" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4.1|^7.0.1|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^7.1|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/serializer": "^7.1|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0", + "twig/twig": "^3.12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-26T08:30:57+00:00" + }, + { + "name": "symfony/mailer", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/b02726f39a20bc65e30364f5c750c4ddbf1f58e9", + "reference": "b02726f39a20bc65e30364f5c750c4ddbf1f58e9", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.2", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/mime": "^7.2|^8.0", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/twig-bridge": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-25T16:50:00+00:00" + }, + { + "name": "symfony/mime", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "9fc881d95feae4c6c48678cb6372bd8a7ba04f5f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/9fc881d95feae4c6c48678cb6372bd8a7ba04f5f", + "reference": "9fc881d95feae4c6c48678cb6372bd8a7ba04f5f", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<5.2|>=7", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^5.2|^6.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-05T15:57:06+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-27T09:58:17+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-10T14:38:51+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T08:10:11+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-08T02:45:35+00:00" + }, + { + "name": "symfony/polyfill-php84", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php84.git", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", + "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php84\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-24T13:30:11+00:00" + }, + { + "name": "symfony/polyfill-php85", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php85\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-23T16:12:55+00:00" + }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/process", + "version": "v7.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "608476f4604102976d687c483ac63a79ba18cc97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", + "reference": "608476f4604102976d687c483ac63a79ba18cc97", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.4.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-26T15:07:59+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "238d749c56b804b31a9bf3e26519d93b65a60938" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/238d749c56b804b31a9bf3e26519d93b65a60938", + "reference": "238d749c56b804b31a9bf3e26519d93b65a60938", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-25T16:50:00+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.6.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-15T11:30:57+00:00" + }, + { + "name": "symfony/string", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/9f209231affa85aa930a5e46e6eb03381424b30b", + "reference": "9f209231affa85aa930a5e46e6eb03381424b30b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.33", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-09T09:33:46+00:00" + }, + { + "name": "symfony/translation", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "1888cf064399868af3784b9e043240f1d89d25ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/1888cf064399868af3784b9e043240f1d89d25ce", + "reference": "1888cf064399868af3784b9e043240f1d89d25ce", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5.3|^3.3" + }, + "conflict": { + "nikic/php-parser": "<5.0", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" + }, + "require-dev": { + "nikic/php-parser": "^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-17T07:53:42+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.6.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "65a8bc82080447fae78373aa10f8d13b38338977" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", + "reference": "65a8bc82080447fae78373aa10f8d13b38338977", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-15T13:41:35+00:00" + }, + { + "name": "symfony/uid", + "version": "v7.4.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/uid.git", + "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/uid/zipball/7719ce8aba76be93dfe249192f1fbfa52c588e36", + "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-uuid": "^1.15" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", + "keywords": [ + "UID", + "ulid", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/uid/tree/v7.4.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-01-03T23:30:35+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/045321c440ac18347b136c63d2e9bf28a2dc0291", + "reference": "045321c440ac18347b136c63d2e9bf28a2dc0291", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "twig/twig": "^3.12" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-15T10:53:20+00:00" + }, + { + "name": "tijsverkoyen/css-to-inline-styles", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/f0292ccf0ec75843d65027214426b6b163b48b41", + "reference": "f0292ccf0ec75843d65027214426b6b163b48b41", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "php": "^7.4 || ^8.0", + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "TijsVerkoyen\\CssToInlineStyles\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Tijs Verkoyen", + "email": "css_to_inline_styles@verkoyen.eu", + "role": "Developer" + } + ], + "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", + "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", + "support": { + "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.4.0" + }, + "time": "2025-12-02T11:56:42+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.3", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "955e7815d677a3eaa7075231212f2110983adecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/955e7815d677a3eaa7075231212f2110983adecc", + "reference": "955e7815d677a3eaa7075231212f2110983adecc", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.4", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.5", + "symfony/polyfill-ctype": "^1.26", + "symfony/polyfill-mbstring": "^1.26", + "symfony/polyfill-php80": "^1.26" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2025-12-27T19:49:13+00:00" + }, + { + "name": "voku/portable-ascii", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/voku/portable-ascii.git", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + }, + "suggest": { + "ext-intl": "Use Intl for transliterator_transliterate() support" + }, + "type": "library", + "autoload": { + "psr-4": { + "voku\\": "src/voku/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lars Moelleken", + "homepage": "https://www.moelleken.org/" + } + ], + "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", + "homepage": "https://github.com/voku/portable-ascii", + "keywords": [ + "ascii", + "clean", + "php" + ], + "support": { + "issues": "https://github.com/voku/portable-ascii/issues", + "source": "https://github.com/voku/portable-ascii/tree/2.0.3" + }, + "funding": [ + { + "url": "https://www.paypal.me/moelleken", + "type": "custom" + }, + { + "url": "https://github.com/voku", + "type": "github" + }, + { + "url": "https://opencollective.com/portable-ascii", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/voku", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", + "type": "tidelift" + } + ], + "time": "2024-11-21T01:49:47+00:00" + } + ], + "packages-dev": [ + { + "name": "fakerphp/faker", + "version": "v1.24.1", + "source": { + "type": "git", + "url": "https://github.com/FakerPHP/Faker.git", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "conflict": { + "fzaninotto/faker": "*" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "doctrine/persistence": "^1.3 || ^2.0", + "ext-intl": "*", + "phpunit/phpunit": "^9.5.26", + "symfony/phpunit-bridge": "^5.4.16" + }, + "suggest": { + "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", + "ext-curl": "Required by Faker\\Provider\\Image to download images.", + "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", + "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", + "ext-mbstring": "Required for multibyte Unicode string functionality." + }, + "type": "library", + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "support": { + "issues": "https://github.com/FakerPHP/Faker/issues", + "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1" + }, + "time": "2024-11-21T13:46:39+00:00" + }, + { + "name": "filp/whoops", + "version": "2.18.4", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.18.4" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2025-08-08T12:00:00+00:00" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "^1.4 || ^2.0 || ^3.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "support": { + "issues": "https://github.com/hamcrest/hamcrest-php/issues", + "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.1.1" + }, + "time": "2025-04-30T06:54:44+00:00" + }, + { + "name": "laravel/pail", + "version": "v1.2.6", + "source": { + "type": "git", + "url": "https://github.com/laravel/pail.git", + "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pail/zipball/aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", + "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "illuminate/console": "^10.24|^11.0|^12.0|^13.0", + "illuminate/contracts": "^10.24|^11.0|^12.0|^13.0", + "illuminate/log": "^10.24|^11.0|^12.0|^13.0", + "illuminate/process": "^10.24|^11.0|^12.0|^13.0", + "illuminate/support": "^10.24|^11.0|^12.0|^13.0", + "nunomaduro/termwind": "^1.15|^2.0", + "php": "^8.2", + "symfony/console": "^6.0|^7.0|^8.0" + }, + "require-dev": { + "laravel/framework": "^10.24|^11.0|^12.0|^13.0", + "laravel/pint": "^1.13", + "orchestra/testbench-core": "^8.13|^9.17|^10.8|^11.0", + "pestphp/pest": "^2.20|^3.0|^4.0", + "pestphp/pest-plugin-type-coverage": "^2.3|^3.0|^4.0", + "phpstan/phpstan": "^1.12.27", + "symfony/var-dumper": "^6.3|^7.0|^8.0", + "symfony/yaml": "^6.3|^7.0|^8.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Pail\\PailServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Pail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Easily delve into your Laravel application's log files directly from the command line.", + "homepage": "https://github.com/laravel/pail", + "keywords": [ + "dev", + "laravel", + "logs", + "php", + "tail" + ], + "support": { + "issues": "https://github.com/laravel/pail/issues", + "source": "https://github.com/laravel/pail" + }, + "time": "2026-02-09T13:44:54+00:00" + }, + { + "name": "laravel/pint", + "version": "v1.27.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/54cca2de13790570c7b6f0f94f37896bee4abcb5", + "reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.93.1", + "illuminate/view": "^12.51.0", + "larastan/larastan": "^3.9.2", + "laravel-zero/framework": "^12.0.5", + "mockery/mockery": "^1.6.12", + "nunomaduro/termwind": "^2.3.3", + "pestphp/pest": "^3.8.5" + }, + "bin": [ + "builds/pint" + ], + "type": "project", + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", + "keywords": [ + "dev", + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2026-02-10T20:00:20+00:00" + }, + { + "name": "laravel/sail", + "version": "v1.53.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/sail.git", + "reference": "e340eaa2bea9b99192570c48ed837155dbf24fbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sail/zipball/e340eaa2bea9b99192570c48ed837155dbf24fbb", + "reference": "e340eaa2bea9b99192570c48ed837155dbf24fbb", + "shasum": "" + }, + "require": { + "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "php": "^8.0", + "symfony/console": "^6.0|^7.0|^8.0", + "symfony/yaml": "^6.0|^7.0|^8.0" + }, + "require-dev": { + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0|^11.0", + "phpstan/phpstan": "^2.0" + }, + "bin": [ + "bin/sail" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sail\\SailServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Docker files for running a basic Laravel application.", + "keywords": [ + "docker", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/sail/issues", + "source": "https://github.com/laravel/sail" + }, + "time": "2026-02-06T12:16:02+00:00" + }, + { + "name": "mockery/mockery", + "version": "1.6.12", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "^2.0.1", + "lib-pcre": ">=7.0", + "php": ">=7.3" + }, + "conflict": { + "phpunit/phpunit": "<8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5 || ^9.6.17", + "symplify/easy-coding-standard": "^12.1.14" + }, + "type": "library", + "autoload": { + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "https://github.com/padraic", + "role": "Author" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework", + "homepage": "https://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "docs": "https://docs.mockery.io/", + "issues": "https://github.com/mockery/mockery/issues", + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" + }, + "time": "2024-05-16T03:13:13+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nunomaduro/collision", + "version": "v8.9.1", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/a1ed3fa530fd60bc515f9303e8520fcb7d4bd935", + "reference": "a1ed3fa530fd60bc515f9303e8520fcb7d4bd935", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.18.4", + "nunomaduro/termwind": "^2.4.0", + "php": "^8.2.0", + "symfony/console": "^7.4.4 || ^8.0.4" + }, + "conflict": { + "laravel/framework": "<11.48.0 || >=14.0.0", + "phpunit/phpunit": "<11.5.50 || >=14.0.0" + }, + "require-dev": { + "brianium/paratest": "^7.8.5", + "larastan/larastan": "^3.9.2", + "laravel/framework": "^11.48.0 || ^12.52.0", + "laravel/pint": "^1.27.1", + "orchestra/testbench-core": "^9.12.0 || ^10.9.0", + "pestphp/pest": "^3.8.5 || ^4.4.1 || ^5.0.0", + "sebastian/environment": "^7.2.1 || ^8.0.3 || ^9.0.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + }, + "branch-alias": { + "dev-8.x": "8.x-dev" + } + }, + "autoload": { + "files": [ + "./src/Adapters/Phpunit/Autoload.php" + ], + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "dev", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "support": { + "issues": "https://github.com/nunomaduro/collision/issues", + "source": "https://github.com/nunomaduro/collision" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2026-02-17T17:33:08+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.12", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2c1ed04922802c15e1de5d7447b4856de949cf56", + "reference": "2c1ed04922802c15e1de5d7447b4856de949cf56", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.7.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.1", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.3.1" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.46" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.12" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-12-24T07:01:01+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" + } + ], + "time": "2026-02-02T13:52:54+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.5.55", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.12", + "phpunit/php-file-iterator": "^5.1.1", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.3", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.1", + "sebastian/exporter": "^6.3.2", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/recursion-context": "^6.0.3", + "sebastian/type": "^5.1.3", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.55" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2026-02-18T12:37:06+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-19T07:56:08+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2026-01-24T09:26:40+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" + } + ], + "time": "2025-05-21T11:55:47+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74", + "reference": "70a298763b40b213ec087c51c739efcaa90bcd74", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" + } + ], + "time": "2025-09-24T06:12:51+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:57:36+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:58:38+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:00:13+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:01:32+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" + } + ], + "time": "2025-08-13T04:42:22+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" + } + ], + "time": "2025-08-09T06:55:48+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-09T05:16:32+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/yaml", + "version": "v7.4.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "58751048de17bae71c5aa0d13cb19d79bca26391" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/58751048de17bae71c5aa0d13cb19d79bca26391", + "reference": "58751048de17bae71c5aa0d13cb19d79bca26391", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.4.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-09T09:33:46+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c", + "reference": "b7489ce515e168639d17feec34b8847c326b0b3c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.3.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2025-11-17T20:03:58+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": "^8.2" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..ed897f7 --- /dev/null +++ b/config/app.php @@ -0,0 +1,234 @@ + env('FORCE_SSL', false), + + /* + |-------------------------------------------------------------------------- + | Application Name + |-------------------------------------------------------------------------- + | + | This value is the name of your application, which will be used when the + | framework needs to place the application's name in a notification or + | other UI elements where an application name needs to be displayed. + | + */ + + 'name' => env('APP_NAME', 'Laravel'), + + /* + |-------------------------------------------------------------------------- + | Application Environment + |-------------------------------------------------------------------------- + | + | This value determines the "environment" your application is currently + | running in. This may determine how you prefer to configure various + | services the application utilizes. Set this in your ".env" file. + | + */ + + 'env' => env('APP_ENV', 'production'), + + /* + |-------------------------------------------------------------------------- + | Application Debug Mode + |-------------------------------------------------------------------------- + | + | When your application is in debug mode, detailed error messages with + | stack traces will be shown on every error that occurs within your + | application. If disabled, a simple generic error page is shown. + | + */ + + 'debug' => (bool) env('APP_DEBUG', false), + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | the application so that it's available within Artisan commands. + | + */ + + 'url' => env('APP_URL', 'http://localhost'), + + 'api_url' => env('API_URL', 'http://localhost/api'), + + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. The timezone + | is set to "UTC" by default as it is suitable for most use cases. + | + */ + + 'timezone' => env('APP_TIMEZONE', 'UTC'), + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by Laravel's translation / localization methods. This option can be + | set to any locale for which you plan to have translation strings. + | + */ + + 'locale' => env('APP_LOCALE', 'pt'), + + 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'pt'), + + 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is utilized by Laravel's encryption services and should be set + | to a random, 32 character string to ensure that all encrypted values + | are secure. You should do this prior to deploying the application. + | + */ + + 'cipher' => 'AES-256-CBC', + + 'key' => env('APP_KEY'), + + 'previous_keys' => [ + ...array_filter( + explode(',', env('APP_PREVIOUS_KEYS', '')) + ), + ], + + /* + |-------------------------------------------------------------------------- + | Maintenance Mode Driver + |-------------------------------------------------------------------------- + | + | These configuration options determine the driver used to determine and + | manage Laravel's "maintenance mode" status. The "cache" driver will + | allow maintenance mode to be controlled across multiple machines. + | + | Supported drivers: "file", "cache" + | + */ + + 'maintenance' => [ + 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), + 'store' => env('APP_MAINTENANCE_STORE', 'database'), + ], + /* + |-------------------------------------------------------------------------- + | Autoloaded Service Providers + |-------------------------------------------------------------------------- + | + | The service providers listed here will be automatically loaded on the + | request to your application. Feel free to add your own services to + | this array to grant expanded functionality to your applications. + | + */ + + 'providers' => [ + + /* + * Laravel Framework Service Providers... + */ + Illuminate\Auth\AuthServiceProvider::class, + Illuminate\Broadcasting\BroadcastServiceProvider::class, + Illuminate\Bus\BusServiceProvider::class, + Illuminate\Cache\CacheServiceProvider::class, + Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, + Illuminate\Cookie\CookieServiceProvider::class, + Illuminate\Database\DatabaseServiceProvider::class, + Illuminate\Encryption\EncryptionServiceProvider::class, + Illuminate\Filesystem\FilesystemServiceProvider::class, // 👈 Importante + Illuminate\Foundation\Providers\FoundationServiceProvider::class, + Illuminate\Hashing\HashServiceProvider::class, + Illuminate\Mail\MailServiceProvider::class, + Illuminate\Notifications\NotificationServiceProvider::class, + Illuminate\Pagination\PaginationServiceProvider::class, + Illuminate\Pipeline\PipelineServiceProvider::class, + Illuminate\Queue\QueueServiceProvider::class, + Illuminate\Redis\RedisServiceProvider::class, + Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, + Illuminate\Session\SessionServiceProvider::class, + Illuminate\Translation\TranslationServiceProvider::class, + Illuminate\Validation\ValidationServiceProvider::class, + Illuminate\View\ViewServiceProvider::class, + + /* + * Package Service Providers... + */ + + /* + * Application Service Providers... + */ + App\Providers\AppServiceProvider::class, + // App\Providers\AuthServiceProvider::class, + // App\Providers\BroadcastServiceProvider::class, + // App\Providers\EventServiceProvider::class, + App\Providers\RouteServiceProvider::class, + ], + + /* + |-------------------------------------------------------------------------- + | Class Aliases + |-------------------------------------------------------------------------- + | + | This array of class aliases will be registered when this application + | is started. However, feel free to register as many as you wish as + | the aliases are "lazy" loaded so they don't hinder performance. + | + */ + + 'aliases' => [ + 'App' => Illuminate\Support\Facades\App::class, + 'Arr' => Illuminate\Support\Arr::class, + 'Artisan' => Illuminate\Support\Facades\Artisan::class, + 'Auth' => Illuminate\Support\Facades\Auth::class, + 'Blade' => Illuminate\Support\Facades\Blade::class, + 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, + 'Bus' => Illuminate\Support\Facades\Bus::class, + 'Cache' => Illuminate\Support\Facades\Cache::class, + 'Config' => Illuminate\Support\Facades\Config::class, + 'Cookie' => Illuminate\Support\Facades\Cookie::class, + 'Crypt' => Illuminate\Support\Facades\Crypt::class, + 'DB' => Illuminate\Support\Facades\DB::class, + 'Eloquent' => Illuminate\Database\Eloquent\Model::class, + 'Event' => Illuminate\Support\Facades\Event::class, + 'File' => Illuminate\Support\Facades\File::class, + 'Gate' => Illuminate\Support\Facades\Gate::class, + 'Hash' => Illuminate\Support\Facades\Hash::class, + 'Http' => Illuminate\Support\Facades\Http::class, + 'Lang' => Illuminate\Support\Facades\Lang::class, + 'Log' => Illuminate\Support\Facades\Log::class, + 'Mail' => Illuminate\Support\Facades\Mail::class, + 'Notification' => Illuminate\Support\Facades\Notification::class, + 'Password' => Illuminate\Support\Facades\Password::class, + 'Queue' => Illuminate\Support\Facades\Queue::class, + 'Redirect' => Illuminate\Support\Facades\Redirect::class, + 'Request' => Illuminate\Support\Facades\Request::class, + 'Response' => Illuminate\Support\Facades\Response::class, + 'Route' => Illuminate\Support\Facades\Route::class, + 'Schema' => Illuminate\Support\Facades\Schema::class, + 'Session' => Illuminate\Support\Facades\Session::class, + 'Storage' => Illuminate\Support\Facades\Storage::class, + 'Str' => Illuminate\Support\Str::class, + 'URL' => Illuminate\Support\Facades\URL::class, + 'Validator' => Illuminate\Support\Facades\Validator::class, + 'View' => Illuminate\Support\Facades\View::class, + ], + + +]; diff --git a/config/auth.php b/config/auth.php new file mode 100644 index 0000000..0ba5d5d --- /dev/null +++ b/config/auth.php @@ -0,0 +1,115 @@ + [ + 'guard' => env('AUTH_GUARD', 'web'), + 'passwords' => env('AUTH_PASSWORD_BROKER', 'users'), + ], + + /* + |-------------------------------------------------------------------------- + | Authentication Guards + |-------------------------------------------------------------------------- + | + | Next, you may define every authentication guard for your application. + | Of course, a great default configuration has been defined for you + | which utilizes session storage plus the Eloquent user provider. + | + | All authentication guards have a user provider, which defines how the + | users are actually retrieved out of your database or other storage + | system used by the application. Typically, Eloquent is utilized. + | + | Supported: "session" + | + */ + + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + ], + + /* + |-------------------------------------------------------------------------- + | User Providers + |-------------------------------------------------------------------------- + | + | All authentication guards have a user provider, which defines how the + | users are actually retrieved out of your database or other storage + | system used by the application. Typically, Eloquent is utilized. + | + | If you have multiple user tables or models you may configure multiple + | providers to represent the model / table. These providers may then + | be assigned to any extra authentication guards you have defined. + | + | Supported: "database", "eloquent" + | + */ + + 'providers' => [ + 'users' => [ + 'driver' => 'eloquent', + 'model' => env('AUTH_MODEL', App\Models\User::class), + ], + + // 'users' => [ + // 'driver' => 'database', + // 'table' => 'users', + // ], + ], + + /* + |-------------------------------------------------------------------------- + | Resetting Passwords + |-------------------------------------------------------------------------- + | + | These configuration options specify the behavior of Laravel's password + | reset functionality, including the table utilized for token storage + | and the user provider that is invoked to actually retrieve users. + | + | The expiry time is the number of minutes that each reset token will be + | considered valid. This security feature keeps tokens short-lived so + | they have less time to be guessed. You may change this as needed. + | + | The throttle setting is the number of seconds a user must wait before + | generating more password reset tokens. This prevents the user from + | quickly generating a very large amount of password reset tokens. + | + */ + + 'passwords' => [ + 'users' => [ + 'provider' => 'users', + 'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'), + 'expire' => 60, + 'throttle' => 60, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Password Confirmation Timeout + |-------------------------------------------------------------------------- + | + | Here you may define the amount of seconds before a password confirmation + | window expires and users are asked to re-enter their password via the + | confirmation screen. By default, the timeout lasts for three hours. + | + */ + + 'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800), + +]; diff --git a/config/backup.php b/config/backup.php new file mode 100644 index 0000000..3aaefc1 --- /dev/null +++ b/config/backup.php @@ -0,0 +1,341 @@ + [ + /* + * The name of this application. You can use this name to monitor + * the backups. + */ + 'name' => 'laravel-backup', + + 'source' => [ + 'files' => [ + /* + * The list of directories and files that will be included in the backup. + */ + 'include' => [ + // base_path(), + ], + + /* + * These directories and files will be excluded from the backup. + * + * Directories used by the backup process will automatically be excluded. + */ + 'exclude' => [ + // base_path('vendor'), + // base_path('node_modules'), + ], + + /* + * Determines if symlinks should be followed. + */ + 'follow_links' => false, + + /* + * Determines if it should avoid unreadable folders. + */ + 'ignore_unreadable_directories' => false, + + /* + * This path is used to make directories in resulting zip-file relative + * Set to `null` to include complete absolute path + * Example: base_path() + */ + 'relative_path' => null, + ], + + /* + * The names of the connections to the databases that should be backed up + * MySQL, PostgreSQL, SQLite and Mongo databases are supported. + * + * The content of the database dump may be customized for each connection + * by adding a 'dump' key to the connection settings in config/database.php. + * E.g. + * 'mysql' => [ + * ... + * 'dump' => [ + * 'excludeTables' => [ + * 'table_to_exclude_from_backup', + * 'another_table_to_exclude' + * ] + * ], + * ], + * + * If you are using only InnoDB tables on a MySQL server, you can + * also supply the useSingleTransaction option to avoid table locking. + * + * E.g. + * 'mysql' => [ + * ... + * 'dump' => [ + * 'useSingleTransaction' => true, + * ], + * ], + * + * For a complete list of available customization options, see https://github.com/spatie/db-dumper + */ + 'databases' => [ + env('DB_CONNECTION', 'mysql'), + ], + ], + + /* + * The database dump can be compressed to decrease disk space usage. + * + * Out of the box Laravel-backup supplies + * Spatie\DbDumper\Compressors\GzipCompressor::class. + * + * You can also create custom compressor. More info on that here: + * https://github.com/spatie/db-dumper#using-compression + * + * If you do not want any compressor at all, set it to null. + */ + 'database_dump_compressor' => Spatie\DbDumper\Compressors\GzipCompressor::class, + + /* + * If specified, the database dumped file name will contain a timestamp (e.g.: 'Y-m-d-H-i-s'). + */ + 'database_dump_file_timestamp_format' => null, + + /* + * The base of the dump filename, either 'database' or 'connection' + * + * If 'database' (default), the dumped filename will contain the database name. + * If 'connection', the dumped filename will contain the connection name. + */ + 'database_dump_filename_base' => 'database', + + /* + * The file extension used for the database dump files. + * + * If not specified, the file extension will be .archive for MongoDB and .sql for all other databases + * The file extension should be specified without a leading . + */ + 'database_dump_file_extension' => '', + + 'destination' => [ + /* + * The compression algorithm to be used for creating the zip archive. + * + * If backing up only database, you may choose gzip compression for db dump and no compression at zip. + * + * Some common algorithms are listed below: + * ZipArchive::CM_STORE (no compression at all; set 0 as compression level) + * ZipArchive::CM_DEFAULT + * ZipArchive::CM_DEFLATE + * ZipArchive::CM_BZIP2 + * ZipArchive::CM_XZ + * + * For more check https://www.php.net/manual/zip.constants.php and confirm it's supported by your system. + */ + 'compression_method' => ZipArchive::CM_DEFAULT, + + /* + * The compression level corresponding to the used algorithm; an integer between 0 and 9. + * + * Check supported levels for the chosen algorithm, usually 1 means the fastest and weakest compression, + * while 9 the slowest and strongest one. + * + * Setting of 0 for some algorithms may switch to the strongest compression. + */ + 'compression_level' => 9, + + /* + * The filename prefix used for the backup zip file. + */ + 'filename_prefix' => '', + + /* + * The disk names on which the backups will be stored. + */ + 'disks' => [ + env('FILESYSTEM_DISK', 'local'), + ], + ], + + /* + * The directory where the temporary files will be stored. + */ + 'temporary_directory' => storage_path('app/backup-temp'), + + /* + * The password to be used for archive encryption. + * Set to `null` to disable encryption. + */ + 'password' => env('BACKUP_ARCHIVE_PASSWORD'), + + /* + * The encryption algorithm to be used for archive encryption. + * You can set it to `null` or `false` to disable encryption. + * + * When set to 'default', we'll use ZipArchive::EM_AES_256 if it is + * available on your system. + */ + 'encryption' => 'default', + + /* + * The number of attempts, in case the backup command encounters an exception + */ + 'tries' => 1, + + /* + * The number of seconds to wait before attempting a new backup if the previous try failed + * Set to `0` for none + */ + 'retry_delay' => 0, + ], + + /* + * You can get notified when specific events occur. Out of the box you can use 'mail' and 'slack'. + * For Slack you need to install laravel/slack-notification-channel. + * + * You can also use your own notification classes, just make sure the class is named after one of + * the `Spatie\Backup\Notifications\Notifications` classes. + */ + 'notifications' => [ + 'notifications' => [ + \Spatie\Backup\Notifications\Notifications\BackupHasFailedNotification::class => ['mail'], + \Spatie\Backup\Notifications\Notifications\UnhealthyBackupWasFoundNotification::class => ['mail'], + \Spatie\Backup\Notifications\Notifications\CleanupHasFailedNotification::class => ['mail'], + \Spatie\Backup\Notifications\Notifications\BackupWasSuccessfulNotification::class => ['mail'], + \Spatie\Backup\Notifications\Notifications\HealthyBackupWasFoundNotification::class => ['mail'], + \Spatie\Backup\Notifications\Notifications\CleanupWasSuccessfulNotification::class => ['mail'], + ], + + /* + * Here you can specify the notifiable to which the notifications should be sent. The default + * notifiable will use the variables specified in this config file. + */ + 'notifiable' => \Spatie\Backup\Notifications\Notifiable::class, + + 'mail' => [ + 'to' => ['luismedon@gmail.com'], + + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', 'Example'), + ], + ], + + 'slack' => [ + 'webhook_url' => '', + + /* + * If this is set to null the default channel of the webhook will be used. + */ + 'channel' => null, + + 'username' => null, + + 'icon' => null, + ], + + 'discord' => [ + 'webhook_url' => '', + + /* + * If this is an empty string, the name field on the webhook will be used. + */ + 'username' => '', + + /* + * If this is an empty string, the avatar on the webhook will be used. + */ + 'avatar_url' => '', + ], + ], + + /* + * Here you can specify which backups should be monitored. + * If a backup does not meet the specified requirements the + * UnHealthyBackupWasFound event will be fired. + */ + 'monitor_backups' => [ + [ + 'name' => 'laravel-backup', + 'disks' => [env('FILESYSTEM_DISK', 'local')], + 'health_checks' => [ + \Spatie\Backup\Tasks\Monitor\HealthChecks\MaximumAgeInDays::class => 1, + \Spatie\Backup\Tasks\Monitor\HealthChecks\MaximumStorageInMegabytes::class => 5000, + ], + ], + + /* + [ + 'name' => 'name of the second app', + 'disks' => ['local', 's3'], + 'health_checks' => [ + \Spatie\Backup\Tasks\Monitor\HealthChecks\MaximumAgeInDays::class => 1, + \Spatie\Backup\Tasks\Monitor\HealthChecks\MaximumStorageInMegabytes::class => 5000, + ], + ], + */ + ], + + 'cleanup' => [ + /* + * The strategy that will be used to cleanup old backups. The default strategy + * will keep all backups for a certain amount of days. After that period only + * a daily backup will be kept. After that period only weekly backups will + * be kept and so on. + * + * No matter how you configure it the default strategy will never + * delete the newest backup. + */ + 'strategy' => \Spatie\Backup\Tasks\Cleanup\Strategies\DefaultStrategy::class, + + 'default_strategy' => [ + /* + * The number of days for which backups must be kept. + */ + 'keep_all_backups_for_days' => 0, + + /* + * After the "keep_all_backups_for_days" period is over, the most recent backup + * of that day will be kept. Older backups within the same day will be removed. + * If you create backups only once a day, no backups will be removed yet. + */ + 'keep_daily_backups_for_days' => 5, + + /* + * After the "keep_daily_backups_for_days" period is over, the most recent backup + * of that week will be kept. Older backups within the same week will be removed. + * If you create backups only once a week, no backups will be removed yet. + */ + 'keep_weekly_backups_for_weeks' => 0, + + /* + * After the "keep_weekly_backups_for_weeks" period is over, the most recent backup + * of that month will be kept. Older backups within the same month will be removed. + */ + 'keep_monthly_backups_for_months' => 0, + + /* + * After the "keep_monthly_backups_for_months" period is over, the most recent backup + * of that year will be kept. Older backups within the same year will be removed. + */ + 'keep_yearly_backups_for_years' => 0, + + /* + * After cleaning up the backups remove the oldest backup until + * this amount of megabytes has been reached. + * Set null for unlimited size. + */ + 'delete_oldest_backups_when_using_more_megabytes_than' => null, + ], + + /* + * The number of attempts, in case the cleanup command encounters an exception + */ + 'tries' => 1, + + /* + * The number of seconds to wait before attempting a new cleanup if the previous try failed + * Set to `0` for none + */ + 'retry_delay' => 0, + ], + +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..e040637 --- /dev/null +++ b/config/cache.php @@ -0,0 +1,108 @@ + env('CACHE_DRIVER', 'database'), + + /* + |-------------------------------------------------------------------------- + | Cache Stores + |-------------------------------------------------------------------------- + | + | Here you may define all of the cache "stores" for your application as + | well as their drivers. You may even define multiple stores for the + | same cache driver to group types of items stored in your caches. + | + | Supported drivers: "array", "database", "file", "memcached", + | "redis", "dynamodb", "octane", "null" + | + */ + + 'stores' => [ + + 'array' => [ + 'driver' => 'array', + 'serialize' => false, + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_CACHE_CONNECTION'), + 'table' => env('DB_CACHE_TABLE', 'cache'), + 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), + 'lock_table' => env('DB_CACHE_LOCK_TABLE'), + ], + + 'file' => [ + 'driver' => 'file', + 'path' => storage_path('framework/cache/data'), + 'lock_path' => storage_path('framework/cache/data'), + ], + + 'memcached' => [ + 'driver' => 'memcached', + 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), + 'sasl' => [ + env('MEMCACHED_USERNAME'), + env('MEMCACHED_PASSWORD'), + ], + 'options' => [ + // Memcached::OPT_CONNECT_TIMEOUT => 2000, + ], + 'servers' => [ + [ + 'host' => env('MEMCACHED_HOST', '127.0.0.1'), + 'port' => env('MEMCACHED_PORT', 11211), + 'weight' => 100, + ], + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_CACHE_CONNECTION', 'cache'), + 'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'), + ], + + 'dynamodb' => [ + 'driver' => 'dynamodb', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), + 'endpoint' => env('DYNAMODB_ENDPOINT'), + ], + + 'octane' => [ + 'driver' => 'octane', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing the APC, database, memcached, Redis, and DynamoDB cache + | stores, there might be other applications using the same cache. For + | that reason, you may prefix every cache key to avoid collisions. + | + */ + + 'prefix' => env('CACHE_PREFIX'), + +]; diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..8910562 --- /dev/null +++ b/config/database.php @@ -0,0 +1,174 @@ + env('DB_CONNECTION', 'sqlite'), + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Below are all of the database connections defined for your application. + | An example configuration is provided for each database system which + | is supported by Laravel. You're free to add / remove connections. + | + */ + + 'connections' => [ + + 'sqlite' => [ + 'driver' => 'sqlite', + 'url' => env('DB_URL'), + 'database' => env('DB_DATABASE', database_path('database.sqlite')), + 'prefix' => '', + 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), + 'busy_timeout' => null, + 'journal_mode' => null, + 'synchronous' => null, + ], + + 'mysql' => [ + 'driver' => 'mysql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'mariadb' => [ + 'driver' => 'mariadb', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'pgsql' => [ + 'driver' => 'pgsql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '5432'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + 'search_path' => 'public', + 'sslmode' => 'prefer', + ], + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', 'localhost'), + 'port' => env('DB_PORT', '1433'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + // 'encrypt' => env('DB_ENCRYPT', 'yes'), + // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run on the database. + | + */ + + 'migrations' => [ + 'table' => 'migrations', + 'update_date_on_publish' => true, + ], + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer body of commands than a typical key-value system + | such as Memcached. You may define your connection settings here. + | + */ + + 'redis' => [ + + 'client' => env('REDIS_CLIENT', 'phpredis'), + + 'options' => [ + 'cluster' => env('REDIS_CLUSTER', 'redis'), + 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), + 'persistent' => env('REDIS_PERSISTENT', false), + ], + + 'default' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_DB', '0'), + ], + + 'cache' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_CACHE_DB', '1'), + ], + + ], + +]; diff --git a/config/filesystems.php b/config/filesystems.php new file mode 100644 index 0000000..aa6efbc --- /dev/null +++ b/config/filesystems.php @@ -0,0 +1,79 @@ + env('FILESYSTEM_DISK', 'local'), + + /* + |-------------------------------------------------------------------------- + | Filesystem Disks + |-------------------------------------------------------------------------- + | + | Below you may configure as many filesystem disks as necessary, and you + | may even configure multiple disks for the same driver. Examples for + | most supported storage drivers are configured here for reference. + | + | Supported drivers: "local", "ftp", "sftp", "s3" + | + */ + + 'disks' => [ + + 'local' => [ + 'driver' => 'local', + 'root' => storage_path('app/private'), + 'serve' => true, + 'throw' => false, + 'report' => false, + ], + + 'public' => [ + 'driver' => 'local', + 'root' => storage_path('app/public'), + 'url' => env('APP_URL').'/storage', + 'visibility' => 'public', + 'throw' => false, + 'report' => false, + ], + + 's3' => [ + 'driver' => 's3', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION'), + 'bucket' => env('AWS_BUCKET'), + 'url' => env('AWS_URL'), + 'endpoint' => env('AWS_ENDPOINT'), + 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', true), + ], + + + ], + + /* + |-------------------------------------------------------------------------- + | Symbolic Links + |-------------------------------------------------------------------------- + | + | Here you may configure the symbolic links that will be created when the + | `storage:link` Artisan command is executed. The array keys should be + | the locations of the links and the values should be their targets. + | + */ + + 'links' => [ + public_path('storage') => storage_path('app/public'), + ], + +]; diff --git a/config/logging.php b/config/logging.php new file mode 100644 index 0000000..8d94292 --- /dev/null +++ b/config/logging.php @@ -0,0 +1,132 @@ + env('LOG_CHANNEL', 'stack'), + + /* + |-------------------------------------------------------------------------- + | Deprecations Log Channel + |-------------------------------------------------------------------------- + | + | This option controls the log channel that should be used to log warnings + | regarding deprecated PHP and library features. This allows you to get + | your application ready for upcoming major versions of dependencies. + | + */ + + 'deprecations' => [ + 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), + 'trace' => env('LOG_DEPRECATIONS_TRACE', false), + ], + + /* + |-------------------------------------------------------------------------- + | Log Channels + |-------------------------------------------------------------------------- + | + | Here you may configure the log channels for your application. Laravel + | utilizes the Monolog PHP logging library, which includes a variety + | of powerful log handlers and formatters that you're free to use. + | + | Available drivers: "single", "daily", "slack", "syslog", + | "errorlog", "monolog", "custom", "stack" + | + */ + + 'channels' => [ + + 'stack' => [ + 'driver' => 'stack', + 'channels' => explode(',', env('LOG_STACK', 'single')), + 'ignore_exceptions' => false, + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'days' => env('LOG_DAILY_DAYS', 14), + 'replace_placeholders' => true, + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'), + 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'), + 'level' => env('LOG_LEVEL', 'critical'), + 'replace_placeholders' => true, + ], + + 'papertrail' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), + 'handler_with' => [ + 'host' => env('PAPERTRAIL_URL'), + 'port' => env('PAPERTRAIL_PORT'), + 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), + ], + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => StreamHandler::class, + 'formatter' => env('LOG_STDERR_FORMATTER'), + 'with' => [ + 'stream' => 'php://stderr', + ], + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => env('LOG_LEVEL', 'debug'), + 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), + 'replace_placeholders' => true, + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'null' => [ + 'driver' => 'monolog', + 'handler' => NullHandler::class, + ], + + 'emergency' => [ + 'path' => storage_path('logs/laravel.log'), + ], + + ], + +]; diff --git a/config/mail.php b/config/mail.php new file mode 100644 index 0000000..756305b --- /dev/null +++ b/config/mail.php @@ -0,0 +1,116 @@ + env('MAIL_MAILER', 'log'), + + /* + |-------------------------------------------------------------------------- + | Mailer Configurations + |-------------------------------------------------------------------------- + | + | Here you may configure all of the mailers used by your application plus + | their respective settings. Several examples have been configured for + | you and you are free to add your own as your application requires. + | + | Laravel supports a variety of mail "transport" drivers that can be used + | when delivering an email. You may specify which one you're using for + | your mailers below. You may also add additional mailers if needed. + | + | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", + | "postmark", "resend", "log", "array", + | "failover", "roundrobin" + | + */ + + 'mailers' => [ + + 'smtp' => [ + 'transport' => 'smtp', + 'scheme' => env('MAIL_SCHEME'), + 'url' => env('MAIL_URL'), + 'host' => env('MAIL_HOST', '127.0.0.1'), + 'port' => env('MAIL_PORT', 2525), + 'username' => env('MAIL_USERNAME'), + 'password' => env('MAIL_PASSWORD'), + 'timeout' => null, + 'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)), + ], + + 'ses' => [ + 'transport' => 'ses', + ], + + 'postmark' => [ + 'transport' => 'postmark', + // 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'), + // 'client' => [ + // 'timeout' => 5, + // ], + ], + + 'resend' => [ + 'transport' => 'resend', + ], + + 'sendmail' => [ + 'transport' => 'sendmail', + 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), + ], + + 'log' => [ + 'transport' => 'log', + 'channel' => env('MAIL_LOG_CHANNEL'), + ], + + 'array' => [ + 'transport' => 'array', + ], + + 'failover' => [ + 'transport' => 'failover', + 'mailers' => [ + 'smtp', + 'log', + ], + ], + + 'roundrobin' => [ + 'transport' => 'roundrobin', + 'mailers' => [ + 'ses', + 'postmark', + ], + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all emails sent by your application to be sent from + | the same address. Here you may specify a name and address that is + | used globally for all emails that are sent by your application. + | + */ + + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', 'Example'), + ], + +]; diff --git a/config/permission.php b/config/permission.php new file mode 100644 index 0000000..8e84e9d --- /dev/null +++ b/config/permission.php @@ -0,0 +1,202 @@ + [ + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * Eloquent model should be used to retrieve your permissions. Of course, it + * is often just the "Permission" model but you may use whatever you like. + * + * The model you want to use as a Permission model needs to implement the + * `Spatie\Permission\Contracts\Permission` contract. + */ + + 'permission' => Spatie\Permission\Models\Permission::class, + + /* + * When using the "HasRoles" trait from this package, we need to know which + * Eloquent model should be used to retrieve your roles. Of course, it + * is often just the "Role" model but you may use whatever you like. + * + * The model you want to use as a Role model needs to implement the + * `Spatie\Permission\Contracts\Role` contract. + */ + + 'role' => Spatie\Permission\Models\Role::class, + + ], + + 'table_names' => [ + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'roles' => 'roles', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your permissions. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'permissions' => 'permissions', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your models permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_permissions' => 'model_has_permissions', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your models roles. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_roles' => 'model_has_roles', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'role_has_permissions' => 'role_has_permissions', + ], + + 'column_names' => [ + /* + * Change this if you want to name the related pivots other than defaults + */ + 'role_pivot_key' => null, // default 'role_id', + 'permission_pivot_key' => null, // default 'permission_id', + + /* + * Change this if you want to name the related model primary key other than + * `model_id`. + * + * For example, this would be nice if your primary keys are all UUIDs. In + * that case, name this `model_uuid`. + */ + + 'model_morph_key' => 'model_id', + + /* + * Change this if you want to use the teams feature and your related model's + * foreign key is other than `team_id`. + */ + + 'team_foreign_key' => 'team_id', + ], + + /* + * When set to true, the method for checking permissions will be registered on the gate. + * Set this to false if you want to implement custom logic for checking permissions. + */ + + 'register_permission_check_method' => true, + + /* + * When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered + * this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated + * NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it. + */ + 'register_octane_reset_listener' => false, + + /* + * Events will fire when a role or permission is assigned/unassigned: + * \Spatie\Permission\Events\RoleAttached + * \Spatie\Permission\Events\RoleDetached + * \Spatie\Permission\Events\PermissionAttached + * \Spatie\Permission\Events\PermissionDetached + * + * To enable, set to true, and then create listeners to watch these events. + */ + 'events_enabled' => false, + + /* + * Teams Feature. + * When set to true the package implements teams using the 'team_foreign_key'. + * If you want the migrations to register the 'team_foreign_key', you must + * set this to true before doing the migration. + * If you already did the migration then you must make a new migration to also + * add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions' + * (view the latest version of this package's migration file) + */ + + 'teams' => false, + + /* + * The class to use to resolve the permissions team id + */ + 'team_resolver' => \Spatie\Permission\DefaultTeamResolver::class, + + /* + * Passport Client Credentials Grant + * When set to true the package will use Passports Client to check permissions + */ + + 'use_passport_client_credentials' => false, + + /* + * When set to true, the required permission names are added to exception messages. + * This could be considered an information leak in some contexts, so the default + * setting is false here for optimum safety. + */ + + 'display_permission_in_exception' => false, + + /* + * When set to true, the required role names are added to exception messages. + * This could be considered an information leak in some contexts, so the default + * setting is false here for optimum safety. + */ + + 'display_role_in_exception' => false, + + /* + * By default wildcard permission lookups are disabled. + * See documentation to understand supported syntax. + */ + + 'enable_wildcard_permission' => false, + + /* + * The class to use for interpreting wildcard permissions. + * If you need to modify delimiters, override the class and specify its name here. + */ + // 'permission.wildcard_permission' => Spatie\Permission\WildcardPermission::class, + + /* Cache-specific settings */ + + 'cache' => [ + + /* + * By default all permissions are cached for 24 hours to speed up performance. + * When permissions or roles are updated the cache is flushed automatically. + */ + + 'expiration_time' => \DateInterval::createFromDateString('24 hours'), + + /* + * The cache key used to store all permissions. + */ + + 'key' => 'spatie.permission.cache', + + /* + * You may optionally indicate a specific cache driver to use for permission and + * role caching using any of the `store` drivers listed in the cache.php config + * file. Using 'default' here means to use the `default` set in cache.php. + */ + + 'store' => 'default', + ], +]; diff --git a/config/queue.php b/config/queue.php new file mode 100644 index 0000000..116bd8d --- /dev/null +++ b/config/queue.php @@ -0,0 +1,112 @@ + env('QUEUE_CONNECTION', 'database'), + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection options for every queue backend + | used by your application. An example configuration is provided for + | each backend supported by Laravel. You're also free to add more. + | + | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" + | + */ + + 'connections' => [ + + 'sync' => [ + 'driver' => 'sync', + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_QUEUE_CONNECTION'), + 'table' => env('DB_QUEUE_TABLE', 'jobs'), + 'queue' => env('DB_QUEUE', 'default'), + 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), + 'after_commit' => false, + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'), + 'queue' => env('BEANSTALKD_QUEUE', 'default'), + 'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90), + 'block_for' => 0, + 'after_commit' => false, + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), + 'queue' => env('SQS_QUEUE', 'default'), + 'suffix' => env('SQS_SUFFIX'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'after_commit' => false, + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), + 'queue' => env('REDIS_QUEUE', 'default'), + 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), + 'block_for' => null, + 'after_commit' => false, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Job Batching + |-------------------------------------------------------------------------- + | + | The following options configure the database and table that store job + | batching information. These options can be updated to any database + | connection and table which has been defined by your application. + | + */ + + 'batching' => [ + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'job_batches', + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control how and where failed jobs are stored. Laravel ships with + | support for storing failed jobs in a simple file or in a database. + | + | Supported drivers: "database-uuids", "dynamodb", "file", "null" + | + */ + + 'failed' => [ + 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'failed_jobs', + ], + +]; diff --git a/config/sanctum.php b/config/sanctum.php new file mode 100644 index 0000000..9209788 --- /dev/null +++ b/config/sanctum.php @@ -0,0 +1,84 @@ + explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( + '%s%s', + 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', + Sanctum::currentApplicationUrlWithPort(), + // Sanctum::currentRequestHost(), + ))), + + /* + |-------------------------------------------------------------------------- + | Sanctum Guards + |-------------------------------------------------------------------------- + | + | This array contains the authentication guards that will be checked when + | Sanctum is trying to authenticate a request. If none of these guards + | are able to authenticate the request, Sanctum will use the bearer + | token that's present on an incoming request for authentication. + | + */ + + 'guard' => ['web'], + + /* + |-------------------------------------------------------------------------- + | Expiration Minutes + |-------------------------------------------------------------------------- + | + | This value controls the number of minutes until an issued token will be + | considered expired. This will override any values set in the token's + | "expires_at" attribute, but first-party sessions are not affected. + | + */ + + 'expiration' => 20, + + /* + |-------------------------------------------------------------------------- + | Token Prefix + |-------------------------------------------------------------------------- + | + | Sanctum can prefix new tokens in order to take advantage of numerous + | security scanning initiatives maintained by open source platforms + | that notify developers if they commit tokens into repositories. + | + | See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning + | + */ + + 'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''), + + /* + |-------------------------------------------------------------------------- + | Sanctum Middleware + |-------------------------------------------------------------------------- + | + | When authenticating your first-party SPA with Sanctum you may need to + | customize some of the middleware Sanctum uses while processing the + | request. You may change the middleware listed below as required. + | + */ + + 'middleware' => [ + 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, + 'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class, + 'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, + ], + +]; diff --git a/config/services.php b/config/services.php new file mode 100644 index 0000000..27a3617 --- /dev/null +++ b/config/services.php @@ -0,0 +1,38 @@ + [ + 'token' => env('POSTMARK_TOKEN'), + ], + + 'ses' => [ + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + ], + + 'resend' => [ + 'key' => env('RESEND_KEY'), + ], + + 'slack' => [ + 'notifications' => [ + 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), + 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), + ], + ], + +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..ba0aa60 --- /dev/null +++ b/config/session.php @@ -0,0 +1,217 @@ + env('SESSION_DRIVER', 'database'), + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle before it expires. If you want them + | to expire immediately when the browser is closed then you may + | indicate that via the expire_on_close configuration option. + | + */ + + 'lifetime' => (int) env('SESSION_LIFETIME', 120), + + 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), + + /* + |-------------------------------------------------------------------------- + | Session Encryption + |-------------------------------------------------------------------------- + | + | This option allows you to easily specify that all of your session data + | should be encrypted before it's stored. All encryption is performed + | automatically by Laravel and you may use the session like normal. + | + */ + + 'encrypt' => env('SESSION_ENCRYPT', false), + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When utilizing the "file" session driver, the session files are placed + | on disk. The default storage location is defined here; however, you + | are free to provide another location where they should be stored. + | + */ + + 'files' => storage_path('framework/sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => env('SESSION_CONNECTION'), + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table to + | be used to store sessions. Of course, a sensible default is defined + | for you; however, you're welcome to change this to another table. + | + */ + + 'table' => env('SESSION_TABLE', 'sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Cache Store + |-------------------------------------------------------------------------- + | + | When using one of the framework's cache driven session backends, you may + | define the cache store which should be used to store the session data + | between requests. This must match one of your defined cache stores. + | + | Affects: "apc", "dynamodb", "memcached", "redis" + | + */ + + 'store' => env('SESSION_STORE'), + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => [2, 100], + + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the session cookie that is created by + | the framework. Typically, you should not need to change this value + | since doing so does not grant a meaningful security improvement. + | + */ + + 'cookie' => env( + 'SESSION_COOKIE', + Str::slug(env('APP_NAME', 'laravel'), '_').'_session' + ), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application, but you're free to change this when necessary. + | + */ + + 'path' => env('SESSION_PATH', '/'), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | This value determines the domain and subdomains the session cookie is + | available to. By default, the cookie will be available to the root + | domain and all subdomains. Typically, this shouldn't be changed. + | + */ + + 'domain' => env('SESSION_DOMAIN'), + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you when it can't be done securely. + | + */ + + 'secure' => env('SESSION_SECURE_COOKIE'), + + /* + |-------------------------------------------------------------------------- + | HTTP Access Only + |-------------------------------------------------------------------------- + | + | Setting this value to true will prevent JavaScript from accessing the + | value of the cookie and the cookie will only be accessible through + | the HTTP protocol. It's unlikely you should disable this option. + | + */ + + 'http_only' => env('SESSION_HTTP_ONLY', true), + + /* + |-------------------------------------------------------------------------- + | Same-Site Cookies + |-------------------------------------------------------------------------- + | + | This option determines how your cookies behave when cross-site requests + | take place, and can be used to mitigate CSRF attacks. By default, we + | will set this value to "lax" to permit secure cross-site requests. + | + | See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value + | + | Supported: "lax", "strict", "none", null + | + */ + + 'same_site' => env('SESSION_SAME_SITE', 'lax'), + + /* + |-------------------------------------------------------------------------- + | Partitioned Cookies + |-------------------------------------------------------------------------- + | + | Setting this value to true will tie the cookie to the top-level site for + | a cross-site context. Partitioned cookies are accepted by the browser + | when flagged "secure" and the Same-Site attribute is set to "none". + | + */ + + 'partitioned' => env('SESSION_PARTITIONED_COOKIE', false), + +]; diff --git a/config/telescope.php b/config/telescope.php new file mode 100644 index 0000000..8e6fd1c --- /dev/null +++ b/config/telescope.php @@ -0,0 +1,206 @@ + env('TELESCOPE_ENABLED', true), + + /* + |-------------------------------------------------------------------------- + | Telescope Domain + |-------------------------------------------------------------------------- + | + | This is the subdomain where Telescope will be accessible from. If the + | setting is null, Telescope will reside under the same domain as the + | application. Otherwise, this value will be used as the subdomain. + | + */ + + 'domain' => env('TELESCOPE_DOMAIN'), + + /* + |-------------------------------------------------------------------------- + | Telescope Path + |-------------------------------------------------------------------------- + | + | This is the URI path where Telescope will be accessible from. Feel free + | to change this path to anything you like. Note that the URI will not + | affect the paths of its internal API that aren't exposed to users. + | + */ + + 'path' => env('TELESCOPE_PATH', 'telescope'), + + /* + |-------------------------------------------------------------------------- + | Telescope Storage Driver + |-------------------------------------------------------------------------- + | + | This configuration options determines the storage driver that will + | be used to store Telescope's data. In addition, you may set any + | custom options as needed by the particular driver you choose. + | + */ + + 'driver' => env('TELESCOPE_DRIVER', 'database'), + + 'storage' => [ + 'database' => [ + 'connection' => env('DB_CONNECTION', 'mysql'), + 'chunk' => 1000, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Telescope Queue + |-------------------------------------------------------------------------- + | + | This configuration options determines the queue connection and queue + | which will be used to process ProcessPendingUpdate jobs. This can + | be changed if you would prefer to use a non-default connection. + | + */ + + 'queue' => [ + 'connection' => env('TELESCOPE_QUEUE_CONNECTION', null), + 'queue' => env('TELESCOPE_QUEUE', null), + 'delay' => env('TELESCOPE_QUEUE_DELAY', 10), + ], + + /* + |-------------------------------------------------------------------------- + | Telescope Route Middleware + |-------------------------------------------------------------------------- + | + | These middleware will be assigned to every Telescope route, giving you + | the chance to add your own middleware to this list or change any of + | the existing middleware. Or, you can simply stick with this list. + | + */ + + 'middleware' => [ + 'web', + Authorize::class, + ], + + /* + |-------------------------------------------------------------------------- + | Allowed / Ignored Paths & Commands + |-------------------------------------------------------------------------- + | + | The following array lists the URI paths and Artisan commands that will + | not be watched by Telescope. In addition to this list, some Laravel + | commands, like migrations and queue commands, are always ignored. + | + */ + + 'only_paths' => [ + // 'api/*' + ], + + 'ignore_paths' => [ + 'livewire*', + 'nova-api*', + 'pulse*', + ], + + 'ignore_commands' => [ + // + ], + + /* + |-------------------------------------------------------------------------- + | Telescope Watchers + |-------------------------------------------------------------------------- + | + | The following array lists the "watchers" that will be registered with + | Telescope. The watchers gather the application's profile data when + | a request or task is executed. Feel free to customize this list. + | + */ + + 'watchers' => [ + Watchers\BatchWatcher::class => env('TELESCOPE_BATCH_WATCHER', true), + + Watchers\CacheWatcher::class => [ + 'enabled' => env('TELESCOPE_CACHE_WATCHER', true), + 'hidden' => [], + ], + + Watchers\ClientRequestWatcher::class => env('TELESCOPE_CLIENT_REQUEST_WATCHER', true), + + Watchers\CommandWatcher::class => [ + 'enabled' => env('TELESCOPE_COMMAND_WATCHER', true), + 'ignore' => [], + ], + + Watchers\DumpWatcher::class => [ + 'enabled' => env('TELESCOPE_DUMP_WATCHER', true), + 'always' => env('TELESCOPE_DUMP_WATCHER_ALWAYS', false), + ], + + Watchers\EventWatcher::class => [ + 'enabled' => env('TELESCOPE_EVENT_WATCHER', true), + 'ignore' => [], + ], + + Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true), + + Watchers\GateWatcher::class => [ + 'enabled' => env('TELESCOPE_GATE_WATCHER', true), + 'ignore_abilities' => [], + 'ignore_packages' => true, + 'ignore_paths' => [], + ], + + Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true), + + Watchers\LogWatcher::class => [ + 'enabled' => env('TELESCOPE_LOG_WATCHER', true), + 'level' => 'error', + ], + + Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true), + + Watchers\ModelWatcher::class => [ + 'enabled' => env('TELESCOPE_MODEL_WATCHER', true), + 'events' => ['eloquent.*'], + 'hydrations' => true, + ], + + Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true), + + Watchers\QueryWatcher::class => [ + 'enabled' => env('TELESCOPE_QUERY_WATCHER', true), + 'ignore_packages' => true, + 'ignore_paths' => [], + 'slow' => 100, + ], + + Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true), + + Watchers\RequestWatcher::class => [ + 'enabled' => env('TELESCOPE_REQUEST_WATCHER', true), + 'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64), + 'ignore_http_methods' => [], + 'ignore_status_codes' => [], + ], + + Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true), + Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true), + ], +]; diff --git a/database/.gitignore b/database/.gitignore new file mode 100644 index 0000000..9b19b93 --- /dev/null +++ b/database/.gitignore @@ -0,0 +1 @@ +*.sqlite* diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php new file mode 100644 index 0000000..584104c --- /dev/null +++ b/database/factories/UserFactory.php @@ -0,0 +1,44 @@ + + */ +class UserFactory extends Factory +{ + /** + * The current password being used by the factory. + */ + protected static ?string $password; + + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'name' => fake()->name(), + 'email' => fake()->unique()->safeEmail(), + 'email_verified_at' => now(), + 'password' => static::$password ??= Hash::make('password'), + 'remember_token' => Str::random(10), + ]; + } + + /** + * Indicate that the model's email address should be unverified. + */ + public function unverified(): static + { + return $this->state(fn (array $attributes) => [ + 'email_verified_at' => null, + ]); + } +} diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php new file mode 100644 index 0000000..05fb5d9 --- /dev/null +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -0,0 +1,49 @@ +id(); + $table->string('name'); + $table->string('email')->unique(); + $table->timestamp('email_verified_at')->nullable(); + $table->string('password'); + $table->rememberToken(); + $table->timestamps(); + }); + + Schema::create('password_reset_tokens', function (Blueprint $table) { + $table->string('email')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + + Schema::create('sessions', function (Blueprint $table) { + $table->string('id')->primary(); + $table->foreignId('user_id')->nullable()->index(); + $table->string('ip_address', 45)->nullable(); + $table->text('user_agent')->nullable(); + $table->longText('payload'); + $table->integer('last_activity')->index(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('users'); + Schema::dropIfExists('password_reset_tokens'); + Schema::dropIfExists('sessions'); + } +}; diff --git a/database/migrations/0001_01_01_000001_create_cache_table.php b/database/migrations/0001_01_01_000001_create_cache_table.php new file mode 100644 index 0000000..b9c106b --- /dev/null +++ b/database/migrations/0001_01_01_000001_create_cache_table.php @@ -0,0 +1,35 @@ +string('key')->primary(); + $table->mediumText('value'); + $table->integer('expiration'); + }); + + Schema::create('cache_locks', function (Blueprint $table) { + $table->string('key')->primary(); + $table->string('owner'); + $table->integer('expiration'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cache'); + Schema::dropIfExists('cache_locks'); + } +}; diff --git a/database/migrations/0001_01_01_000002_create_jobs_table.php b/database/migrations/0001_01_01_000002_create_jobs_table.php new file mode 100644 index 0000000..425e705 --- /dev/null +++ b/database/migrations/0001_01_01_000002_create_jobs_table.php @@ -0,0 +1,57 @@ +id(); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + + Schema::create('job_batches', function (Blueprint $table) { + $table->string('id')->primary(); + $table->string('name'); + $table->integer('total_jobs'); + $table->integer('pending_jobs'); + $table->integer('failed_jobs'); + $table->longText('failed_job_ids'); + $table->mediumText('options')->nullable(); + $table->integer('cancelled_at')->nullable(); + $table->integer('created_at'); + $table->integer('finished_at')->nullable(); + }); + + Schema::create('failed_jobs', function (Blueprint $table) { + $table->id(); + $table->string('uuid')->unique(); + $table->text('connection'); + $table->text('queue'); + $table->longText('payload'); + $table->longText('exception'); + $table->timestamp('failed_at')->useCurrent(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('jobs'); + Schema::dropIfExists('job_batches'); + Schema::dropIfExists('failed_jobs'); + } +}; diff --git a/database/migrations/2025_03_23_112822_create_clients_table.php b/database/migrations/2025_03_23_112822_create_clients_table.php new file mode 100644 index 0000000..8a88b51 --- /dev/null +++ b/database/migrations/2025_03_23_112822_create_clients_table.php @@ -0,0 +1,34 @@ +id(); + $table->string('name'); + $table->string('tax_number'); + $table->string('address'); + $table->string('phone'); + $table->string('email'); + $table->foreignId('seller_id')->constrained('users')->onDelete('cascade'); + $table->unsignedBigInteger('receive_invoice_id')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('clients'); + } +}; diff --git a/database/migrations/2025_03_23_113932_create_receive_invoice_types_table.php b/database/migrations/2025_03_23_113932_create_receive_invoice_types_table.php new file mode 100644 index 0000000..eb0a21b --- /dev/null +++ b/database/migrations/2025_03_23_113932_create_receive_invoice_types_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('description'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('receive_invoice_types'); + } +}; diff --git a/database/migrations/2025_03_23_114136_create_client_foreignkeys.php b/database/migrations/2025_03_23_114136_create_client_foreignkeys.php new file mode 100644 index 0000000..3069a43 --- /dev/null +++ b/database/migrations/2025_03_23_114136_create_client_foreignkeys.php @@ -0,0 +1,26 @@ +foreign('receive_invoice_id')->references('id')->on('receive_invoice_types')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('client_foreignkeys'); + } +}; diff --git a/database/migrations/2025_03_26_155735_add_column_status_to_clients.php b/database/migrations/2025_03_26_155735_add_column_status_to_clients.php new file mode 100644 index 0000000..38ca53f --- /dev/null +++ b/database/migrations/2025_03_26_155735_add_column_status_to_clients.php @@ -0,0 +1,28 @@ +enum('status', ['A', 'I'])->default('A')->after('seller_id'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('clients', function (Blueprint $table) { + $table->dropColumn('status'); + }); + } +}; diff --git a/database/migrations/2025_03_27_152255_create_c_p_e_s_table.php b/database/migrations/2025_03_27_152255_create_c_p_e_s_table.php new file mode 100644 index 0000000..86e965e --- /dev/null +++ b/database/migrations/2025_03_27_152255_create_c_p_e_s_table.php @@ -0,0 +1,64 @@ +id(); + $table->string('description')->unique(); + $table->timestamps(); + }); + + Schema::create('contract_status', function (Blueprint $table) { + $table->id(); + $table->string('code'); + $table->string('description')->unique(); + $table->timestamps(); + }); + + Schema::create('cpe', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('client_id'); + $table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade'); + + $table->decimal('pvp', 10, 2); + $table->decimal('net', 10, 2); + $table->decimal('power', 8, 2); + $table->string('tier'); + $table->decimal('annual_consumption', 8, 2); + $table->unsignedBigInteger('contract_type_id'); + $table->foreign('contract_type_id')->references('id')->on('contract_types')->onDelete('cascade'); + + $table->date('validity'); + $table->date('activation_date'); + $table->date('renewal_date')->nullable(); + $table->text('notes')->nullable(); + $table->date('payment_date')->nullable(); + $table->string('previous_supplier'); + + $table->unsignedBigInteger('status_id'); + $table->foreign('status_id')->references('id')->on('contract_status')->onDelete('cascade'); + + $table->timestamps(); + }); + + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('contract_status'); + Schema::dropIfExists('contract_types'); + Schema::dropIfExists('cpe'); + } +}; diff --git a/database/migrations/2025_04_03_101233_add_client_type_to_clients_table.php b/database/migrations/2025_04_03_101233_add_client_type_to_clients_table.php new file mode 100644 index 0000000..540308a --- /dev/null +++ b/database/migrations/2025_04_03_101233_add_client_type_to_clients_table.php @@ -0,0 +1,28 @@ +enum('client_type', ['business', 'domestic'])->default('domestic')->after('email'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('clients', function (Blueprint $table) { + $table->dropColumn('client_type'); + }); + } +}; diff --git a/database/migrations/2025_04_03_143359_create_cpe_payments_table.php b/database/migrations/2025_04_03_143359_create_cpe_payments_table.php new file mode 100644 index 0000000..7ff85e4 --- /dev/null +++ b/database/migrations/2025_04_03_143359_create_cpe_payments_table.php @@ -0,0 +1,33 @@ +id(); + $table->unsignedBigInteger('cpe_id'); + $table->foreign('cpe_id')->references('id')->on('cpe')->onDelete('cascade'); + $table->decimal('amount', 10, 2); + $table->date('reference_period'); + $table->date('payment_date'); + $table->enum('status', ['pending', 'paid', 'overdue'])->default('pending'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cpe_payments'); + } +}; diff --git a/database/migrations/2025_04_10_191159_create_telescope_entries_table.php b/database/migrations/2025_04_10_191159_create_telescope_entries_table.php new file mode 100644 index 0000000..700a83f --- /dev/null +++ b/database/migrations/2025_04_10_191159_create_telescope_entries_table.php @@ -0,0 +1,70 @@ +getConnection()); + + $schema->create('telescope_entries', function (Blueprint $table) { + $table->bigIncrements('sequence'); + $table->uuid('uuid'); + $table->uuid('batch_id'); + $table->string('family_hash')->nullable(); + $table->boolean('should_display_on_index')->default(true); + $table->string('type', 20); + $table->longText('content'); + $table->dateTime('created_at')->nullable(); + + $table->unique('uuid'); + $table->index('batch_id'); + $table->index('family_hash'); + $table->index('created_at'); + $table->index(['type', 'should_display_on_index']); + }); + + $schema->create('telescope_entries_tags', function (Blueprint $table) { + $table->uuid('entry_uuid'); + $table->string('tag'); + + $table->primary(['entry_uuid', 'tag']); + $table->index('tag'); + + $table->foreign('entry_uuid') + ->references('uuid') + ->on('telescope_entries') + ->onDelete('cascade'); + }); + + $schema->create('telescope_monitoring', function (Blueprint $table) { + $table->string('tag')->primary(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + $schema = Schema::connection($this->getConnection()); + + $schema->dropIfExists('telescope_entries_tags'); + $schema->dropIfExists('telescope_entries'); + $schema->dropIfExists('telescope_monitoring'); + } +}; diff --git a/database/migrations/2025_04_10_192052_add_status_index_to_clients_table.php b/database/migrations/2025_04_10_192052_add_status_index_to_clients_table.php new file mode 100644 index 0000000..a950499 --- /dev/null +++ b/database/migrations/2025_04_10_192052_add_status_index_to_clients_table.php @@ -0,0 +1,28 @@ +index('status'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('clients', function (Blueprint $table) { + $table->dropIndex(['status']); + }); + } +}; diff --git a/database/migrations/2025_04_11_181702_add_notes_and_contact_info_to_clients_table.php b/database/migrations/2025_04_11_181702_add_notes_and_contact_info_to_clients_table.php new file mode 100644 index 0000000..ab77465 --- /dev/null +++ b/database/migrations/2025_04_11_181702_add_notes_and_contact_info_to_clients_table.php @@ -0,0 +1,30 @@ +text('contact_info')->nullable()->after('status'); + $table->text('notes')->nullable()->after('status'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('clients', function (Blueprint $table) { + $table->dropColumn('contact_info'); + $table->dropColumn('notes'); + }); + } +}; diff --git a/database/migrations/2025_04_19_175820_create_payment_methods_table.php b/database/migrations/2025_04_19_175820_create_payment_methods_table.php new file mode 100644 index 0000000..5455729 --- /dev/null +++ b/database/migrations/2025_04_19_175820_create_payment_methods_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('name'); + $table->timestamps(); + }); + } + + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('payment_methods'); + } +}; diff --git a/database/migrations/2025_04_19_175854_add_payment_method_id_to_cpe_table.php b/database/migrations/2025_04_19_175854_add_payment_method_id_to_cpe_table.php new file mode 100644 index 0000000..668d132 --- /dev/null +++ b/database/migrations/2025_04_19_175854_add_payment_method_id_to_cpe_table.php @@ -0,0 +1,35 @@ +unsignedBigInteger('payment_method_id')->nullable()->after('net'); + + $table->foreign('payment_method_id') + ->references('id') + ->on('payment_methods') + ->onDelete('restrict'); + }); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('cpe', function (Blueprint $table) { + // + }); + } +}; diff --git a/database/migrations/2025_04_19_180919_add_icon_to_payment_methods_table.php b/database/migrations/2025_04_19_180919_add_icon_to_payment_methods_table.php new file mode 100644 index 0000000..a9c1dbc --- /dev/null +++ b/database/migrations/2025_04_19_180919_add_icon_to_payment_methods_table.php @@ -0,0 +1,28 @@ +string('icon')->nullable()->after('name'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('payment_methods', function (Blueprint $table) { + $table->dropColumn('icon'); + }); + } +}; diff --git a/database/migrations/2025_04_23_104031_create_contracts_table.php b/database/migrations/2025_04_23_104031_create_contracts_table.php new file mode 100644 index 0000000..70a6667 --- /dev/null +++ b/database/migrations/2025_04_23_104031_create_contracts_table.php @@ -0,0 +1,42 @@ +id(); + $table->foreignId('client_id')->constrained(); + $table->enum('type', ['cpe', 'cpi']); + $table->decimal('pvp', 10, 2); + $table->decimal('net', 10, 2); + $table->decimal('power', 10, 2); + $table->integer('annual_consumption'); + $table->string('tier')->nullable(); + $table->foreignId('contract_type_id')->constrained(); + $table->date('validity')->nullable(); + $table->date('activation_date')->nullable(); + $table->string('previous_supplier')->nullable(); + $table->foreignId('status_id')->constrained('contract_status'); + $table->decimal('commission_rate', 5, 2)->default(0); + $table->text('notes')->nullable(); + $table->timestamps(); + }); + } + + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('contracts'); + } +}; diff --git a/database/migrations/2025_04_23_104100_create_payments_table.php b/database/migrations/2025_04_23_104100_create_payments_table.php new file mode 100644 index 0000000..1365a0c --- /dev/null +++ b/database/migrations/2025_04_23_104100_create_payments_table.php @@ -0,0 +1,33 @@ +id(); + $table->foreignId('contract_id')->constrained()->onDelete('cascade'); + $table->decimal('amount', 10, 2); + $table->date('reference_period'); + $table->date('payment_date')->nullable(); + $table->enum('status', ['pending', 'paid', 'overdue']); + $table->timestamps(); + }); + } + + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('payments'); + } +}; diff --git a/database/migrations/2025_04_23_105408_drop_old_cpe_cpi_tables.php b/database/migrations/2025_04_23_105408_drop_old_cpe_cpi_tables.php new file mode 100644 index 0000000..cacb058 --- /dev/null +++ b/database/migrations/2025_04_23_105408_drop_old_cpe_cpi_tables.php @@ -0,0 +1,25 @@ +engine('InnoDB'); + $table->bigIncrements('id'); // permission id + $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) + $table->string('guard_name'); // For MyISAM use string('guard_name', 25); + $table->timestamps(); + + $table->unique(['name', 'guard_name']); + }); + + Schema::create($tableNames['roles'], static function (Blueprint $table) use ($teams, $columnNames) { + // $table->engine('InnoDB'); + $table->bigIncrements('id'); // role id + if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing + $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable(); + $table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index'); + } + $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) + $table->string('guard_name'); // For MyISAM use string('guard_name', 25); + $table->timestamps(); + if ($teams || config('permission.testing')) { + $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']); + } else { + $table->unique(['name', 'guard_name']); + } + }); + + Schema::create($tableNames['model_has_permissions'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) { + $table->unsignedBigInteger($pivotPermission); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index'); + + $table->foreign($pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } else { + $table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } + + }); + + Schema::create($tableNames['model_has_roles'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) { + $table->unsignedBigInteger($pivotRole); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index'); + + $table->foreign($pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } else { + $table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } + }); + + Schema::create($tableNames['role_has_permissions'], static function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) { + $table->unsignedBigInteger($pivotPermission); + $table->unsignedBigInteger($pivotRole); + + $table->foreign($pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + + $table->foreign($pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + + $table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary'); + }); + + app('cache') + ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null) + ->forget(config('permission.cache.key')); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + $tableNames = config('permission.table_names'); + + if (empty($tableNames)) { + throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.'); + } + + Schema::drop($tableNames['role_has_permissions']); + Schema::drop($tableNames['model_has_roles']); + Schema::drop($tableNames['model_has_permissions']); + Schema::drop($tableNames['roles']); + Schema::drop($tableNames['permissions']); + } +}; diff --git a/database/migrations/2025_04_30_134322_add_description_to_permissions_table.php b/database/migrations/2025_04_30_134322_add_description_to_permissions_table.php new file mode 100644 index 0000000..53f5a98 --- /dev/null +++ b/database/migrations/2025_04_30_134322_add_description_to_permissions_table.php @@ -0,0 +1,28 @@ +string('description')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('permissions', function (Blueprint $table) { + $table->dropColumn('description'); + }); + } +}; diff --git a/database/migrations/2025_04_30_153303_add_description_to_roles_table.php b/database/migrations/2025_04_30_153303_add_description_to_roles_table.php new file mode 100644 index 0000000..e2c04eb --- /dev/null +++ b/database/migrations/2025_04_30_153303_add_description_to_roles_table.php @@ -0,0 +1,28 @@ +string('description')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('roles', function (Blueprint $table) { + $table->dropColumn('description'); + }); + } +}; diff --git a/database/migrations/2025_05_28_075006_create_client_types_table.php b/database/migrations/2025_05_28_075006_create_client_types_table.php new file mode 100644 index 0000000..2854589 --- /dev/null +++ b/database/migrations/2025_05_28_075006_create_client_types_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('description'); + $table->string('icon')->nullable(); + $table->string('color')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('client_types'); + } +}; diff --git a/database/migrations/2025_05_28_075025_update_clients_table_with_client_type_id.php b/database/migrations/2025_05_28_075025_update_clients_table_with_client_type_id.php new file mode 100644 index 0000000..a9f5a0c --- /dev/null +++ b/database/migrations/2025_05_28_075025_update_clients_table_with_client_type_id.php @@ -0,0 +1,32 @@ +unsignedBigInteger('client_type_id')->nullable()->after('id'); + + // Se quiser remover o campo antigo: + // $table->dropColumn('client_type'); + + $table->foreign('client_type_id')->references('id')->on('client_types')->onDelete('set null'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/database/migrations/2025_05_28_075243_remove_client_type_column_from_clients_table.php b/database/migrations/2025_05_28_075243_remove_client_type_column_from_clients_table.php new file mode 100644 index 0000000..59ebbce --- /dev/null +++ b/database/migrations/2025_05_28_075243_remove_client_type_column_from_clients_table.php @@ -0,0 +1,32 @@ +dropColumn('client_type'); + }); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('clients', function (Blueprint $table) { + Schema::table('clients', function (Blueprint $table) { + $table->string('client_type')->nullable(); + }); + }); + } +}; diff --git a/database/migrations/2025_06_02_184902_create_power_tiers_table.php b/database/migrations/2025_06_02_184902_create_power_tiers_table.php new file mode 100644 index 0000000..61f0d01 --- /dev/null +++ b/database/migrations/2025_06_02_184902_create_power_tiers_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('name')->unique(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('power_tiers'); + } +}; diff --git a/database/migrations/2025_06_02_185651_update_contracts_table_for_new_fields.php b/database/migrations/2025_06_02_185651_update_contracts_table_for_new_fields.php new file mode 100644 index 0000000..5474404 --- /dev/null +++ b/database/migrations/2025_06_02_185651_update_contracts_table_for_new_fields.php @@ -0,0 +1,93 @@ +id(); + $table->string('name'); + $table->timestamps(); + }); + + Schema::table('contracts', function (Blueprint $table) { + // DROP colunas obsoletas + if (Schema::hasColumn('contracts', 'pvp')) { + $table->dropColumn('pvp'); + } + if (Schema::hasColumn('contracts', 'net')) { + $table->dropColumn('net'); + } + if (Schema::hasColumn('contracts', 'power')) { + $table->dropColumn('power'); + } + if (Schema::hasColumn('contracts', 'previous_supplier')) { + $table->dropColumn('previous_supplier'); + } + + // Somente adiciona se não existir + if (!Schema::hasColumn('contracts', 'supply_type')) { + $table->enum('supply_type', ['cpe', 'cui'])->after('client_id'); + } + + if (!Schema::hasColumn('contracts', 'supply_address')) { + $table->string('supply_address')->nullable()->after('supply_type'); + } + + if (!Schema::hasColumn('contracts', 'power_tier_id')) { + $table->foreignId('power_tier_id')->nullable()->constrained()->after('annual_consumption'); + } + + if (!Schema::hasColumn('contracts', 'payment_method_id')) { + $table->foreignId('payment_method_id')->nullable()->constrained()->after('contract_type_id'); + } + + if (!Schema::hasColumn('contracts', 'delivery_method')) { + $table->enum('delivery_method', ['correio', 'email'])->nullable()->after('payment_method_id'); + } + + if (!Schema::hasColumn('contracts', 'delivery_email')) { + $table->string('delivery_email')->nullable()->after('delivery_method'); + } + + if (!Schema::hasColumn('contracts', 'contract_date')) { + $table->date('contract_date')->nullable()->after('validity'); + } + + if (!Schema::hasColumn('contracts', 'previous_supplier_id')) { + $table->foreignId('previous_supplier_id')->nullable()->constrained('suppliers')->after('contract_date'); + } + + if (!Schema::hasColumn('contracts', 'new_supplier_id')) { + $table->foreignId('new_supplier_id')->nullable()->constrained('suppliers')->after('previous_supplier_id'); + } + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + + Schema::dropIfExists('suppliers'); + Schema::table('contracts', function (Blueprint $table) { + // ROLLBACK: Recriar colunas removidas + $table->decimal('pvp', 10, 2)->nullable(); + $table->decimal('net', 10, 2)->nullable(); + $table->decimal('power', 10, 2)->nullable(); + $table->string('previous_supplier')->nullable(); + + // Remover novas colunas + $table->dropForeign(['power_tier_id']); + $table->dropColumn(['supply_type', 'supply_address', 'power_tier_id', 'payment_method_id', 'delivery_method', 'delivery_email', 'contract_date', 'previous_supplier_id', 'new_supplier_id']); + }); + } +}; diff --git a/database/migrations/2025_06_04_080623_add_seller_id_to_contracts_table.php b/database/migrations/2025_06_04_080623_add_seller_id_to_contracts_table.php new file mode 100644 index 0000000..23b4eea --- /dev/null +++ b/database/migrations/2025_06_04_080623_add_seller_id_to_contracts_table.php @@ -0,0 +1,30 @@ +unsignedBigInteger('seller_id')->nullable()->after('client_id'); + $table->foreign('seller_id')->references('id')->on('users')->onDelete('set null'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->dropForeign(['seller_id']); + $table->dropColumn('seller_id'); + }); + } +}; diff --git a/database/migrations/2025_06_06_083053_add_financial_fields_to_contracts_table.php b/database/migrations/2025_06_06_083053_add_financial_fields_to_contracts_table.php new file mode 100644 index 0000000..bb9a8e2 --- /dev/null +++ b/database/migrations/2025_06_06_083053_add_financial_fields_to_contracts_table.php @@ -0,0 +1,30 @@ +decimal('contract_value', 10, 2)->nullable()->after('client_id'); + $table->decimal('commission_value', 10, 2)->nullable()->after('contract_value'); + $table->decimal('profit_value', 10, 2)->nullable()->after('commission_value'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->dropColumn(['contract_value', 'commission_value', 'profit_value']); + }); + } +}; diff --git a/database/migrations/2025_06_12_143226_rename_tier_to_code_in_contracts_table.php b/database/migrations/2025_06_12_143226_rename_tier_to_code_in_contracts_table.php new file mode 100644 index 0000000..b994593 --- /dev/null +++ b/database/migrations/2025_06_12_143226_rename_tier_to_code_in_contracts_table.php @@ -0,0 +1,28 @@ +renameColumn('tier', 'code'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->renameColumn('code', 'tier'); + }); + } +}; diff --git a/database/migrations/2025_06_12_144037_create_typologies_table.php b/database/migrations/2025_06_12_144037_create_typologies_table.php new file mode 100644 index 0000000..c9acb09 --- /dev/null +++ b/database/migrations/2025_06_12_144037_create_typologies_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('code')->unique(); + $table->string('description'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('typologies'); + } +}; diff --git a/database/migrations/2025_06_12_144056_add_typology_id_to_contracts_table.php b/database/migrations/2025_06_12_144056_add_typology_id_to_contracts_table.php new file mode 100644 index 0000000..c2f965a --- /dev/null +++ b/database/migrations/2025_06_12_144056_add_typology_id_to_contracts_table.php @@ -0,0 +1,29 @@ +foreignId('typology_id')->nullable()->constrained('typologies')->onDelete('set null'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->dropForeign(['typology_id']); + $table->dropColumn('typology_id'); + }); + } +}; diff --git a/database/migrations/2025_06_12_144336_drop_code_from_typologies_table.php b/database/migrations/2025_06_12_144336_drop_code_from_typologies_table.php new file mode 100644 index 0000000..8a043ac --- /dev/null +++ b/database/migrations/2025_06_12_144336_drop_code_from_typologies_table.php @@ -0,0 +1,28 @@ +dropColumn('code'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('typologies', function (Blueprint $table) { + $table->string('code')->unique()->nullable(); + }); + } +}; diff --git a/database/migrations/2025_06_12_160216_remove_receive_invoice_id_from_clients_table.php b/database/migrations/2025_06_12_160216_remove_receive_invoice_id_from_clients_table.php new file mode 100644 index 0000000..9167c29 --- /dev/null +++ b/database/migrations/2025_06_12_160216_remove_receive_invoice_id_from_clients_table.php @@ -0,0 +1,27 @@ +dropForeign(['receive_invoice_id']); + $table->dropColumn('receive_invoice_id'); + }); + } + + public function down(): void + { + Schema::table('clients', function (Blueprint $table) { + $table->unsignedBigInteger('receive_invoice_id')->nullable()->after('contact_info'); + + $table->foreign('receive_invoice_id') + ->references('id') + ->on('receive_invoice_types') + ->onDelete('cascade'); + }); + } +}; diff --git a/database/migrations/2025_06_20_132113_create_ciu_tiers_table.php b/database/migrations/2025_06_20_132113_create_ciu_tiers_table.php new file mode 100644 index 0000000..f0639a6 --- /dev/null +++ b/database/migrations/2025_06_20_132113_create_ciu_tiers_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('name'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cui_tiers'); + } +}; diff --git a/database/migrations/2025_06_20_133448_add_ciu_tier_id_to_contracts_table.php b/database/migrations/2025_06_20_133448_add_ciu_tier_id_to_contracts_table.php new file mode 100644 index 0000000..c128335 --- /dev/null +++ b/database/migrations/2025_06_20_133448_add_ciu_tier_id_to_contracts_table.php @@ -0,0 +1,23 @@ +unsignedBigInteger('cui_tier_id')->nullable()->after('power_tier_id'); + $table->foreign('cui_tier_id')->references('id')->on('cui_tiers')->onDelete('set null'); + }); + } + + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->dropForeign(['cui_tier_id']); + $table->dropColumn('cui_tier_id'); + }); + } +}; diff --git a/database/migrations/2025_06_23_192219_add_status_to_resources_tables.php b/database/migrations/2025_06_23_192219_add_status_to_resources_tables.php new file mode 100644 index 0000000..18125d3 --- /dev/null +++ b/database/migrations/2025_06_23_192219_add_status_to_resources_tables.php @@ -0,0 +1,53 @@ +char('status', 1)->default('A')->after('id'); + }); + + Schema::table('contract_types', function (Blueprint $table) { + $table->char('status', 1)->default('A')->after('id'); + }); + + Schema::table('payment_methods', function (Blueprint $table) { + $table->char('status', 1)->default('A')->after('id'); + }); + + Schema::table('typologies', function (Blueprint $table) { + $table->char('status', 1)->default('A')->after('id'); + }); + + Schema::table('cui_tiers', function (Blueprint $table) { + $table->char('status', 1)->default('A')->after('id'); + }); + } + + public function down(): void + { + Schema::table('power_tiers', function (Blueprint $table) { + $table->dropColumn('status'); + }); + + Schema::table('contract_types', function (Blueprint $table) { + $table->dropColumn('status'); + }); + + Schema::table('payment_methods', function (Blueprint $table) { + $table->dropColumn('status'); + }); + + Schema::table('typologies', function (Blueprint $table) { + $table->dropColumn('status'); + }); + + Schema::table('cui_tiers', function (Blueprint $table) { + $table->dropColumn('status'); + }); + } +}; diff --git a/database/migrations/2025_06_23_192618_add_status_to_suppliers.php b/database/migrations/2025_06_23_192618_add_status_to_suppliers.php new file mode 100644 index 0000000..a565a1c --- /dev/null +++ b/database/migrations/2025_06_23_192618_add_status_to_suppliers.php @@ -0,0 +1,28 @@ +char('status', 1)->default('A')->after('id'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('suppliers', function (Blueprint $table) { + $table->dropColumn('status'); + }); + } +}; diff --git a/database/migrations/2025_06_25_110317_add_can_login_to_users_table.php b/database/migrations/2025_06_25_110317_add_can_login_to_users_table.php new file mode 100644 index 0000000..bea0118 --- /dev/null +++ b/database/migrations/2025_06_25_110317_add_can_login_to_users_table.php @@ -0,0 +1,28 @@ + boolean('can_login')->default(true); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('can_login'); + }); + } +}; diff --git a/database/migrations/2025_06_25_130953_make_annual_consumption_nullable_in_contracts_table.php b/database/migrations/2025_06_25_130953_make_annual_consumption_nullable_in_contracts_table.php new file mode 100644 index 0000000..815181a --- /dev/null +++ b/database/migrations/2025_06_25_130953_make_annual_consumption_nullable_in_contracts_table.php @@ -0,0 +1,28 @@ +decimal('annual_consumption', 12, 2)->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->decimal('annual_consumption', 12, 2)->nullable(false)->change(); + }); + } +}; diff --git a/database/migrations/2025_06_25_131956_remove_type_from_contracts_table.php b/database/migrations/2025_06_25_131956_remove_type_from_contracts_table.php new file mode 100644 index 0000000..1f9780b --- /dev/null +++ b/database/migrations/2025_06_25_131956_remove_type_from_contracts_table.php @@ -0,0 +1,28 @@ +dropColumn('type'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->string('type')->nullable(); + }); + } +}; diff --git a/database/migrations/2025_06_25_151156_add_color_to_suppliers_table.php b/database/migrations/2025_06_25_151156_add_color_to_suppliers_table.php new file mode 100644 index 0000000..f6eaccd --- /dev/null +++ b/database/migrations/2025_06_25_151156_add_color_to_suppliers_table.php @@ -0,0 +1,28 @@ +string('color', 20)->nullable()->after('name'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('suppliers', function (Blueprint $table) { + $table->dropColumn('color'); + }); + } +}; diff --git a/database/migrations/2025_08_22_091214_add_color_to_contract_status_table.php b/database/migrations/2025_08_22_091214_add_color_to_contract_status_table.php new file mode 100644 index 0000000..7056be0 --- /dev/null +++ b/database/migrations/2025_08_22_091214_add_color_to_contract_status_table.php @@ -0,0 +1,28 @@ +string('color', 7)->nullable()->after('description'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contract_status', function (Blueprint $table) { + $table->dropColumn('color'); + }); + } +}; diff --git a/database/migrations/2025_08_25_141236_add_go_ki_to_contracts_table.php b/database/migrations/2025_08_25_141236_add_go_ki_to_contracts_table.php new file mode 100644 index 0000000..620bb3c --- /dev/null +++ b/database/migrations/2025_08_25_141236_add_go_ki_to_contracts_table.php @@ -0,0 +1,28 @@ +decimal('go_ki', 10, 2)->after('profit_value'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->dropColumn('go_ki'); + }); + } +}; diff --git a/database/migrations/2025_08_26_091926_create_lead_status_table.php b/database/migrations/2025_08_26_091926_create_lead_status_table.php new file mode 100644 index 0000000..846b44e --- /dev/null +++ b/database/migrations/2025_08_26_091926_create_lead_status_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('name'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('lead_status'); + } +}; diff --git a/database/migrations/2025_08_26_092040_add_type_and_lead_status_to_clients_table.php b/database/migrations/2025_08_26_092040_add_type_and_lead_status_to_clients_table.php new file mode 100644 index 0000000..404a950 --- /dev/null +++ b/database/migrations/2025_08_26_092040_add_type_and_lead_status_to_clients_table.php @@ -0,0 +1,32 @@ +enum('type', ['lead', 'client'])->default('client')->after('id'); + + $table->unsignedBigInteger('lead_status_id')->nullable()->after('type'); + $table->foreign('lead_status_id')->references('id')->on('lead_status'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('clients', function (Blueprint $table) { + $table->dropForeign(['lead_status_id']); + $table->dropColumn(['type', 'lead_status_id']); + }); + } +}; diff --git a/database/migrations/2025_08_26_101929_alter_clients_nullable_fields.php b/database/migrations/2025_08_26_101929_alter_clients_nullable_fields.php new file mode 100644 index 0000000..f48e3ef --- /dev/null +++ b/database/migrations/2025_08_26_101929_alter_clients_nullable_fields.php @@ -0,0 +1,29 @@ +string('tax_number')->nullable()->change(); + $table->string('address')->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('clients', function (Blueprint $table) { + // + }); + } +}; diff --git a/database/migrations/2025_08_27_142641_create_lead_details_table.php b/database/migrations/2025_08_27_142641_create_lead_details_table.php new file mode 100644 index 0000000..59ffa34 --- /dev/null +++ b/database/migrations/2025_08_27_142641_create_lead_details_table.php @@ -0,0 +1,25 @@ +id(); + $table->foreignId('client_id')->constrained('clients')->onDelete('cascade'); + $table->date('contact_date')->nullable(); + $table->date('contract_end_date')->nullable(); + $table->enum('contract_type', ['CPE', 'CUI'])->nullable(); + $table->timestamps(); + }); + } + + public function down() + { + Schema::dropIfExists('lead_details'); + } +}; diff --git a/database/migrations/2025_09_03_171449_add_delivery_point_code_to_lead_details_table.php b/database/migrations/2025_09_03_171449_add_delivery_point_code_to_lead_details_table.php new file mode 100644 index 0000000..8062997 --- /dev/null +++ b/database/migrations/2025_09_03_171449_add_delivery_point_code_to_lead_details_table.php @@ -0,0 +1,22 @@ +string('delivery_point_code')->nullable()->after('client_id'); + }); + } + + public function down(): void + { + Schema::table('lead_details', function (Blueprint $table) { + $table->dropColumn('delivery_point_code'); + }); + } +}; diff --git a/database/migrations/2025_09_04_135532_add_paid_to_contracts_table.php b/database/migrations/2025_09_04_135532_add_paid_to_contracts_table.php new file mode 100644 index 0000000..effb749 --- /dev/null +++ b/database/migrations/2025_09_04_135532_add_paid_to_contracts_table.php @@ -0,0 +1,22 @@ +boolean('paid')->default(false)->after('client_id'); + }); + } + + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->dropColumn('paid'); + }); + } +}; diff --git a/database/migrations/2025_09_08_110610_add_pin_to_users_table.php b/database/migrations/2025_09_08_110610_add_pin_to_users_table.php new file mode 100644 index 0000000..67b9e77 --- /dev/null +++ b/database/migrations/2025_09_08_110610_add_pin_to_users_table.php @@ -0,0 +1,28 @@ +string('pin')->nullable()->after('password'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('pin'); + }); + } +}; diff --git a/database/migrations/2025_09_08_175045_move_timestamps_to_end_in_contracts_table.php b/database/migrations/2025_09_08_175045_move_timestamps_to_end_in_contracts_table.php new file mode 100644 index 0000000..68f6492 --- /dev/null +++ b/database/migrations/2025_09_08_175045_move_timestamps_to_end_in_contracts_table.php @@ -0,0 +1,22 @@ +timestamp('created_at')->after('typology_id')->change(); + $table->timestamp('updated_at')->after('created_at')->change(); + }); + } + + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + + }); + } +}; diff --git a/database/migrations/2025_09_15_100622_create_contract_histories_table.php b/database/migrations/2025_09_15_100622_create_contract_histories_table.php new file mode 100644 index 0000000..c870c7a --- /dev/null +++ b/database/migrations/2025_09_15_100622_create_contract_histories_table.php @@ -0,0 +1,35 @@ +id(); + $table->foreignId('contract_id')->constrained('contracts')->onDelete('cascade'); + $table->date('renewal_date'); + $table->date('validity')->nullable(); + $table->decimal('contract_value', 10, 2); + $table->decimal('commission_value', 10, 2)->nullable(); + $table->decimal('profit_value', 10, 2)->nullable(); + $table->decimal('commission_rate', 5, 2)->nullable(); + $table->text('notes')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('contract_histories'); + } +}; diff --git a/database/migrations/2025_09_15_104231_add_annual_consumption_to_contract_histories_table.php b/database/migrations/2025_09_15_104231_add_annual_consumption_to_contract_histories_table.php new file mode 100644 index 0000000..83447c7 --- /dev/null +++ b/database/migrations/2025_09_15_104231_add_annual_consumption_to_contract_histories_table.php @@ -0,0 +1,30 @@ +decimal('annual_consumption', 12, 2)->after('validity')->nullable(); + $table->json('contract_snapshot')->nullable()->after('notes'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contract_histories', function (Blueprint $table) { + $table->dropColumn('annual_consumption'); + $table->dropColumn('contract_snapshot'); + }); + } +}; diff --git a/database/migrations/2025_09_15_105109_del_renewal_date_contract_histories_table.php b/database/migrations/2025_09_15_105109_del_renewal_date_contract_histories_table.php new file mode 100644 index 0000000..cf3423f --- /dev/null +++ b/database/migrations/2025_09_15_105109_del_renewal_date_contract_histories_table.php @@ -0,0 +1,28 @@ +dropColumn('renewal_date'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contract_histories', function (Blueprint $table) { + // + }); + } +}; diff --git a/database/migrations/2025_09_19_143217_add_installment_count_to_contracts_table.php b/database/migrations/2025_09_19_143217_add_installment_count_to_contracts_table.php new file mode 100644 index 0000000..e63cb33 --- /dev/null +++ b/database/migrations/2025_09_19_143217_add_installment_count_to_contracts_table.php @@ -0,0 +1,21 @@ +tinyInteger('installment_count')->unsigned()->default(1)->after('contract_value'); + }); + } + + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->dropColumn('installment_count'); + }); + } +}; diff --git a/database/migrations/2025_09_19_143222_create_contract_installments_table.php b/database/migrations/2025_09_19_143222_create_contract_installments_table.php new file mode 100644 index 0000000..02f6c40 --- /dev/null +++ b/database/migrations/2025_09_19_143222_create_contract_installments_table.php @@ -0,0 +1,28 @@ +id(); + $table->foreignId('contract_id')->constrained('contracts')->onDelete('cascade'); + $table->tinyInteger('installment_number')->unsigned(); + $table->decimal('amount', 10, 2); + $table->date('due_date'); + $table->boolean('paid')->default(false); + $table->timestamp('paid_at')->nullable(); + $table->timestamps(); + + $table->unique(['contract_id', 'installment_number']); + }); + } + + public function down(): void + { + Schema::dropIfExists('contract_installments'); + } +}; diff --git a/database/migrations/2025_11_12_140812_create_personal_access_tokens_table.php b/database/migrations/2025_11_12_140812_create_personal_access_tokens_table.php new file mode 100644 index 0000000..40ff706 --- /dev/null +++ b/database/migrations/2025_11_12_140812_create_personal_access_tokens_table.php @@ -0,0 +1,33 @@ +id(); + $table->morphs('tokenable'); + $table->text('name'); + $table->string('token', 64)->unique(); + $table->text('abilities')->nullable(); + $table->timestamp('last_used_at')->nullable(); + $table->timestamp('expires_at')->nullable()->index(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('personal_access_tokens'); + } +}; diff --git a/database/migrations/2026_01_12_174505_add_locality_to_clients_table.php b/database/migrations/2026_01_12_174505_add_locality_to_clients_table.php new file mode 100644 index 0000000..394213a --- /dev/null +++ b/database/migrations/2026_01_12_174505_add_locality_to_clients_table.php @@ -0,0 +1,28 @@ +string('locality')->nullable()->after('address'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('clients', function (Blueprint $table) { + $table->dropColumn('locality'); + }); + } +}; diff --git a/database/migrations/2026_09_15_000000_add_previous_supplier_id_to_contract_histories_table.php b/database/migrations/2026_09_15_000000_add_previous_supplier_id_to_contract_histories_table.php new file mode 100644 index 0000000..2b216a6 --- /dev/null +++ b/database/migrations/2026_09_15_000000_add_previous_supplier_id_to_contract_histories_table.php @@ -0,0 +1,33 @@ +foreignId('previous_supplier_id') + ->nullable() + ->after('contract_id') + ->constrained('suppliers') + ->nullOnDelete(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contract_histories', function (Blueprint $table) { + $table->dropForeign(['previous_supplier_id']); + $table->dropColumn('previous_supplier_id'); + }); + } +}; diff --git a/database/migrations/2026_09_22_000000_add_chargeback_fields_to_contracts_table.php b/database/migrations/2026_09_22_000000_add_chargeback_fields_to_contracts_table.php new file mode 100644 index 0000000..3c5b2be --- /dev/null +++ b/database/migrations/2026_09_22_000000_add_chargeback_fields_to_contracts_table.php @@ -0,0 +1,24 @@ +boolean('chargeback')->default(false)->after('paid'); + $table->decimal('chargeback_value', 10, 2)->nullable()->after('chargeback'); + $table->date('chargeback_date')->nullable()->after('chargeback_value'); + }); + } + + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->dropColumn(['chargeback', 'chargeback_value', 'chargeback_date']); + }); + } +}; diff --git a/database/migrations/2026_09_24_000001_add_contract_end_date_to_contracts_table.php b/database/migrations/2026_09_24_000001_add_contract_end_date_to_contracts_table.php new file mode 100644 index 0000000..a4998a9 --- /dev/null +++ b/database/migrations/2026_09_24_000001_add_contract_end_date_to_contracts_table.php @@ -0,0 +1,22 @@ +date('contract_end_date')->nullable()->after('validity'); + }); + } + + public function down(): void + { + Schema::table('contracts', function (Blueprint $table) { + $table->dropColumn('contract_end_date'); + }); + } +}; diff --git a/database/migrations/2026_09_25_000000_add_installment_counts_to_contract_histories_table.php b/database/migrations/2026_09_25_000000_add_installment_counts_to_contract_histories_table.php new file mode 100644 index 0000000..9032031 --- /dev/null +++ b/database/migrations/2026_09_25_000000_add_installment_counts_to_contract_histories_table.php @@ -0,0 +1,23 @@ +unsignedInteger('total_installments')->nullable()->after('profit_value'); + $table->unsignedInteger('paid_installments')->nullable()->after('total_installments'); + }); + } + + public function down(): void + { + Schema::table('contract_histories', function (Blueprint $table) { + $table->dropColumn(['total_installments', 'paid_installments']); + }); + } +}; diff --git a/database/migrations/2026_09_25_000001_reorder_installment_counts_on_contract_histories_table.php b/database/migrations/2026_09_25_000001_reorder_installment_counts_on_contract_histories_table.php new file mode 100644 index 0000000..1f1bc20 --- /dev/null +++ b/database/migrations/2026_09_25_000001_reorder_installment_counts_on_contract_histories_table.php @@ -0,0 +1,36 @@ +unsignedInteger('total_installments') + ->nullable() + ->after('profit_value') + ->change(); + $table->unsignedInteger('paid_installments') + ->nullable() + ->after('total_installments') + ->change(); + }); + } + + public function down(): void + { + Schema::table('contract_histories', function (Blueprint $table) { + $table->unsignedInteger('paid_installments') + ->nullable() + ->after('total_installments') + ->change(); + $table->unsignedInteger('total_installments') + ->nullable() + ->after('profit_value') + ->change(); + }); + } +}; diff --git a/database/migrations/2026_09_25_000002_add_contract_details_to_contract_histories_table.php b/database/migrations/2026_09_25_000002_add_contract_details_to_contract_histories_table.php new file mode 100644 index 0000000..b7d4117 --- /dev/null +++ b/database/migrations/2026_09_25_000002_add_contract_details_to_contract_histories_table.php @@ -0,0 +1,38 @@ +foreignId('current_supplier_id')->nullable()->after('previous_supplier_id'); + $table->foreignId('seller_id')->nullable()->after('annual_consumption'); + $table->foreignId('contract_type_id')->nullable()->after('seller_id'); + $table->date('contract_date')->nullable()->after('contract_type_id'); + $table->date('activation_date')->nullable()->after('contract_date'); + $table->date('renewal_date')->nullable()->after('activation_date'); + $table->string('renewal_type')->nullable()->after('renewal_date'); + $table->decimal('go_ki', 10, 2)->nullable()->after('renewal_type'); + }); + } + + public function down(): void + { + Schema::table('contract_histories', function (Blueprint $table) { + $table->dropColumn([ + 'current_supplier_id', + 'seller_id', + 'contract_type_id', + 'contract_date', + 'activation_date', + 'renewal_date', + 'renewal_type', + 'go_ki', + ]); + }); + } +}; diff --git a/database/migrations/2026_09_28_000000_create_renewal_types_table.php b/database/migrations/2026_09_28_000000_create_renewal_types_table.php new file mode 100644 index 0000000..f534b98 --- /dev/null +++ b/database/migrations/2026_09_28_000000_create_renewal_types_table.php @@ -0,0 +1,23 @@ +id(); + $table->string('value')->unique(); + $table->string('description'); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists('renewal_types'); + } +}; diff --git a/database/migrations/2026_09_30_000000_add_typology_id_to_contract_histories_table.php b/database/migrations/2026_09_30_000000_add_typology_id_to_contract_histories_table.php new file mode 100644 index 0000000..91cb441 --- /dev/null +++ b/database/migrations/2026_09_30_000000_add_typology_id_to_contract_histories_table.php @@ -0,0 +1,26 @@ +foreignId('typology_id') + ->nullable() + ->constrained('typologies') + ->onDelete('set null'); + }); + } + + public function down(): void + { + Schema::table('contract_histories', function (Blueprint $table) { + $table->dropForeign(['typology_id']); + $table->dropColumn('typology_id'); + }); + } +}; diff --git a/database/migrations/2026_10_02_000000_add_chargeback_fields_to_contract_histories_table.php b/database/migrations/2026_10_02_000000_add_chargeback_fields_to_contract_histories_table.php new file mode 100644 index 0000000..b9bcac8 --- /dev/null +++ b/database/migrations/2026_10_02_000000_add_chargeback_fields_to_contract_histories_table.php @@ -0,0 +1,30 @@ +boolean('chargeback')->nullable()->default(false); + $table->decimal('chargeback_value', 10, 2)->nullable(); + $table->date('chargeback_date')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('contract_histories', function (Blueprint $table) { + $table->dropColumn(['chargeback', 'chargeback_value', 'chargeback_date']); + }); + } +}; diff --git a/database/seeders/ClientTypesSeeder.php b/database/seeders/ClientTypesSeeder.php new file mode 100644 index 0000000..ee90e6e --- /dev/null +++ b/database/seeders/ClientTypesSeeder.php @@ -0,0 +1,30 @@ + ['description' => 'Doméstico', 'icon' => 'fas fa-home', 'color' => '#0d6efd'], + 2 => ['description' => 'Empresarial', 'icon' => 'fas fa-building', 'color' => '#ffc107'], + 3 => ['description' => 'Condomínios', 'icon' => 'fas fa-city', 'color' => '#20c997'], + 4 => ['description' => 'Solar', 'icon' => 'fas fa-solar-panel', 'color' => '#fd7e14'], + ]; + + foreach ($types as $id => $data) { + ClientType::updateOrCreate( + ['id' => $id], + $data + ); + } + } +} diff --git a/database/seeders/ClientsTableSeeder.php b/database/seeders/ClientsTableSeeder.php new file mode 100644 index 0000000..84305c0 --- /dev/null +++ b/database/seeders/ClientsTableSeeder.php @@ -0,0 +1,34 @@ +pluck('id')->toArray(); + $sellerIds = DB::table('users')->pluck('id')->toArray(); + + foreach (range(1, 50) as $i) { + Clients::create([ + 'client_type_id' => $faker->randomElement($clientTypeIds), + 'name' => $faker->name, + 'tax_number' => $faker->numerify('#########'), + 'address' => $faker->address, + 'phone' => $faker->phoneNumber, + 'email' => $faker->unique()->safeEmail, + 'seller_id' => $faker->randomElement($sellerIds), + 'status' => $faker->randomElement(['A', 'I']), + 'notes' => $faker->optional()->sentence, + 'contact_info' => $faker->optional()->paragraph + ]); + } + } +} diff --git a/database/seeders/ContractStatusSeeder.php b/database/seeders/ContractStatusSeeder.php new file mode 100644 index 0000000..3197bf7 --- /dev/null +++ b/database/seeders/ContractStatusSeeder.php @@ -0,0 +1,41 @@ + 'OK'], + ['description' => 'Ativo', 'color' => '#28a745'] + ); + + ContractStatus::firstOrCreate( + ['code' => 'TD'], + ['description' => 'Rescindido', 'color' => '#ffc107'] + ); + + ContractStatus::firstOrCreate( + ['code' => 'WL'], + ['description' => 'Para Ativação', 'color' => '#17a2b8'] + ); + + ContractStatus::firstOrCreate( + ['code' => 'PD'], + ['description' => 'Pendente de documentação', 'color' => '#6c757d'] + ); + + ContractStatus::firstOrCreate( + ['code' => 'CL'], + ['description' => 'Cancelado', 'color' => '#dc3545'] + ); + } +} diff --git a/database/seeders/ContractTypesSeeder.php b/database/seeders/ContractTypesSeeder.php new file mode 100644 index 0000000..84a0b9b --- /dev/null +++ b/database/seeders/ContractTypesSeeder.php @@ -0,0 +1,24 @@ + $type], + ['status' => 'A'] + ); + } + } +} diff --git a/database/seeders/ContractsTableSeeder.php b/database/seeders/ContractsTableSeeder.php new file mode 100644 index 0000000..99400fb --- /dev/null +++ b/database/seeders/ContractsTableSeeder.php @@ -0,0 +1,58 @@ +pluck('id')->toArray(); + $sellerIds = DB::table('users')->pluck('id')->toArray(); + $contractTypeIds = DB::table('contract_types')->pluck('id')->toArray(); + $statusIds = DB::table('contract_status')->pluck('id')->toArray(); + $powerTierIds = DB::table('power_tiers')->pluck('id')->toArray(); + $cuiTierIds = DB::table('cui_tiers')->pluck('id')->toArray(); + $paymentMethodIds = DB::table('payment_methods')->pluck('id')->toArray(); + $supplierIds = DB::table('suppliers')->pluck('id')->toArray(); + $typologyIds = DB::table('typologies')->pluck('id')->toArray(); + + foreach (range(1, 50) as $i) { + $supplyType = $faker->randomElement(['cpe', 'cui']); + + Contract::create([ + 'client_id' => $faker->randomElement($clientIds), + 'contract_value' => $faker->randomFloat(2, 500, 5000), + 'commission_value' => $faker->randomFloat(2, 50, 500), + 'profit_value' => $faker->randomFloat(2, 10, 450), + 'seller_id' => $faker->randomElement($sellerIds), + 'supply_type' => $supplyType, + 'supply_address' => $faker->address, + 'annual_consumption' => $supplyType === 'cpe' ? $faker->numberBetween(1000, 20000) : null, + 'code' => strtoupper($faker->bothify('CPE#####??')), + 'contract_type_id' => $faker->randomElement($contractTypeIds), + 'validity' => $faker->dateTimeBetween('+1 year', '+3 years')->format('Y-m-d'), + 'contract_date' => $faker->dateTimeBetween('-1 years', 'now')->format('Y-m-d'), + 'activation_date' => $faker->dateTimeBetween('now', '+30 days')->format('Y-m-d'), + 'status_id' => $faker->randomElement($statusIds), + 'commission_rate' => $faker->randomFloat(2, 0, 10), + 'go_ki' => $faker->randomFloat(2, 0, 10), + 'notes' => $faker->optional()->sentence, + 'power_tier_id' => $supplyType === 'cpe' ? $faker->randomElement($powerTierIds) : null, + 'cui_tier_id' => $supplyType === 'cui' ? $faker->randomElement($cuiTierIds) : null, + 'payment_method_id' => $faker->randomElement($paymentMethodIds), + 'delivery_method' => $faker->randomElement(['correio', 'email']), + 'delivery_email' => $faker->safeEmail, + 'previous_supplier_id' => $faker->randomElement($supplierIds), + 'new_supplier_id' => $faker->randomElement($supplierIds), + 'typology_id' => $faker->randomElement($typologyIds), + ]); + } + } +} diff --git a/database/seeders/CuiTiersSeeder.php b/database/seeders/CuiTiersSeeder.php new file mode 100644 index 0000000..8a926b5 --- /dev/null +++ b/database/seeders/CuiTiersSeeder.php @@ -0,0 +1,25 @@ +insert([ + ['name' => 'Escalão 1', 'status' => 'A', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Escalão 2', 'status' => 'A', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Escalão 3', 'status' => 'A', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Escalão 4', 'status' => 'A', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Longas Utilizações', 'status' => 'A', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Curtas Utilizações', 'status' => 'A', 'created_at' => now(), 'updated_at' => now()], + ['name' => 'Mensal', 'status' => 'A', 'created_at' => now(), 'updated_at' => now()], + ]); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php new file mode 100644 index 0000000..a72fddd --- /dev/null +++ b/database/seeders/DatabaseSeeder.php @@ -0,0 +1,34 @@ +call([ + ClientTypesSeeder::class, + PermissionSeeder::class, + UserSeeder::class, + PaymentMethodsSeeder::class, + ReceiveInvoiceTypesSeeder::class, + RenewalTypesSeeder::class, + ContractTypesSeeder::class, + ContractStatusSeeder::class, + PowerTiersTableSeeder::class, + TypologySeeder::class, + SuppliersSeeder::class, + CuiTiersSeeder::class, + ClientsTableSeeder::class, + ContractsTableSeeder::class, + ]); + + } +} diff --git a/database/seeders/LeadStatusSeeder.php b/database/seeders/LeadStatusSeeder.php new file mode 100644 index 0000000..8f54bc6 --- /dev/null +++ b/database/seeders/LeadStatusSeeder.php @@ -0,0 +1,25 @@ +updateOrInsert( + ['name' => $status], + ['name' => $status] + ); + } + } +} diff --git a/database/seeders/PaymentMethodsSeeder.php b/database/seeders/PaymentMethodsSeeder.php new file mode 100644 index 0000000..c73091f --- /dev/null +++ b/database/seeders/PaymentMethodsSeeder.php @@ -0,0 +1,39 @@ +insert([ + [ + 'name' => 'Transferência Bancária', + 'icon' => 'fas fa-university', + 'status' => 'A', + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'name' => 'MB', + 'icon' => 'fab fa-app-store-ios', + 'status' => 'A', + 'created_at' => now(), + 'updated_at' => now(), + ], + [ + 'name' => 'Outro', + 'icon' => 'fas fa-money-bill-wave', + 'status' => 'A', + 'created_at' => now(), + 'updated_at' => now(), + ], + ]); + } +} diff --git a/database/seeders/PermissionSeeder.php b/database/seeders/PermissionSeeder.php new file mode 100644 index 0000000..2650960 --- /dev/null +++ b/database/seeders/PermissionSeeder.php @@ -0,0 +1,69 @@ +forgetCachedPermissions(); + + // ===== PERMISSÕES ===== + $permissions = [ + 'view_contract_summary' => 'Ver resumo financeiro do contrato', + 'manager_permissions' => 'Gerir permissões de utilizadores', + 'manage_resources' => 'Gerir Recursos' + ]; + + $permissionModels = []; + + foreach ($permissions as $name => $description) { + $permissionModels[$name] = Permission::updateOrCreate( + ['name' => $name], + ['description' => $description] + ); + } + + // ===== ROLES ===== + $roles = [ + 'admin' => 'Administrador do sistema (invisível)', + 'administracao' => 'Administração', + 'financeira' => 'Financeira', + 'vendedor' => 'Vendedor', + ]; + + $roleModels = []; + + foreach ($roles as $name => $description) { + $roleModels[$name] = Role::updateOrCreate( + ['name' => $name], + ['description' => $description] + ); + } + + // ===== ATRIBUIR PERMISSÕES AOS ROLES ===== + + // Administração + $roleModels['administracao']->syncPermissions([ + $permissionModels['view_contract_summary'], + $permissionModels['manager_permissions'], + $permissionModels['manage_resources'] + ]); + + // Financeira + $roleModels['financeira']->syncPermissions([ + $permissionModels['view_contract_summary'], + ]); + + // Super Admin (acesso total) + $roleModels['admin']->syncPermissions(Permission::all()); + + // Vendedor (sem permissões por enquanto, ajustável depois) + $roleModels['vendedor']->syncPermissions([]); + } +} diff --git a/database/seeders/PowerTiersTableSeeder.php b/database/seeders/PowerTiersTableSeeder.php new file mode 100644 index 0000000..cd5e4ff --- /dev/null +++ b/database/seeders/PowerTiersTableSeeder.php @@ -0,0 +1,31 @@ + 'Simples', 'status' => 'A'], + ['name' => 'Tri-horária','status' => 'A'], + ['name' => 'Bi-horária', 'status' => 'A'], + ['name' => 'BTE', 'status' => 'A'], + ['name' => 'MT', 'status' => 'A'], + ['name' => 'AT', 'status' => 'A'], + ]; + + foreach ($tiers as $tier) { + DB::table('power_tiers')->updateOrInsert( + ['name' => $tier['name']], + ['status' => $tier['status'], 'updated_at' => now(), 'created_at' => now()] + ); + } + } +} diff --git a/database/seeders/ReceiveInvoiceTypesSeeder.php b/database/seeders/ReceiveInvoiceTypesSeeder.php new file mode 100644 index 0000000..f2a1efa --- /dev/null +++ b/database/seeders/ReceiveInvoiceTypesSeeder.php @@ -0,0 +1,19 @@ + 'Email']); + ReceiveInvoiceTypes::firstOrCreate(['description' => 'Correio']); + } +} diff --git a/database/seeders/RenewalTypesSeeder.php b/database/seeders/RenewalTypesSeeder.php new file mode 100644 index 0000000..07634e6 --- /dev/null +++ b/database/seeders/RenewalTypesSeeder.php @@ -0,0 +1,21 @@ + 'tacita'], + ['description' => 'Tácita'] + ); + RenewalType::firstOrCreate( + ['value' => 'negociada'], + ['description' => 'Negociada'] + ); + } +} diff --git a/database/seeders/ResetPermissionsSeeder.php b/database/seeders/ResetPermissionsSeeder.php new file mode 100644 index 0000000..2d4813f --- /dev/null +++ b/database/seeders/ResetPermissionsSeeder.php @@ -0,0 +1,26 @@ +truncate(); + DB::table('model_has_permissions')->truncate(); + DB::table('role_has_permissions')->truncate(); + Role::truncate(); + Permission::truncate(); + } +} diff --git a/database/seeders/SuppliersSeeder.php b/database/seeders/SuppliersSeeder.php new file mode 100644 index 0000000..a0e08df --- /dev/null +++ b/database/seeders/SuppliersSeeder.php @@ -0,0 +1,42 @@ + 'Axpo', 'color' => '#FF0000'], + ['name' => 'PORTULOGOS', 'color' => '#005489'], + ['name' => 'NABALIA', 'color' => '#00FFF0'], + ['name' => 'ZUG POWER', 'color' => '#69B0E4'], + ['name' => 'ALFA ENERGIA', 'color' => '#0077CC'], + ['name' => 'YES ENERGY', 'color' => '#D3EDA1'], + ['name' => 'ACCIONA', 'color' => '#FFFFFF'], + ['name' => 'AUDAX', 'color' => '#FFFF00'], + ['name' => 'IBERDROLA', 'color' => '#62852B'], + ['name' => 'ENDESA', 'color' => '#A4C4E7'], + ['name' => 'EDP - COMERCIAL', 'color' => '#00D9FF'], + ['name' => 'REPSOL', 'color' => '#F7B801'], + ['name' => 'PLENITUDE', 'color' => '#C8E48E'], + ['name' => 'MEO ENERGIA', 'color' => '#A0E556'], + ]; + + foreach ($suppliers as $supplier) { + DB::table('suppliers')->insert([ + 'name' => $supplier['name'], + 'color' => $supplier['color'], + 'status' => 'A', + 'created_at' => now(), + 'updated_at' => now(), + ]); + } + } +} diff --git a/database/seeders/TypologySeeder.php b/database/seeders/TypologySeeder.php new file mode 100644 index 0000000..7080832 --- /dev/null +++ b/database/seeders/TypologySeeder.php @@ -0,0 +1,31 @@ + $desc]); + } + } +} diff --git a/database/seeders/UserSeeder.php b/database/seeders/UserSeeder.php new file mode 100644 index 0000000..b8b629c --- /dev/null +++ b/database/seeders/UserSeeder.php @@ -0,0 +1,79 @@ + 'luismedon@gmail.com'], + [ + 'name' => 'Admin', + 'password' => Hash::make('123'), + 'can_login' => true, + ] + ); + + $userJorge = User::firstOrCreate( + ['email' => '77jpef@gmail.com'], + [ + 'name' => 'Jorge Ferreira', + 'password' => Hash::make('rtIcp6F'), + 'can_login' => true, + ] + ); + + $userAdmin->syncRoles(Role::all()); + + $rolesWithoutAdmin = Role::where('id', '!=', 1)->get(); + $userJorge->syncRoles($rolesWithoutAdmin); + + // Buscar roles existentes + $roleVendedor = Role::where('name', 'vendedor')->first(); + $roleComercial = Role::where('name', 'Financeira')->first(); + + // Novos utilizadores + $newUsers = [ + 'JOSE', + 'ANDRÉ', + 'J.FERNANDES', + 'RUI RODRIGUES', + 'SILVIA', + ]; + + foreach ($newUsers as $name) { + $email = strtolower(str_replace(' ', '', $name)) . '@example.com'; + + $user = User::firstOrCreate( + ['name' => $name], + [ + 'email' => $email, + 'password' => Hash::make(Str::random(16)), + 'can_login' => false, + ] + ); + + if ($name === 'SILVIA') { + if ($roleComercial) { + $user->syncRoles([$roleComercial]); + } + } else { + if ($roleVendedor) { + $user->syncRoles([$roleVendedor]); + } + } + } + } +} diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 0000000..329749f --- /dev/null +++ b/docs/API.md @@ -0,0 +1,131 @@ +# API da aplicacao + +## Arquitetura + +Web e API usam os mesmos servicos em `app/Services`, com as mesmas regras de +negocio e acesso aos dados. A web mantem as vistas Blade e os redirecionamentos. +A API devolve JSON, exceto a exportacao Excel e o diagnostico HTML `phpinfo`. +Os controllers nao fazem chamadas HTTP a propria aplicacao. `APP_API_URL` ou +`app.api_url` deixam de ser necessarios para o login e a sessao web. + +O bootstrap Laravel regista `routes/api.php` com o prefixo `/api`. + +## Autenticacao + +`POST /api/login` recebe `email` e `password` e devolve `token` e `user`. +Os tokens Sanctum expiram apos 20 minutos. Use estes cabecalhos nos pedidos: + +```http +Authorization: Bearer +Accept: application/json +Content-Type: application/json +``` + +`POST /api/refresh` prolonga um token ainda valido por 20 minutos. +`POST /api/logout` revoga o token atual. A recuperacao de senha revoga todos +os tokens do utilizador. Contas com `can_login=false` nao podem autenticar-se +nem usar tokens existentes. O login web usa o mesmo servico, regenera a sessao +e valida/renova o token localmente em cada pedido autenticado. + +Login e verificacao de PIN permitem 10 tentativas por minuto; pedidos publicos +de recuperacao de senha e envio de email de teste permitem 5 por minuto. + +## Endpoints + +Todos os caminhos abaixo sao relativos a `/api`. +`CRUD /recurso` significa `GET /recurso`, `POST /recurso`, +`GET /recurso/{id}`, `PUT` ou `PATCH /recurso/{id}` e `DELETE /recurso/{id}`. +As rotas `/resources` aceitam `PUT`, nao `PATCH`. + +| Operacao | Endpoint | Acesso | +| --- | --- | --- | +| Login | `POST /login` | Publico | +| Pedir recuperacao de senha | `POST /password/email` | Publico | +| Redefinir senha | `POST /password/reset` | Publico | +| Sair / renovar / verificar token | `POST /logout`, `POST /refresh`, `GET /check-token` | Autenticado | +| Utilizador atual e permissoes | `GET /me` | Autenticado | +| Dashboard | `GET /dashboard` | Autenticado | +| Analises | `GET /analytics` | Role `administracao` | +| Guardar / verificar PIN | `POST /user/pin`, `POST /user/check-pin` | Autenticado | +| Clientes | CRUD `/clients` | Autenticado | +| Opcoes de clientes | `GET /clients/options?type={client_type_id}` | Autenticado | +| Detalhe e contratos de cliente | `GET /clients/{id}/detail` | Autenticado | +| Pesquisa por nome | `GET /clients/search/name?term=...` | Autenticado | +| Pesquisa por ID | `POST /clients/search/id`, corpo `{"id":1}` | Autenticado | +| Leads | CRUD `/leads` | Autenticado | +| Estados de leads | `GET /leads/options` | Autenticado | +| Converter lead | `PUT /leads/{id}/convert` | Autenticado | +| Contratos | CRUD `/contracts` | Autenticado | +| Opcoes de contratos | `GET /contracts/options?client_id=...` | Autenticado | +| Dados de edicao | `GET /contracts/{id}/edit` | Autenticado | +| Opcoes / executar renovacao | `GET /contracts/{id}/renew`, `POST /contracts/{id}/renew` | Autenticado | +| Historico | `GET /contracts/{id}/history` | Autenticado | +| Ler / editar / eliminar historico | `GET`, `PUT`, `DELETE /contracts/{id}/history/{historyId}` | Autenticado | +| Eliminar contratos em lote | `DELETE /contracts/bulk`, corpo `{"ids":[1,2]}` | Autenticado | +| Exportar contratos | `GET /contracts/export` | Permissao `view_contract_summary` | +| Utilizadores | CRUD `/users` | Role `admin` | +| Roles para criar utilizador | `GET /users/options` | Role `admin` | +| Enviar recuperacao de senha a utilizador | `POST /users/{user}/password-reset` | Role `admin` | +| Roles e permissoes | `GET /admin/access/roles-permissions` | Role `admin` | +| Atualizar permissoes de role | `POST /admin/access/roles/{role}/permissions` | Role `admin` | +| Utilizadores e roles | `GET /admin/access/users` | Role `admin` | +| Atualizar roles de utilizador | `POST /admin/access/users/{user}/roles` | Role `admin` | +| Recursos auxiliares | CRUD `/resources/{resource}` | Permissao `manage_resources` | +| Informacao do sistema | `GET /admin/info` | Role `admin` | +| Diagnostico PHP (HTML) | `GET /admin/phpinfo` | Role `admin` | +| Executar migrations | `POST /admin/runMigrations` | Role `admin` | +| Email de teste | `POST /admin/testEmail`, corpo `{"email":"destino@example.com"}` | Role `admin` | + +Recursos permitidos: `power_tiers`, `contract_types`, `payment_methods`, +`typologies`, `cui_tiers`, `suppliers`, `contract-statuses`. +Roles e permissoes sao enviadas como listas de nomes nos campos `roles` e +`permissions`. Os campos de negocio e datas seguem os FormRequests existentes, +incluindo o formato `d/m/Y` nos formularios de contratos. As operacoes de +senha recebem `email`; a redefinicao tambem recebe `token`, `password` e +`password_confirmation`. + +## Respostas e compatibilidade + +Criacao: `201`; operacao concluida: `200`; nao autenticado: `401`; +acesso negado: `403`; registo inexistente: `404`; validacao: `422`; +limite de tentativas: `429`. Erros de validacao incluem `message` e `errors`. +Os erros API sao JSON mesmo sem o cabecalho `Accept`. + +Clientes mantem a listagem antiga `{"clients":[...]}` quando `per_page` nao e +enviado. Com `per_page`, devolvem um paginador em `clients`, com `data`, +`current_page`, `last_page`, `per_page`, `total` e links. Clientes e contratos +limitam `per_page` ao intervalo 1-100. A listagem paginada de clientes filtra +`type=client`, tal como a web; a listagem antiga conserva o comportamento +anterior de devolver os registos ativos. Filtros de nome, NIF, email, tipo e +codigo de contrato sao partilhados. Contratos incluem os totais da pagina atual. + +IDs de clientes passam a ser incluidos nas respostas. Passwords, hashes de PIN +e remember tokens nao sao serializados. Dados financeiros e snapshots de +contratos sao omitidos das respostas de negocio sem `view_contract_summary`. +Atualizacoes sem essa permissao preservam os valores financeiros e parcelas. +Exportacoes exigem essa permissao, tambem na web. + +As antigas operacoes administrativas `GET /admin/runMigrations` e +`GET /admin/testEmail` passam a `POST`, exigem a role `admin`, e o email de +destino passa a ser obrigatorio. Nenhuma migration foi executada durante esta +refatoracao. Estes endpoints devem ser restritos tambem ao nivel de rede em +producao, especialmente `phpinfo` e a execucao de migrations. + +## Verificacao + +Os testes unitarios de regras ficam em `tests/Unit`. Os testes HTTP da API ficam +em `tests/Api`, e os fluxos web destinados ao browser ficam em `tests/Browser`. +Ambos usam uma base SQLite em memoria, com o esquema oficial de permissoes do +Spatie e tabelas minimas; nao usam nem alteram a base de dados da aplicacao. +Os testes Browser verificam a resposta HTTP, vistas, CSRF, redirecionamentos e +sessoes Laravel; nao executam JavaScript num Chromium real. + +```bash +APP_ENV=testing DB_CONNECTION=sqlite DB_DATABASE=:memory: CACHE_STORE=array SESSION_DRIVER=array \ + vendor/bin/phpunit tests/Unit tests/Api tests/Browser +``` + +Cada grupo tambem pode ser executado isoladamente com `vendor/bin/phpunit +--testsuite API` ou `vendor/bin/phpunit --testsuite Browser`. O PHP CLI necessita +da extensao `pdo_sqlite`. Os testes Feature legados que dependem de dados +preexistentes nao estao incluidos no comando acima. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8cec533 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2720 @@ +{ + "name": "volcerto", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@popperjs/core": "^2.11.6", + "@tailwindcss/vite": "^4.0.0", + "axios": "^1.13.5", + "bootstrap": "^5.2.3", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^1.2.0", + "sass": "^1.56.1", + "tailwindcss": "^4.0.0", + "vite": "^6.4.1" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", + "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", + "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", + "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", + "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", + "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", + "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", + "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", + "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", + "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", + "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", + "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", + "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", + "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", + "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", + "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", + "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", + "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", + "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", + "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", + "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", + "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", + "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", + "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", + "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", + "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.11.tgz", + "integrity": "sha512-y1Ko/QaZh6Fv8sSOOPpRztT8nvNKSetvE4CLxsDdyY5kkBS7hKq04D3y3ldelniWe6YqRIzBHTzfAIc1hZ+0FA==", + "dev": true, + "dependencies": { + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "tailwindcss": "4.0.11" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.11.tgz", + "integrity": "sha512-vpR3j69boI64ftpDbbC2NPXhbF7LEkBbQ/Ol1mSU9medtdcmabMiEPlN9FtvE2IkoXZpiDM1utSsdutZSka9Cg==", + "dev": true, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.0.11", + "@tailwindcss/oxide-darwin-arm64": "4.0.11", + "@tailwindcss/oxide-darwin-x64": "4.0.11", + "@tailwindcss/oxide-freebsd-x64": "4.0.11", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.11", + "@tailwindcss/oxide-linux-arm64-gnu": "4.0.11", + "@tailwindcss/oxide-linux-arm64-musl": "4.0.11", + "@tailwindcss/oxide-linux-x64-gnu": "4.0.11", + "@tailwindcss/oxide-linux-x64-musl": "4.0.11", + "@tailwindcss/oxide-win32-arm64-msvc": "4.0.11", + "@tailwindcss/oxide-win32-x64-msvc": "4.0.11" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.11.tgz", + "integrity": "sha512-6gGLTOwR3WNh63pUnY6znRY7XiLRVmvyAkQRdyRxPquNIZ7lTeqWlZcxt5Gtlh1VzZXkQ8OWyYte8ZBnulhvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.11.tgz", + "integrity": "sha512-CM5SF53zzqYqQQGlP6N94zTliUi2FxW4itr223xb2PWgbwf48JTE2P6DNrA5DHOxacIliiCYiBzmKGwKdGMu8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.11.tgz", + "integrity": "sha512-YB1LJC04O3UugV0egl3jnpXWyJIlcV7oVb0cplcqG0aP6nPYH0SqmD+ysbOrl6Ti1qAVuOHnfJvnAup2hbXMgw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.11.tgz", + "integrity": "sha512-tK63Mi/kbU5GVZFkUH+zLL/G0yiRGY15MU2xFUa3H2q2px4IuWJTWRmv6iPOcZm3kYpsh+0C+dSoz0lDEknENg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.11.tgz", + "integrity": "sha512-vMJPxCQtdhqGGw1MOQnPJ6hyh5BR5EQhRXJk9Ji/1oo2P1chgEaPuGYGZGdZMy9bnFaufnjae0liqk6E3SNTFw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.11.tgz", + "integrity": "sha512-5qac6Wps9vCwkQcgyw+VlJvXkdGoOnJp8eK3TaKpZ3fTQozGgvy/AyimV8I7I4ZjU6mTjuQbZe1CPP/cuG+Ldw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.11.tgz", + "integrity": "sha512-hR/Lw7QgODodKLpf37+ohJJZjYEJLg6c+h3nIXJ6eLYDbCZjJ0Z0+jHP0rHXyGab7JL+QlIksNuNbJjj+2qpsw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.11.tgz", + "integrity": "sha512-4aCBYzU2SyFUw/dSP3SYAaeo3I7+c6to9acqXAl/Y5XnAO3q6SBrjw2sU2RG7f5Yi+jxevFh4BcOS5ofhhoTIA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.11.tgz", + "integrity": "sha512-Y5j5Yp3lRcgyzOF+CY+u54aUUtvZ6OwiVPeILE3wqbsDA6X3UiUpVr8tW2eREERld0gELfXG8TyNAtDsBIOHwA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.11.tgz", + "integrity": "sha512-ofgW1IugQDJR+fGJUZMniwTzrwHvaw6wpoOE1mIXBFP2wWoDjvNTXUJyMDxF2N6UypXGYCJMDdEohB1CyWf9cg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.11.tgz", + "integrity": "sha512-jUDa1xZNVPuarkEbwxh8aFQ3oagDQRYXcPmfsiDZ2IAxcYnE8YPNbA2HvFxJowppnnu/v/xdWvneN24VBr1Zpw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.11.tgz", + "integrity": "sha512-rjzupwJLR/2d06SQ7JWPyEdj95qW4tGcP/i6vHkbtHnDR0XkohaG7ab8lKHnxJsr+/4RDHwKDGRPKB3VWgx2vg==", + "dev": true, + "dependencies": { + "@tailwindcss/node": "4.0.11", + "@tailwindcss/oxide": "4.0.11", + "lightningcss": "^1.29.1", + "tailwindcss": "4.0.11" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", + "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/bootstrap": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "optional": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concurrently": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.2.tgz", + "integrity": "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", + "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "optional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/immutable": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "optional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "dev": true, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/laravel-vite-plugin": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.2.0.tgz", + "integrity": "sha512-R0pJ+IcTVeqEMoKz/B2Ij57QVq3sFTABiFmb06gAwFdivbOgsUtuhX6N2MGLEArajrS3U5JbberzwOe7uXHMHQ==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "vite-plugin-full-reload": "^1.1.0" + }, + "bin": { + "clean-orphaned-assets": "bin/clean.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0" + } + }, + "node_modules/lightningcss": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz", + "integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.29.2", + "lightningcss-darwin-x64": "1.29.2", + "lightningcss-freebsd-x64": "1.29.2", + "lightningcss-linux-arm-gnueabihf": "1.29.2", + "lightningcss-linux-arm64-gnu": "1.29.2", + "lightningcss-linux-arm64-musl": "1.29.2", + "lightningcss-linux-x64-gnu": "1.29.2", + "lightningcss-linux-x64-musl": "1.29.2", + "lightningcss-win32-arm64-msvc": "1.29.2", + "lightningcss-win32-x64-msvc": "1.29.2" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz", + "integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz", + "integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz", + "integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz", + "integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz", + "integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz", + "integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz", + "integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz", + "integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz", + "integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz", + "integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "optional": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "optional": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/sass": { + "version": "1.85.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.85.1.tgz", + "integrity": "sha512-Uk8WpxM5v+0cMR0XjX9KfRIacmSG86RH4DCCZjLU2rFh5tyutt9siAXJ7G+YfxQ99Q6wrRMbMlVl6KqUms71ag==", + "dev": true, + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tailwindcss": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.11.tgz", + "integrity": "sha512-GZ6+tNwieqvpFLZfx2tkZpfOMAK7iumbOJOLmd6v8AcYuHbjUb+cmDRu6l+rFkIqarh5FfLbCSRJhegcVdoPng==", + "dev": true + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "optional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-full-reload": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz", + "integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "picomatch": "^2.3.1" + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..93ecc61 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite" + }, + "devDependencies": { + "@popperjs/core": "^2.11.6", + "@tailwindcss/vite": "^4.0.0", + "axios": "^1.13.5", + "bootstrap": "^5.2.3", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^1.2.0", + "sass": "^1.56.1", + "tailwindcss": "^4.0.0", + "vite": "^6.4.1" + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..f2fa645 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,21 @@ + + + + + ./tests/Unit + + + ./tests/Api + + + ./tests/Browser + + + ./tests/Feature + + + diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..b574a59 --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,25 @@ + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Handle X-XSRF-Token Header + RewriteCond %{HTTP:x-xsrf-token} . + RewriteRule .* - [E=HTTP_X_XSRF_TOKEN:%{HTTP:X-XSRF-Token}] + + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Send Requests To Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + diff --git a/public/assets/demo/chart-area-demo.js b/public/assets/demo/chart-area-demo.js new file mode 100644 index 0000000..16a9844 --- /dev/null +++ b/public/assets/demo/chart-area-demo.js @@ -0,0 +1,146 @@ +// Set new default font family and font color to mimic Bootstrap's default styling +(Chart.defaults.global.defaultFontFamily = "Metropolis"), +'-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'; +Chart.defaults.global.defaultFontColor = "#858796"; + +function number_format(number, decimals, dec_point, thousands_sep) { + // * example: number_format(1234.56, 2, ',', ' '); + // * return: '1 234,56' + number = (number + "").replace(",", "").replace(" ", ""); + var n = !isFinite(+number) ? 0 : +number, + prec = !isFinite(+decimals) ? 0 : Math.abs(decimals), + sep = typeof thousands_sep === "undefined" ? "," : thousands_sep, + dec = typeof dec_point === "undefined" ? "." : dec_point, + s = "", + toFixedFix = function(n, prec) { + var k = Math.pow(10, prec); + return "" + Math.round(n * k) / k; + }; + // Fix for IE parseFloat(0.55).toFixed(0) = 0; + s = (prec ? toFixedFix(n, prec) : "" + Math.round(n)).split("."); + if (s[0].length > 3) { + s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep); + } + if ((s[1] || "").length < prec) { + s[1] = s[1] || ""; + s[1] += new Array(prec - s[1].length + 1).join("0"); + } + return s.join(dec); +} + +// Area Chart Example +var ctx = document.getElementById("myAreaChart"); +var myLineChart = new Chart(ctx, { + type: "line", + data: { + labels: [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + ], + datasets: [{ + label: "Earnings", + lineTension: 0.3, + backgroundColor: "rgba(0, 97, 242, 0.05)", + borderColor: "rgba(0, 97, 242, 1)", + pointRadius: 3, + pointBackgroundColor: "rgba(0, 97, 242, 1)", + pointBorderColor: "rgba(0, 97, 242, 1)", + pointHoverRadius: 3, + pointHoverBackgroundColor: "rgba(0, 97, 242, 1)", + pointHoverBorderColor: "rgba(0, 97, 242, 1)", + pointHitRadius: 10, + pointBorderWidth: 2, + data: [ + 0, + 10000, + 5000, + 15000, + 10000, + 20000, + 15000, + 25000, + 20000, + 30000, + 25000, + 40000 + ] + }] + }, + options: { + maintainAspectRatio: false, + layout: { + padding: { + left: 10, + right: 25, + top: 25, + bottom: 0 + } + }, + scales: { + xAxes: [{ + time: { + unit: "date" + }, + gridLines: { + display: false, + drawBorder: false + }, + ticks: { + maxTicksLimit: 7 + } + }], + yAxes: [{ + ticks: { + maxTicksLimit: 5, + padding: 10, + // Include a dollar sign in the ticks + callback: function(value, index, values) { + return "$" + number_format(value); + } + }, + gridLines: { + color: "rgb(234, 236, 244)", + zeroLineColor: "rgb(234, 236, 244)", + drawBorder: false, + borderDash: [2], + zeroLineBorderDash: [2] + } + }] + }, + legend: { + display: false + }, + tooltips: { + backgroundColor: "rgb(255,255,255)", + bodyFontColor: "#858796", + titleMarginBottom: 10, + titleFontColor: "#6e707e", + titleFontSize: 14, + borderColor: "#dddfeb", + borderWidth: 1, + xPadding: 15, + yPadding: 15, + displayColors: false, + intersect: false, + mode: "index", + caretPadding: 10, + callbacks: { + label: function(tooltipItem, chart) { + var datasetLabel = + chart.datasets[tooltipItem.datasetIndex].label || ""; + return datasetLabel + ": $" + number_format(tooltipItem.yLabel); + } + } + } + } +}); diff --git a/public/assets/demo/chart-bar-demo.js b/public/assets/demo/chart-bar-demo.js new file mode 100644 index 0000000..d7a1f1e --- /dev/null +++ b/public/assets/demo/chart-bar-demo.js @@ -0,0 +1,113 @@ +// Set new default font family and font color to mimic Bootstrap's default styling +(Chart.defaults.global.defaultFontFamily = "Metropolis"), +'-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'; +Chart.defaults.global.defaultFontColor = "#858796"; + +function number_format(number, decimals, dec_point, thousands_sep) { + // * example: number_format(1234.56, 2, ',', ' '); + // * return: '1 234,56' + number = (number + "").replace(",", "").replace(" ", ""); + var n = !isFinite(+number) ? 0 : +number, + prec = !isFinite(+decimals) ? 0 : Math.abs(decimals), + sep = typeof thousands_sep === "undefined" ? "," : thousands_sep, + dec = typeof dec_point === "undefined" ? "." : dec_point, + s = "", + toFixedFix = function(n, prec) { + var k = Math.pow(10, prec); + return "" + Math.round(n * k) / k; + }; + // Fix for IE parseFloat(0.55).toFixed(0) = 0; + s = (prec ? toFixedFix(n, prec) : "" + Math.round(n)).split("."); + if (s[0].length > 3) { + s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep); + } + if ((s[1] || "").length < prec) { + s[1] = s[1] || ""; + s[1] += new Array(prec - s[1].length + 1).join("0"); + } + return s.join(dec); +} + +// Bar Chart Example +var ctx = document.getElementById("myBarChart"); +var myBarChart = new Chart(ctx, { + type: "bar", + data: { + labels: ["January", "February", "March", "April", "May", "June"], + datasets: [{ + label: "Revenue", + backgroundColor: "rgba(0, 97, 242, 1)", + hoverBackgroundColor: "rgba(0, 97, 242, 0.9)", + borderColor: "#4e73df", + data: [4215, 5312, 6251, 7841, 9821, 14984], + maxBarThickness: 25 + }] + }, + options: { + maintainAspectRatio: false, + layout: { + padding: { + left: 10, + right: 25, + top: 25, + bottom: 0 + } + }, + scales: { + xAxes: [{ + time: { + unit: "month" + }, + gridLines: { + display: false, + drawBorder: false + }, + ticks: { + maxTicksLimit: 6 + } + }], + yAxes: [{ + ticks: { + min: 0, + max: 15000, + maxTicksLimit: 5, + padding: 10, + // Include a dollar sign in the ticks + callback: function(value, index, values) { + return "$" + number_format(value); + } + }, + gridLines: { + color: "rgb(234, 236, 244)", + zeroLineColor: "rgb(234, 236, 244)", + drawBorder: false, + borderDash: [2], + zeroLineBorderDash: [2] + } + }] + }, + legend: { + display: false + }, + tooltips: { + titleMarginBottom: 10, + titleFontColor: "#6e707e", + titleFontSize: 14, + backgroundColor: "rgb(255,255,255)", + bodyFontColor: "#858796", + borderColor: "#dddfeb", + borderWidth: 1, + xPadding: 15, + yPadding: 15, + displayColors: false, + caretPadding: 10, + callbacks: { + label: function(tooltipItem, chart) { + var datasetLabel = + chart.datasets[tooltipItem.datasetIndex].label || ""; + return datasetLabel + ": $" + number_format(tooltipItem.yLabel); + } + } + } + } +}); diff --git a/public/assets/demo/chart-pie-demo.js b/public/assets/demo/chart-pie-demo.js new file mode 100644 index 0000000..641ce73 --- /dev/null +++ b/public/assets/demo/chart-pie-demo.js @@ -0,0 +1,44 @@ +// Set new default font family and font color to mimic Bootstrap's default styling +(Chart.defaults.global.defaultFontFamily = "Metropolis"), +'-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'; +Chart.defaults.global.defaultFontColor = "#858796"; + +// Pie Chart Example +var ctx = document.getElementById("myPieChart"); +var myPieChart = new Chart(ctx, { + type: "doughnut", + data: { + labels: ["Direct", "Referral", "Social"], + datasets: [{ + data: [55, 30, 15], + backgroundColor: [ + "rgba(0, 97, 242, 1)", + "rgba(0, 172, 105, 1)", + "rgba(88, 0, 232, 1)" + ], + hoverBackgroundColor: [ + "rgba(0, 97, 242, 0.9)", + "rgba(0, 172, 105, 0.9)", + "rgba(88, 0, 232, 0.9)" + ], + hoverBorderColor: "rgba(234, 236, 244, 1)" + }] + }, + options: { + maintainAspectRatio: false, + tooltips: { + backgroundColor: "rgb(255,255,255)", + bodyFontColor: "#858796", + borderColor: "#dddfeb", + borderWidth: 1, + xPadding: 15, + yPadding: 15, + displayColors: false, + caretPadding: 10 + }, + legend: { + display: false + }, + cutoutPercentage: 80 + } +}); diff --git a/public/assets/fonts/metropolis/Metropolis-Black.otf b/public/assets/fonts/metropolis/Metropolis-Black.otf new file mode 100644 index 0000000..3abd623 Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-Black.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-BlackItalic.otf b/public/assets/fonts/metropolis/Metropolis-BlackItalic.otf new file mode 100644 index 0000000..3d6a9e4 Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-BlackItalic.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-Bold.otf b/public/assets/fonts/metropolis/Metropolis-Bold.otf new file mode 100644 index 0000000..a42b941 Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-Bold.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-BoldItalic.otf b/public/assets/fonts/metropolis/Metropolis-BoldItalic.otf new file mode 100644 index 0000000..f242515 Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-BoldItalic.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-ExtraBold.otf b/public/assets/fonts/metropolis/Metropolis-ExtraBold.otf new file mode 100644 index 0000000..ca0b9ec Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-ExtraBold.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-ExtraBoldItalic.otf b/public/assets/fonts/metropolis/Metropolis-ExtraBoldItalic.otf new file mode 100644 index 0000000..667c708 Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-ExtraBoldItalic.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-ExtraLight.otf b/public/assets/fonts/metropolis/Metropolis-ExtraLight.otf new file mode 100644 index 0000000..b02e041 Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-ExtraLight.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-ExtraLightItalic.otf b/public/assets/fonts/metropolis/Metropolis-ExtraLightItalic.otf new file mode 100644 index 0000000..2740b28 Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-ExtraLightItalic.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-Light.otf b/public/assets/fonts/metropolis/Metropolis-Light.otf new file mode 100644 index 0000000..b8b917c Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-Light.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-LightItalic.otf b/public/assets/fonts/metropolis/Metropolis-LightItalic.otf new file mode 100644 index 0000000..717133c Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-LightItalic.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-Medium.otf b/public/assets/fonts/metropolis/Metropolis-Medium.otf new file mode 100644 index 0000000..239d69d Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-Medium.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-MediumItalic.otf b/public/assets/fonts/metropolis/Metropolis-MediumItalic.otf new file mode 100644 index 0000000..dc30091 Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-MediumItalic.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-Regular.otf b/public/assets/fonts/metropolis/Metropolis-Regular.otf new file mode 100644 index 0000000..737760b Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-Regular.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-RegularItalic.otf b/public/assets/fonts/metropolis/Metropolis-RegularItalic.otf new file mode 100644 index 0000000..14d62bc Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-RegularItalic.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-SemiBold.otf b/public/assets/fonts/metropolis/Metropolis-SemiBold.otf new file mode 100644 index 0000000..f9889d0 Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-SemiBold.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-SemiBoldItalic.otf b/public/assets/fonts/metropolis/Metropolis-SemiBoldItalic.otf new file mode 100644 index 0000000..fdbd016 Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-SemiBoldItalic.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-Thin.otf b/public/assets/fonts/metropolis/Metropolis-Thin.otf new file mode 100644 index 0000000..f969dcc Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-Thin.otf differ diff --git a/public/assets/fonts/metropolis/Metropolis-ThinItalic.otf b/public/assets/fonts/metropolis/Metropolis-ThinItalic.otf new file mode 100644 index 0000000..248bd94 Binary files /dev/null and b/public/assets/fonts/metropolis/Metropolis-ThinItalic.otf differ diff --git a/public/assets/fonts/metropolis/SIL Open Font License.txt b/public/assets/fonts/metropolis/SIL Open Font License.txt new file mode 100644 index 0000000..2608640 --- /dev/null +++ b/public/assets/fonts/metropolis/SIL Open Font License.txt @@ -0,0 +1,43 @@ +Copyright (c) 2015, Chris Simpson, with Reserved Font Name: "Metropolis". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the copyright statement(s). + +"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. + +5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/public/assets/img/backgrounds/bg-angles.svg b/public/assets/img/backgrounds/bg-angles.svg new file mode 100644 index 0000000..4640557 --- /dev/null +++ b/public/assets/img/backgrounds/bg-angles.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/public/assets/img/backgrounds/bg-pattern-shapes.png b/public/assets/img/backgrounds/bg-pattern-shapes.png new file mode 100644 index 0000000..3cc6062 Binary files /dev/null and b/public/assets/img/backgrounds/bg-pattern-shapes.png differ diff --git a/public/assets/img/backgrounds/bg-waves.svg b/public/assets/img/backgrounds/bg-waves.svg new file mode 100644 index 0000000..4cc82ea --- /dev/null +++ b/public/assets/img/backgrounds/bg-waves.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/public/assets/img/demo/cards/card-img-bottom.jpg b/public/assets/img/demo/cards/card-img-bottom.jpg new file mode 100644 index 0000000..1304e02 Binary files /dev/null and b/public/assets/img/demo/cards/card-img-bottom.jpg differ diff --git a/public/assets/img/demo/cards/card-img-left.jpg b/public/assets/img/demo/cards/card-img-left.jpg new file mode 100644 index 0000000..db6961f Binary files /dev/null and b/public/assets/img/demo/cards/card-img-left.jpg differ diff --git a/public/assets/img/demo/cards/card-img-overlay.jpg b/public/assets/img/demo/cards/card-img-overlay.jpg new file mode 100644 index 0000000..d95579a Binary files /dev/null and b/public/assets/img/demo/cards/card-img-overlay.jpg differ diff --git a/public/assets/img/demo/cards/card-img-right.jpg b/public/assets/img/demo/cards/card-img-right.jpg new file mode 100644 index 0000000..9d1167a Binary files /dev/null and b/public/assets/img/demo/cards/card-img-right.jpg differ diff --git a/public/assets/img/demo/cards/card-img-top.jpg b/public/assets/img/demo/cards/card-img-top.jpg new file mode 100644 index 0000000..7ef4271 Binary files /dev/null and b/public/assets/img/demo/cards/card-img-top.jpg differ diff --git a/public/assets/img/demo/demo-logo.svg b/public/assets/img/demo/demo-logo.svg new file mode 100644 index 0000000..84415fd --- /dev/null +++ b/public/assets/img/demo/demo-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/img/demo/demo-ocean-lg.jpg b/public/assets/img/demo/demo-ocean-lg.jpg new file mode 100644 index 0000000..c4f967b Binary files /dev/null and b/public/assets/img/demo/demo-ocean-lg.jpg differ diff --git a/public/assets/img/demo/demo-ocean-sm.jpg b/public/assets/img/demo/demo-ocean-sm.jpg new file mode 100644 index 0000000..929e310 Binary files /dev/null and b/public/assets/img/demo/demo-ocean-sm.jpg differ diff --git a/public/assets/img/demo/pug.svg b/public/assets/img/demo/pug.svg new file mode 100644 index 0000000..a7cd463 --- /dev/null +++ b/public/assets/img/demo/pug.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/demo/user-placeholder.svg b/public/assets/img/demo/user-placeholder.svg new file mode 100644 index 0000000..b778049 --- /dev/null +++ b/public/assets/img/demo/user-placeholder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/img/favicon.png b/public/assets/img/favicon.png new file mode 100644 index 0000000..a34f1b9 Binary files /dev/null and b/public/assets/img/favicon.png differ diff --git a/public/assets/img/illustrations/400-error-bad-request.svg b/public/assets/img/illustrations/400-error-bad-request.svg new file mode 100644 index 0000000..1f9f917 --- /dev/null +++ b/public/assets/img/illustrations/400-error-bad-request.svg @@ -0,0 +1,601 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/401-error-unauthorized.svg b/public/assets/img/illustrations/401-error-unauthorized.svg new file mode 100644 index 0000000..6fee0da --- /dev/null +++ b/public/assets/img/illustrations/401-error-unauthorized.svg @@ -0,0 +1,948 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/403-error-forbidden.svg b/public/assets/img/illustrations/403-error-forbidden.svg new file mode 100644 index 0000000..300d820 --- /dev/null +++ b/public/assets/img/illustrations/403-error-forbidden.svg @@ -0,0 +1,690 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/404-error-with-a-cute-animal.svg b/public/assets/img/illustrations/404-error-with-a-cute-animal.svg new file mode 100644 index 0000000..2bf242f --- /dev/null +++ b/public/assets/img/illustrations/404-error-with-a-cute-animal.svg @@ -0,0 +1,571 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/404-error.svg b/public/assets/img/illustrations/404-error.svg new file mode 100644 index 0000000..aa1d96e --- /dev/null +++ b/public/assets/img/illustrations/404-error.svg @@ -0,0 +1,566 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/500-internal-server-error.svg b/public/assets/img/illustrations/500-internal-server-error.svg new file mode 100644 index 0000000..5ed97a1 --- /dev/null +++ b/public/assets/img/illustrations/500-internal-server-error.svg @@ -0,0 +1,1048 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/503-error-service-unavailable.svg b/public/assets/img/illustrations/503-error-service-unavailable.svg new file mode 100644 index 0000000..8dda33d --- /dev/null +++ b/public/assets/img/illustrations/503-error-service-unavailable.svg @@ -0,0 +1,559 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/504-error-gateway-timeout.svg b/public/assets/img/illustrations/504-error-gateway-timeout.svg new file mode 100644 index 0000000..f80c85d --- /dev/null +++ b/public/assets/img/illustrations/504-error-gateway-timeout.svg @@ -0,0 +1,711 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/CREDITS.md b/public/assets/img/illustrations/CREDITS.md new file mode 100644 index 0000000..85fb16d --- /dev/null +++ b/public/assets/img/illustrations/CREDITS.md @@ -0,0 +1,14 @@ +# Illustration Credits + +The illustrations in this directory are sourced +from Stories by Freepik. + +Freepik offers hundreds of free, high quality +illustrations you can use in your projects. You +can view them all here: + + + +Make sure to view their licensing terms to make +sure you are attributing the image authors +correctly when using their assets. diff --git a/public/assets/img/illustrations/at-work.svg b/public/assets/img/illustrations/at-work.svg new file mode 100644 index 0000000..a656600 --- /dev/null +++ b/public/assets/img/illustrations/at-work.svg @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/browser-stats.svg b/public/assets/img/illustrations/browser-stats.svg new file mode 100644 index 0000000..0a03fdf --- /dev/null +++ b/public/assets/img/illustrations/browser-stats.svg @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/data-report.svg b/public/assets/img/illustrations/data-report.svg new file mode 100644 index 0000000..8ec4167 --- /dev/null +++ b/public/assets/img/illustrations/data-report.svg @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/problem-solving.svg b/public/assets/img/illustrations/problem-solving.svg new file mode 100644 index 0000000..bf2ac65 --- /dev/null +++ b/public/assets/img/illustrations/problem-solving.svg @@ -0,0 +1 @@ + diff --git a/public/assets/img/illustrations/processing.svg b/public/assets/img/illustrations/processing.svg new file mode 100644 index 0000000..a653e50 --- /dev/null +++ b/public/assets/img/illustrations/processing.svg @@ -0,0 +1,577 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/profiles/profile-1.png b/public/assets/img/illustrations/profiles/profile-1.png new file mode 100644 index 0000000..2650e7f Binary files /dev/null and b/public/assets/img/illustrations/profiles/profile-1.png differ diff --git a/public/assets/img/illustrations/profiles/profile-2.png b/public/assets/img/illustrations/profiles/profile-2.png new file mode 100644 index 0000000..11999f9 Binary files /dev/null and b/public/assets/img/illustrations/profiles/profile-2.png differ diff --git a/public/assets/img/illustrations/profiles/profile-3.png b/public/assets/img/illustrations/profiles/profile-3.png new file mode 100644 index 0000000..1d6ae3a Binary files /dev/null and b/public/assets/img/illustrations/profiles/profile-3.png differ diff --git a/public/assets/img/illustrations/profiles/profile-4.png b/public/assets/img/illustrations/profiles/profile-4.png new file mode 100644 index 0000000..7aede29 Binary files /dev/null and b/public/assets/img/illustrations/profiles/profile-4.png differ diff --git a/public/assets/img/illustrations/profiles/profile-5.png b/public/assets/img/illustrations/profiles/profile-5.png new file mode 100644 index 0000000..b87e16a Binary files /dev/null and b/public/assets/img/illustrations/profiles/profile-5.png differ diff --git a/public/assets/img/illustrations/profiles/profile-6.png b/public/assets/img/illustrations/profiles/profile-6.png new file mode 100644 index 0000000..472aa62 Binary files /dev/null and b/public/assets/img/illustrations/profiles/profile-6.png differ diff --git a/public/assets/img/illustrations/statistics.svg b/public/assets/img/illustrations/statistics.svg new file mode 100644 index 0000000..3643716 --- /dev/null +++ b/public/assets/img/illustrations/statistics.svg @@ -0,0 +1,759 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/team-spirit.svg b/public/assets/img/illustrations/team-spirit.svg new file mode 100644 index 0000000..3dd4317 --- /dev/null +++ b/public/assets/img/illustrations/team-spirit.svg @@ -0,0 +1,720 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/img/illustrations/windows.svg b/public/assets/img/illustrations/windows.svg new file mode 100644 index 0000000..effedf5 --- /dev/null +++ b/public/assets/img/illustrations/windows.svg @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/css/custom.css b/public/css/custom.css new file mode 100644 index 0000000..e026a07 --- /dev/null +++ b/public/css/custom.css @@ -0,0 +1,117 @@ +.text-center { + text-align: center; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.colorGray{ + color: gray; +} +.colorBlack{ + color: black; +} +.clear { + clear: both; +} +.sensitiveColumn { + display: none; +} + +#layoutSidenav, +#layoutSidenav_content, +#layoutSidenav_content > main, +#layoutSidenav_content > footer { + min-width: 0; +} + +@media (min-width: 576px) { + .contract-list-bulk-action { + width: auto !important; + } +} + +@media (max-width: 575.98px) { + .container-xl.px-4, + .container-fluid.px-4 { + padding-right: 0.75rem !important; + padding-left: 0.75rem !important; + } + + .topnav .navbar-brand { + max-width: calc(100vw - 8rem); + overflow: hidden; + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + text-overflow: ellipsis; + white-space: nowrap; + } + + .responsive-page-header { + align-items: stretch !important; + flex-direction: column !important; + } + + .responsive-page-header > .d-flex { + flex-direction: column; + width: 100%; + } + + .responsive-page-header .btn { + width: 100%; + } + + .responsive-page-header .nav { + flex-wrap: wrap; + } + + .responsive-date-range { + display: grid; + grid-template-columns: 3rem minmax(0, 1fr); + } + + .responsive-date-range > * { + min-width: 0; + margin-left: 0 !important; + border-radius: 0 !important; + } + + .responsive-date-range > :first-child { + border-top-left-radius: var(--bs-border-radius) !important; + } + + .responsive-date-range > :nth-child(2) { + border-top-right-radius: var(--bs-border-radius) !important; + } + + .responsive-date-range > :nth-child(3) { + border-bottom-left-radius: var(--bs-border-radius) !important; + } + + .responsive-date-range > :last-child { + border-bottom-right-radius: var(--bs-border-radius) !important; + } + + .responsive-pagination .pagination { + flex-wrap: wrap; + justify-content: center; + } + + .responsive-pagination .pagination .page-item:not(:first-child):not(:last-child):not(.active) { + display: none; + } + + .card-body.p-4 { + padding: 1rem !important; + } + + .chart-container { + min-height: 250px; + } + + .modal-dialog { + margin: 0.5rem; + } +} diff --git a/public/css/styles.css b/public/css/styles.css new file mode 100644 index 0000000..2d9f224 --- /dev/null +++ b/public/css/styles.css @@ -0,0 +1,19620 @@ +@charset "UTF-8"; +/*! +* Start Bootstrap - SB Admin Pro v2.0.5 (https://shop.startbootstrap.com/product/sb-admin-pro) +* Copyright 2013-2023 Start Bootstrap +* Licensed under SEE_LICENSE (https://github.com/StartBootstrap/sb-admin-pro/blob/master/LICENSE) +*/ +/*! + * Bootstrap v5.2.3 (https://getbootstrap.com/) + * Copyright 2011-2022 The Bootstrap Authors + * Copyright 2011-2022 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +:root { + --bs-blue: #0061f2; + --bs-indigo: #5800e8; + --bs-purple: #6900c7; + --bs-pink: #e30059; + --bs-red: #e81500; + --bs-orange: #f76400; + --bs-yellow: #f4a100; + --bs-green: #00ac69; + --bs-teal: #00ba94; + --bs-cyan: #00cfd5; + --bs-black: #000; + --bs-white: #fff; + --bs-gray: #69707a; + --bs-gray-dark: #363d47; + --bs-gray-100: #f2f6fc; + --bs-gray-200: #e0e5ec; + --bs-gray-300: #d4dae3; + --bs-gray-400: #c5ccd6; + --bs-gray-500: #a7aeb8; + --bs-gray-600: #69707a; + --bs-gray-700: #4a515b; + --bs-gray-800: #363d47; + --bs-gray-900: #212832; + --bs-primary: #0061f2; + --bs-secondary: #6900c7; + --bs-success: #00ac69; + --bs-info: #00cfd5; + --bs-warning: #f4a100; + --bs-danger: #e81500; + --bs-light: #f2f6fc; + --bs-dark: #212832; + --bs-black: #000; + --bs-white: #fff; + --bs-red: #e81500; + --bs-orange: #f76400; + --bs-yellow: #f4a100; + --bs-green: #00ac69; + --bs-teal: #00ba94; + --bs-cyan: #00cfd5; + --bs-blue: #0061f2; + --bs-indigo: #5800e8; + --bs-purple: #6900c7; + --bs-pink: #e30059; + --bs-red-soft: #f1e0e3; + --bs-orange-soft: #f3e7e3; + --bs-yellow-soft: #f2eee3; + --bs-green-soft: #daefed; + --bs-teal-soft: #daf0f2; + --bs-cyan-soft: #daf2f8; + --bs-blue-soft: #dae7fb; + --bs-indigo-soft: #e3ddfa; + --bs-purple-soft: #e4ddf7; + --bs-pink-soft: #f1ddec; + --bs-primary-soft: #dae7fb; + --bs-secondary-soft: #e4ddf7; + --bs-success-soft: #daefed; + --bs-info-soft: #daf2f8; + --bs-warning-soft: #f2eee3; + --bs-danger-soft: #f1e0e3; + --bs-primary-rgb: 0, 97, 242; + --bs-secondary-rgb: 105, 0, 199; + --bs-success-rgb: 0, 172, 105; + --bs-info-rgb: 0, 207, 213; + --bs-warning-rgb: 244, 161, 0; + --bs-danger-rgb: 232, 21, 0; + --bs-light-rgb: 242, 246, 252; + --bs-dark-rgb: 33, 40, 50; + --bs-black-rgb: 0, 0, 0; + --bs-white-rgb: 255, 255, 255; + --bs-red-rgb: 232, 21, 0; + --bs-orange-rgb: 247, 100, 0; + --bs-yellow-rgb: 244, 161, 0; + --bs-green-rgb: 0, 172, 105; + --bs-teal-rgb: 0, 186, 148; + --bs-cyan-rgb: 0, 207, 213; + --bs-blue-rgb: 0, 97, 242; + --bs-indigo-rgb: 88, 0, 232; + --bs-purple-rgb: 105, 0, 199; + --bs-pink-rgb: 227, 0, 89; + --bs-red-soft-rgb: 241, 224, 227; + --bs-orange-soft-rgb: 243, 231, 227; + --bs-yellow-soft-rgb: 242, 238, 227; + --bs-green-soft-rgb: 218, 239, 237; + --bs-teal-soft-rgb: 218, 240, 242; + --bs-cyan-soft-rgb: 218, 242, 248; + --bs-blue-soft-rgb: 218, 231, 251; + --bs-indigo-soft-rgb: 227, 221, 250; + --bs-purple-soft-rgb: 228, 221, 247; + --bs-pink-soft-rgb: 241, 221, 236; + --bs-primary-soft-rgb: 218, 231, 251; + --bs-secondary-soft-rgb: 228, 221, 247; + --bs-success-soft-rgb: 218, 239, 237; + --bs-info-soft-rgb: 218, 242, 248; + --bs-warning-soft-rgb: 242, 238, 227; + --bs-danger-soft-rgb: 241, 224, 227; + --bs-white-rgb: 255, 255, 255; + --bs-black-rgb: 0, 0, 0; + --bs-body-color-rgb: 105, 112, 122; + --bs-body-bg-rgb: 242, 246, 252; + --bs-font-sans-serif: "Metropolis", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); + --bs-body-font-family: Metropolis, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; + --bs-body-font-size: 1rem; + --bs-body-font-weight: 400; + --bs-body-line-height: 1.5; + --bs-body-color: #69707a; + --bs-body-bg: #f2f6fc; + --bs-border-width: 1px; + --bs-border-style: solid; + --bs-border-color: #e0e5ec; + --bs-border-color-translucent: rgba(0, 0, 0, 0.175); + --bs-border-radius: 0.35rem; + --bs-border-radius-sm: 0.25rem; + --bs-border-radius-lg: 0.5rem; + --bs-border-radius-xl: 1rem; + --bs-border-radius-2xl: 2rem; + --bs-border-radius-pill: 50rem; + --bs-link-color: #0061f2; + --bs-link-hover-color: #004ec2; + --bs-code-color: #e30059; + --bs-highlight-bg: #fdeccc; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +@media (prefers-reduced-motion: no-preference) { + :root { + scroll-behavior: smooth; + } +} + +body { + margin: 0; + font-family: var(--bs-body-font-family); + font-size: var(--bs-body-font-size); + font-weight: var(--bs-body-font-weight); + line-height: var(--bs-body-line-height); + color: var(--bs-body-color); + text-align: var(--bs-body-text-align); + background-color: var(--bs-body-bg); + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +hr { + margin: 1rem 0; + color: inherit; + border: 0; + border-top: 1px solid; + opacity: 0.25; +} + +h6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 { + margin-top: 0; + margin-bottom: 0.5rem; + font-weight: 500; + line-height: 1.2; + color: #363d47; +} + +h1, .h1 { + font-size: calc(1.275rem + 0.3vw); +} +@media (min-width: 1200px) { + h1, .h1 { + font-size: 1.5rem; + } +} + +h2, .h2 { + font-size: calc(1.265rem + 0.18vw); +} +@media (min-width: 1200px) { + h2, .h2 { + font-size: 1.4rem; + } +} + +h3, .h3 { + font-size: calc(1.255rem + 0.06vw); +} +@media (min-width: 1200px) { + h3, .h3 { + font-size: 1.3rem; + } +} + +h4, .h4 { + font-size: 1.2rem; +} + +h5, .h5 { + font-size: 1.1rem; +} + +h6, .h6 { + font-size: 1rem; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +abbr[title] { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; + cursor: help; + -webkit-text-decoration-skip-ink: none; + text-decoration-skip-ink: none; +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + +ol, +ul { + padding-left: 2rem; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: 500; +} + +dd { + margin-bottom: 0.5rem; + margin-left: 0; +} + +blockquote { + margin: 0 0 1rem; +} + +b, +strong { + font-weight: bolder; +} + +small, .small { + font-size: 0.875em; +} + +mark, .mark { + padding: 0.1875em; + background-color: var(--bs-highlight-bg); +} + +sub, +sup { + position: relative; + font-size: 0.75em; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +a { + color: var(--bs-link-color); + text-decoration: none; +} +a:hover { + color: var(--bs-link-hover-color); + text-decoration: underline; +} + +a:not([href]):not([class]), a:not([href]):not([class]):hover { + color: inherit; + text-decoration: none; +} + +pre, +code, +kbd, +samp { + font-family: var(--bs-font-monospace); + font-size: 1em; +} + +pre { + display: block; + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; + font-size: 0.875em; + color: #69707a; +} +pre code { + font-size: inherit; + color: inherit; + word-break: normal; +} + +code { + font-size: 0.875em; + color: var(--bs-code-color); + word-wrap: break-word; +} +a > code { + color: inherit; +} + +kbd { + padding: 0.1875rem 0.375rem; + font-size: 0.875em; + color: var(--bs-body-bg); + background-color: var(--bs-body-color); + border-radius: 0.25rem; +} +kbd kbd { + padding: 0; + font-size: 1em; +} + +figure { + margin: 0 0 1rem; +} + +img, +svg { + vertical-align: middle; +} + +table { + caption-side: bottom; + border-collapse: collapse; +} + +caption { + padding-top: 0.75rem; + padding-bottom: 0.75rem; + color: #a7aeb8; + text-align: left; +} + +th { + text-align: inherit; + text-align: -webkit-match-parent; +} + +thead, +tbody, +tfoot, +tr, +td, +th { + border-color: inherit; + border-style: solid; + border-width: 0; +} + +label { + display: inline-block; +} + +button { + border-radius: 0; +} + +button:focus:not(:focus-visible) { + outline: 0; +} + +input, +button, +select, +optgroup, +textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +button, +select { + text-transform: none; +} + +[role=button] { + cursor: pointer; +} + +select { + word-wrap: normal; +} +select:disabled { + opacity: 1; +} + +[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator { + display: none !important; +} + +button, +[type=button], +[type=reset], +[type=submit] { + -webkit-appearance: button; +} +button:not(:disabled), +[type=button]:not(:disabled), +[type=reset]:not(:disabled), +[type=submit]:not(:disabled) { + cursor: pointer; +} + +::-moz-focus-inner { + padding: 0; + border-style: none; +} + +textarea { + resize: vertical; +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} + +legend { + float: left; + width: 100%; + padding: 0; + margin-bottom: 0.5rem; + font-size: calc(1.275rem + 0.3vw); + line-height: inherit; +} +@media (min-width: 1200px) { + legend { + font-size: 1.5rem; + } +} +legend + * { + clear: left; +} + +::-webkit-datetime-edit-fields-wrapper, +::-webkit-datetime-edit-text, +::-webkit-datetime-edit-minute, +::-webkit-datetime-edit-hour-field, +::-webkit-datetime-edit-day-field, +::-webkit-datetime-edit-month-field, +::-webkit-datetime-edit-year-field { + padding: 0; +} + +::-webkit-inner-spin-button { + height: auto; +} + +[type=search] { + outline-offset: -2px; + -webkit-appearance: textfield; +} + +/* rtl:raw: +[type="tel"], +[type="url"], +[type="email"], +[type="number"] { + direction: ltr; +} +*/ +::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-color-swatch-wrapper { + padding: 0; +} + +::file-selector-button { + font: inherit; + -webkit-appearance: button; +} + +output { + display: inline-block; +} + +iframe { + border: 0; +} + +summary { + display: list-item; + cursor: pointer; +} + +progress { + vertical-align: baseline; +} + +[hidden] { + display: none !important; +} + +.lead { + font-size: 1.1rem; + font-weight: 400; +} + +.display-1 { + font-size: calc(1.625rem + 4.5vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-1 { + font-size: 5rem; + } +} + +.display-2 { + font-size: calc(1.575rem + 3.9vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-2 { + font-size: 4.5rem; + } +} + +.display-3 { + font-size: calc(1.525rem + 3.3vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-3 { + font-size: 4rem; + } +} + +.display-4 { + font-size: calc(1.475rem + 2.7vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-4 { + font-size: 3.5rem; + } +} + +.display-5 { + font-size: calc(1.425rem + 2.1vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-5 { + font-size: 3rem; + } +} + +.display-6 { + font-size: calc(1.375rem + 1.5vw); + font-weight: 300; + line-height: 1.2; +} +@media (min-width: 1200px) { + .display-6 { + font-size: 2.5rem; + } +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline-item { + display: inline-block; +} +.list-inline-item:not(:last-child) { + margin-right: 0.5rem; +} + +.initialism { + font-size: 0.875em; + text-transform: uppercase; +} + +.blockquote { + margin-bottom: 1rem; + font-size: 1.25rem; +} +.blockquote > :last-child { + margin-bottom: 0; +} + +.blockquote-footer { + margin-top: -1rem; + margin-bottom: 1rem; + font-size: 0.875em; + color: #69707a; +} +.blockquote-footer::before { + content: "— "; +} + +.img-fluid { + max-width: 100%; + height: auto; +} + +.img-thumbnail { + padding: 0.25rem; + background-color: #f2f6fc; + border: 1px solid var(--bs-border-color); + border-radius: 0.35rem; + max-width: 100%; + height: auto; +} + +.figure { + display: inline-block; +} + +.figure-img { + margin-bottom: 0.5rem; + line-height: 1; +} + +.figure-caption { + font-size: 0.875em; + color: #69707a; +} + +.container, +.container-fluid, +.container-xxl, +.container-xl, +.container-lg, +.container-md, +.container-sm { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + width: 100%; + padding-right: calc(var(--bs-gutter-x) * 0.5); + padding-left: calc(var(--bs-gutter-x) * 0.5); + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + .container-sm, .container { + max-width: 540px; + } +} +@media (min-width: 768px) { + .container-md, .container-sm, .container { + max-width: 720px; + } +} +@media (min-width: 992px) { + .container-lg, .container-md, .container-sm, .container { + max-width: 960px; + } +} +@media (min-width: 1200px) { + .container-xl, .container-lg, .container-md, .container-sm, .container { + max-width: 1140px; + } +} +@media (min-width: 1500px) { + .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container { + max-width: 1440px; + } +} +.row { + --bs-gutter-x: 1.5rem; + --bs-gutter-y: 0; + display: flex; + flex-wrap: wrap; + margin-top: calc(-1 * var(--bs-gutter-y)); + margin-right: calc(-0.5 * var(--bs-gutter-x)); + margin-left: calc(-0.5 * var(--bs-gutter-x)); +} +.row > * { + flex-shrink: 0; + width: 100%; + max-width: 100%; + padding-right: calc(var(--bs-gutter-x) * 0.5); + padding-left: calc(var(--bs-gutter-x) * 0.5); + margin-top: var(--bs-gutter-y); +} + +.col { + flex: 1 0 0%; +} + +.row-cols-auto > * { + flex: 0 0 auto; + width: auto; +} + +.row-cols-1 > * { + flex: 0 0 auto; + width: 100%; +} + +.row-cols-2 > * { + flex: 0 0 auto; + width: 50%; +} + +.row-cols-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; +} + +.row-cols-4 > * { + flex: 0 0 auto; + width: 25%; +} + +.row-cols-5 > * { + flex: 0 0 auto; + width: 20%; +} + +.row-cols-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; +} + +.col-auto { + flex: 0 0 auto; + width: auto; +} + +.col-1 { + flex: 0 0 auto; + width: 8.33333333%; +} + +.col-2 { + flex: 0 0 auto; + width: 16.66666667%; +} + +.col-3 { + flex: 0 0 auto; + width: 25%; +} + +.col-4 { + flex: 0 0 auto; + width: 33.33333333%; +} + +.col-5 { + flex: 0 0 auto; + width: 41.66666667%; +} + +.col-6 { + flex: 0 0 auto; + width: 50%; +} + +.col-7 { + flex: 0 0 auto; + width: 58.33333333%; +} + +.col-8 { + flex: 0 0 auto; + width: 66.66666667%; +} + +.col-9 { + flex: 0 0 auto; + width: 75%; +} + +.col-10 { + flex: 0 0 auto; + width: 83.33333333%; +} + +.col-11 { + flex: 0 0 auto; + width: 91.66666667%; +} + +.col-12 { + flex: 0 0 auto; + width: 100%; +} + +.offset-1 { + margin-left: 8.33333333%; +} + +.offset-2 { + margin-left: 16.66666667%; +} + +.offset-3 { + margin-left: 25%; +} + +.offset-4 { + margin-left: 33.33333333%; +} + +.offset-5 { + margin-left: 41.66666667%; +} + +.offset-6 { + margin-left: 50%; +} + +.offset-7 { + margin-left: 58.33333333%; +} + +.offset-8 { + margin-left: 66.66666667%; +} + +.offset-9 { + margin-left: 75%; +} + +.offset-10 { + margin-left: 83.33333333%; +} + +.offset-11 { + margin-left: 91.66666667%; +} + +.g-0, +.gx-0 { + --bs-gutter-x: 0; +} + +.g-0, +.gy-0 { + --bs-gutter-y: 0; +} + +.g-1, +.gx-1 { + --bs-gutter-x: 0.25rem; +} + +.g-1, +.gy-1 { + --bs-gutter-y: 0.25rem; +} + +.g-2, +.gx-2 { + --bs-gutter-x: 0.5rem; +} + +.g-2, +.gy-2 { + --bs-gutter-y: 0.5rem; +} + +.g-3, +.gx-3 { + --bs-gutter-x: 1rem; +} + +.g-3, +.gy-3 { + --bs-gutter-y: 1rem; +} + +.g-4, +.gx-4 { + --bs-gutter-x: 1.5rem; +} + +.g-4, +.gy-4 { + --bs-gutter-y: 1.5rem; +} + +.g-5, +.gx-5 { + --bs-gutter-x: 2.5rem; +} + +.g-5, +.gy-5 { + --bs-gutter-y: 2.5rem; +} + +.g-10, +.gx-10 { + --bs-gutter-x: 6rem; +} + +.g-10, +.gy-10 { + --bs-gutter-y: 6rem; +} + +.g-15, +.gx-15 { + --bs-gutter-x: 9rem; +} + +.g-15, +.gy-15 { + --bs-gutter-y: 9rem; +} + +@media (min-width: 576px) { + .col-sm { + flex: 1 0 0%; + } + .row-cols-sm-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-sm-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-sm-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-sm-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; + } + .row-cols-sm-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-sm-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-sm-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; + } + .col-sm-auto { + flex: 0 0 auto; + width: auto; + } + .col-sm-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-sm-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-sm-3 { + flex: 0 0 auto; + width: 25%; + } + .col-sm-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-sm-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-sm-6 { + flex: 0 0 auto; + width: 50%; + } + .col-sm-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-sm-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-sm-9 { + flex: 0 0 auto; + width: 75%; + } + .col-sm-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-sm-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-sm-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-sm-0 { + margin-left: 0; + } + .offset-sm-1 { + margin-left: 8.33333333%; + } + .offset-sm-2 { + margin-left: 16.66666667%; + } + .offset-sm-3 { + margin-left: 25%; + } + .offset-sm-4 { + margin-left: 33.33333333%; + } + .offset-sm-5 { + margin-left: 41.66666667%; + } + .offset-sm-6 { + margin-left: 50%; + } + .offset-sm-7 { + margin-left: 58.33333333%; + } + .offset-sm-8 { + margin-left: 66.66666667%; + } + .offset-sm-9 { + margin-left: 75%; + } + .offset-sm-10 { + margin-left: 83.33333333%; + } + .offset-sm-11 { + margin-left: 91.66666667%; + } + .g-sm-0, + .gx-sm-0 { + --bs-gutter-x: 0; + } + .g-sm-0, + .gy-sm-0 { + --bs-gutter-y: 0; + } + .g-sm-1, + .gx-sm-1 { + --bs-gutter-x: 0.25rem; + } + .g-sm-1, + .gy-sm-1 { + --bs-gutter-y: 0.25rem; + } + .g-sm-2, + .gx-sm-2 { + --bs-gutter-x: 0.5rem; + } + .g-sm-2, + .gy-sm-2 { + --bs-gutter-y: 0.5rem; + } + .g-sm-3, + .gx-sm-3 { + --bs-gutter-x: 1rem; + } + .g-sm-3, + .gy-sm-3 { + --bs-gutter-y: 1rem; + } + .g-sm-4, + .gx-sm-4 { + --bs-gutter-x: 1.5rem; + } + .g-sm-4, + .gy-sm-4 { + --bs-gutter-y: 1.5rem; + } + .g-sm-5, + .gx-sm-5 { + --bs-gutter-x: 2.5rem; + } + .g-sm-5, + .gy-sm-5 { + --bs-gutter-y: 2.5rem; + } + .g-sm-10, + .gx-sm-10 { + --bs-gutter-x: 6rem; + } + .g-sm-10, + .gy-sm-10 { + --bs-gutter-y: 6rem; + } + .g-sm-15, + .gx-sm-15 { + --bs-gutter-x: 9rem; + } + .g-sm-15, + .gy-sm-15 { + --bs-gutter-y: 9rem; + } +} +@media (min-width: 768px) { + .col-md { + flex: 1 0 0%; + } + .row-cols-md-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-md-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-md-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-md-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; + } + .row-cols-md-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-md-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-md-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; + } + .col-md-auto { + flex: 0 0 auto; + width: auto; + } + .col-md-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-md-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-md-3 { + flex: 0 0 auto; + width: 25%; + } + .col-md-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-md-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-md-6 { + flex: 0 0 auto; + width: 50%; + } + .col-md-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-md-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-md-9 { + flex: 0 0 auto; + width: 75%; + } + .col-md-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-md-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-md-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-md-0 { + margin-left: 0; + } + .offset-md-1 { + margin-left: 8.33333333%; + } + .offset-md-2 { + margin-left: 16.66666667%; + } + .offset-md-3 { + margin-left: 25%; + } + .offset-md-4 { + margin-left: 33.33333333%; + } + .offset-md-5 { + margin-left: 41.66666667%; + } + .offset-md-6 { + margin-left: 50%; + } + .offset-md-7 { + margin-left: 58.33333333%; + } + .offset-md-8 { + margin-left: 66.66666667%; + } + .offset-md-9 { + margin-left: 75%; + } + .offset-md-10 { + margin-left: 83.33333333%; + } + .offset-md-11 { + margin-left: 91.66666667%; + } + .g-md-0, + .gx-md-0 { + --bs-gutter-x: 0; + } + .g-md-0, + .gy-md-0 { + --bs-gutter-y: 0; + } + .g-md-1, + .gx-md-1 { + --bs-gutter-x: 0.25rem; + } + .g-md-1, + .gy-md-1 { + --bs-gutter-y: 0.25rem; + } + .g-md-2, + .gx-md-2 { + --bs-gutter-x: 0.5rem; + } + .g-md-2, + .gy-md-2 { + --bs-gutter-y: 0.5rem; + } + .g-md-3, + .gx-md-3 { + --bs-gutter-x: 1rem; + } + .g-md-3, + .gy-md-3 { + --bs-gutter-y: 1rem; + } + .g-md-4, + .gx-md-4 { + --bs-gutter-x: 1.5rem; + } + .g-md-4, + .gy-md-4 { + --bs-gutter-y: 1.5rem; + } + .g-md-5, + .gx-md-5 { + --bs-gutter-x: 2.5rem; + } + .g-md-5, + .gy-md-5 { + --bs-gutter-y: 2.5rem; + } + .g-md-10, + .gx-md-10 { + --bs-gutter-x: 6rem; + } + .g-md-10, + .gy-md-10 { + --bs-gutter-y: 6rem; + } + .g-md-15, + .gx-md-15 { + --bs-gutter-x: 9rem; + } + .g-md-15, + .gy-md-15 { + --bs-gutter-y: 9rem; + } +} +@media (min-width: 992px) { + .col-lg { + flex: 1 0 0%; + } + .row-cols-lg-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-lg-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-lg-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-lg-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; + } + .row-cols-lg-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-lg-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-lg-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; + } + .col-lg-auto { + flex: 0 0 auto; + width: auto; + } + .col-lg-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-lg-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-lg-3 { + flex: 0 0 auto; + width: 25%; + } + .col-lg-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-lg-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-lg-6 { + flex: 0 0 auto; + width: 50%; + } + .col-lg-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-lg-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-lg-9 { + flex: 0 0 auto; + width: 75%; + } + .col-lg-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-lg-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-lg-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-lg-0 { + margin-left: 0; + } + .offset-lg-1 { + margin-left: 8.33333333%; + } + .offset-lg-2 { + margin-left: 16.66666667%; + } + .offset-lg-3 { + margin-left: 25%; + } + .offset-lg-4 { + margin-left: 33.33333333%; + } + .offset-lg-5 { + margin-left: 41.66666667%; + } + .offset-lg-6 { + margin-left: 50%; + } + .offset-lg-7 { + margin-left: 58.33333333%; + } + .offset-lg-8 { + margin-left: 66.66666667%; + } + .offset-lg-9 { + margin-left: 75%; + } + .offset-lg-10 { + margin-left: 83.33333333%; + } + .offset-lg-11 { + margin-left: 91.66666667%; + } + .g-lg-0, + .gx-lg-0 { + --bs-gutter-x: 0; + } + .g-lg-0, + .gy-lg-0 { + --bs-gutter-y: 0; + } + .g-lg-1, + .gx-lg-1 { + --bs-gutter-x: 0.25rem; + } + .g-lg-1, + .gy-lg-1 { + --bs-gutter-y: 0.25rem; + } + .g-lg-2, + .gx-lg-2 { + --bs-gutter-x: 0.5rem; + } + .g-lg-2, + .gy-lg-2 { + --bs-gutter-y: 0.5rem; + } + .g-lg-3, + .gx-lg-3 { + --bs-gutter-x: 1rem; + } + .g-lg-3, + .gy-lg-3 { + --bs-gutter-y: 1rem; + } + .g-lg-4, + .gx-lg-4 { + --bs-gutter-x: 1.5rem; + } + .g-lg-4, + .gy-lg-4 { + --bs-gutter-y: 1.5rem; + } + .g-lg-5, + .gx-lg-5 { + --bs-gutter-x: 2.5rem; + } + .g-lg-5, + .gy-lg-5 { + --bs-gutter-y: 2.5rem; + } + .g-lg-10, + .gx-lg-10 { + --bs-gutter-x: 6rem; + } + .g-lg-10, + .gy-lg-10 { + --bs-gutter-y: 6rem; + } + .g-lg-15, + .gx-lg-15 { + --bs-gutter-x: 9rem; + } + .g-lg-15, + .gy-lg-15 { + --bs-gutter-y: 9rem; + } +} +@media (min-width: 1200px) { + .col-xl { + flex: 1 0 0%; + } + .row-cols-xl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xl-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; + } + .row-cols-xl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xl-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; + } + .col-xl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xl-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-xl-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xl-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-xl-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-xl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xl-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-xl-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-xl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xl-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-xl-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-xl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xl-0 { + margin-left: 0; + } + .offset-xl-1 { + margin-left: 8.33333333%; + } + .offset-xl-2 { + margin-left: 16.66666667%; + } + .offset-xl-3 { + margin-left: 25%; + } + .offset-xl-4 { + margin-left: 33.33333333%; + } + .offset-xl-5 { + margin-left: 41.66666667%; + } + .offset-xl-6 { + margin-left: 50%; + } + .offset-xl-7 { + margin-left: 58.33333333%; + } + .offset-xl-8 { + margin-left: 66.66666667%; + } + .offset-xl-9 { + margin-left: 75%; + } + .offset-xl-10 { + margin-left: 83.33333333%; + } + .offset-xl-11 { + margin-left: 91.66666667%; + } + .g-xl-0, + .gx-xl-0 { + --bs-gutter-x: 0; + } + .g-xl-0, + .gy-xl-0 { + --bs-gutter-y: 0; + } + .g-xl-1, + .gx-xl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xl-1, + .gy-xl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xl-2, + .gx-xl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xl-2, + .gy-xl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xl-3, + .gx-xl-3 { + --bs-gutter-x: 1rem; + } + .g-xl-3, + .gy-xl-3 { + --bs-gutter-y: 1rem; + } + .g-xl-4, + .gx-xl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xl-4, + .gy-xl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xl-5, + .gx-xl-5 { + --bs-gutter-x: 2.5rem; + } + .g-xl-5, + .gy-xl-5 { + --bs-gutter-y: 2.5rem; + } + .g-xl-10, + .gx-xl-10 { + --bs-gutter-x: 6rem; + } + .g-xl-10, + .gy-xl-10 { + --bs-gutter-y: 6rem; + } + .g-xl-15, + .gx-xl-15 { + --bs-gutter-x: 9rem; + } + .g-xl-15, + .gy-xl-15 { + --bs-gutter-y: 9rem; + } +} +@media (min-width: 1500px) { + .col-xxl { + flex: 1 0 0%; + } + .row-cols-xxl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xxl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xxl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xxl-3 > * { + flex: 0 0 auto; + width: 33.3333333333%; + } + .row-cols-xxl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xxl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xxl-6 > * { + flex: 0 0 auto; + width: 16.6666666667%; + } + .col-xxl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xxl-1 { + flex: 0 0 auto; + width: 8.33333333%; + } + .col-xxl-2 { + flex: 0 0 auto; + width: 16.66666667%; + } + .col-xxl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xxl-4 { + flex: 0 0 auto; + width: 33.33333333%; + } + .col-xxl-5 { + flex: 0 0 auto; + width: 41.66666667%; + } + .col-xxl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xxl-7 { + flex: 0 0 auto; + width: 58.33333333%; + } + .col-xxl-8 { + flex: 0 0 auto; + width: 66.66666667%; + } + .col-xxl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xxl-10 { + flex: 0 0 auto; + width: 83.33333333%; + } + .col-xxl-11 { + flex: 0 0 auto; + width: 91.66666667%; + } + .col-xxl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xxl-0 { + margin-left: 0; + } + .offset-xxl-1 { + margin-left: 8.33333333%; + } + .offset-xxl-2 { + margin-left: 16.66666667%; + } + .offset-xxl-3 { + margin-left: 25%; + } + .offset-xxl-4 { + margin-left: 33.33333333%; + } + .offset-xxl-5 { + margin-left: 41.66666667%; + } + .offset-xxl-6 { + margin-left: 50%; + } + .offset-xxl-7 { + margin-left: 58.33333333%; + } + .offset-xxl-8 { + margin-left: 66.66666667%; + } + .offset-xxl-9 { + margin-left: 75%; + } + .offset-xxl-10 { + margin-left: 83.33333333%; + } + .offset-xxl-11 { + margin-left: 91.66666667%; + } + .g-xxl-0, + .gx-xxl-0 { + --bs-gutter-x: 0; + } + .g-xxl-0, + .gy-xxl-0 { + --bs-gutter-y: 0; + } + .g-xxl-1, + .gx-xxl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xxl-1, + .gy-xxl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xxl-2, + .gx-xxl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xxl-2, + .gy-xxl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xxl-3, + .gx-xxl-3 { + --bs-gutter-x: 1rem; + } + .g-xxl-3, + .gy-xxl-3 { + --bs-gutter-y: 1rem; + } + .g-xxl-4, + .gx-xxl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xxl-4, + .gy-xxl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xxl-5, + .gx-xxl-5 { + --bs-gutter-x: 2.5rem; + } + .g-xxl-5, + .gy-xxl-5 { + --bs-gutter-y: 2.5rem; + } + .g-xxl-10, + .gx-xxl-10 { + --bs-gutter-x: 6rem; + } + .g-xxl-10, + .gy-xxl-10 { + --bs-gutter-y: 6rem; + } + .g-xxl-15, + .gx-xxl-15 { + --bs-gutter-x: 9rem; + } + .g-xxl-15, + .gy-xxl-15 { + --bs-gutter-y: 9rem; + } +} +.table, .datatable-table { + --bs-table-color: var(--bs-body-color); + --bs-table-bg: transparent; + --bs-table-border-color: #e0e5ec; + --bs-table-accent-bg: transparent; + --bs-table-striped-color: var(--bs-body-color); + --bs-table-striped-bg: rgba(0, 0, 0, 0.05); + --bs-table-active-color: var(--bs-body-color); + --bs-table-active-bg: rgba(0, 0, 0, 0.1); + --bs-table-hover-color: var(--bs-body-color); + --bs-table-hover-bg: rgba(224, 229, 236, 0.25); + width: 100%; + margin-bottom: 1rem; + color: var(--bs-table-color); + vertical-align: top; + border-color: var(--bs-table-border-color); +} +.table > :not(caption) > * > *, .datatable-table > :not(caption) > * > * { + padding: 0.75rem 0.75rem; + background-color: var(--bs-table-bg); + border-bottom-width: 1px; + box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg); +} +.table > tbody, .datatable-table > tbody { + vertical-align: inherit; +} +.table > thead, .datatable-table > thead { + vertical-align: bottom; +} + +.table-group-divider { + border-top: 2px solid currentcolor; +} + +.caption-top { + caption-side: top; +} + +.table-sm > :not(caption) > * > * { + padding: 0.25rem 0.25rem; +} + +.table-bordered > :not(caption) > *, .datatable-table > :not(caption) > * { + border-width: 1px 0; +} +.table-bordered > :not(caption) > * > *, .datatable-table > :not(caption) > * > * { + border-width: 0 1px; +} + +.table-borderless > :not(caption) > * > * { + border-bottom-width: 0; +} +.table-borderless > :not(:first-child) { + border-top-width: 0; +} + +.table-striped > tbody > tr:nth-of-type(odd) > * { + --bs-table-accent-bg: var(--bs-table-striped-bg); + color: var(--bs-table-striped-color); +} + +.table-striped-columns > :not(caption) > tr > :nth-child(even) { + --bs-table-accent-bg: var(--bs-table-striped-bg); + color: var(--bs-table-striped-color); +} + +.table-active { + --bs-table-accent-bg: var(--bs-table-active-bg); + color: var(--bs-table-active-color); +} + +.table-hover > tbody > tr:hover > *, .datatable-table > tbody > tr:hover > * { + --bs-table-accent-bg: var(--bs-table-hover-bg); + color: var(--bs-table-hover-color); +} + +.table-primary { + --bs-table-color: #000; + --bs-table-bg: #ccdffc; + --bs-table-border-color: #b8c9e3; + --bs-table-striped-bg: #c2d4ef; + --bs-table-striped-color: #000; + --bs-table-active-bg: #b8c9e3; + --bs-table-active-color: #000; + --bs-table-hover-bg: #bdcee9; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-secondary { + --bs-table-color: #000; + --bs-table-bg: #e1ccf4; + --bs-table-border-color: #cbb8dc; + --bs-table-striped-bg: #d6c2e8; + --bs-table-striped-color: #000; + --bs-table-active-bg: #cbb8dc; + --bs-table-active-color: #000; + --bs-table-hover-bg: #d0bde2; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-success { + --bs-table-color: #000; + --bs-table-bg: #cceee1; + --bs-table-border-color: #b8d6cb; + --bs-table-striped-bg: #c2e2d6; + --bs-table-striped-color: #000; + --bs-table-active-bg: #b8d6cb; + --bs-table-active-color: #000; + --bs-table-hover-bg: #bddcd0; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-info { + --bs-table-color: #000; + --bs-table-bg: #ccf5f7; + --bs-table-border-color: #b8ddde; + --bs-table-striped-bg: #c2e9eb; + --bs-table-striped-color: #000; + --bs-table-active-bg: #b8ddde; + --bs-table-active-color: #000; + --bs-table-hover-bg: #bde3e4; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-warning { + --bs-table-color: #000; + --bs-table-bg: #fdeccc; + --bs-table-border-color: #e4d4b8; + --bs-table-striped-bg: #f0e0c2; + --bs-table-striped-color: #000; + --bs-table-active-bg: #e4d4b8; + --bs-table-active-color: #000; + --bs-table-hover-bg: #eadabd; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-danger { + --bs-table-color: #000; + --bs-table-bg: #fad0cc; + --bs-table-border-color: #e1bbb8; + --bs-table-striped-bg: #eec6c2; + --bs-table-striped-color: #000; + --bs-table-active-bg: #e1bbb8; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e7c0bd; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-light { + --bs-table-color: #000; + --bs-table-bg: #f2f6fc; + --bs-table-border-color: #dadde3; + --bs-table-striped-bg: #e6eaef; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dadde3; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e0e4e9; + --bs-table-hover-color: #000; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-dark { + --bs-table-color: #fff; + --bs-table-bg: #212832; + --bs-table-border-color: #373e47; + --bs-table-striped-bg: #2c333c; + --bs-table-striped-color: #fff; + --bs-table-active-bg: #373e47; + --bs-table-active-color: #fff; + --bs-table-hover-bg: #323841; + --bs-table-hover-color: #fff; + color: var(--bs-table-color); + border-color: var(--bs-table-border-color); +} + +.table-responsive, .datatable-wrapper .datatable-container { + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +@media (max-width: 575.98px) { + .table-responsive-sm { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 767.98px) { + .table-responsive-md { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 991.98px) { + .table-responsive-lg { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 1199.98px) { + .table-responsive-xl { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +@media (max-width: 1499.98px) { + .table-responsive-xxl { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} +.form-label { + margin-bottom: 0.5rem; +} + +.col-form-label { + padding-top: calc(0.875rem + 1px); + padding-bottom: calc(0.875rem + 1px); + margin-bottom: 0; + font-size: inherit; + line-height: 1; +} + +.col-form-label-lg { + padding-top: calc(1.125rem + 1px); + padding-bottom: calc(1.125rem + 1px); + font-size: 1rem; +} + +.col-form-label-sm { + padding-top: calc(0.5rem + 1px); + padding-bottom: calc(0.5rem + 1px); + font-size: 0.75rem; +} + +.form-text { + margin-top: 0.25rem; + font-size: 0.875em; + color: #a7aeb8; +} + +.form-control, .datatable-input { + display: block; + width: 100%; + padding: 0.875rem 1.125rem; + font-size: 0.875rem; + font-weight: 400; + line-height: 1; + color: #69707a; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #c5ccd6; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + border-radius: 0.35rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-control, .datatable-input { + transition: none; + } +} +.form-control[type=file], [type=file].datatable-input { + overflow: hidden; +} +.form-control[type=file]:not(:disabled):not([readonly]), [type=file].datatable-input:not(:disabled):not([readonly]) { + cursor: pointer; +} +.form-control:focus, .datatable-input:focus { + color: #69707a; + background-color: #fff; + border-color: transparent; + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(0, 97, 242, 0.25); +} +.form-control::-webkit-date-and-time-value, .datatable-input::-webkit-date-and-time-value { + height: 1em; +} +.form-control::-moz-placeholder, .datatable-input::-moz-placeholder { + color: #a7aeb8; + opacity: 1; +} +.form-control::placeholder, .datatable-input::placeholder { + color: #a7aeb8; + opacity: 1; +} +.form-control:disabled, .datatable-input:disabled { + background-color: #e0e5ec; + opacity: 1; +} +.form-control::file-selector-button, .datatable-input::file-selector-button { + padding: 0.875rem 1.125rem; + margin: -0.875rem -1.125rem; + -webkit-margin-end: 1.125rem; + margin-inline-end: 1.125rem; + color: #69707a; + background-color: #fff; + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: 1px; + border-radius: 0; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-control::file-selector-button, .datatable-input::file-selector-button { + transition: none; + } +} +.form-control:hover:not(:disabled):not([readonly])::file-selector-button, .datatable-input:hover:not(:disabled):not([readonly])::file-selector-button { + background-color: #f2f2f2; +} + +.form-control-plaintext { + display: block; + width: 100%; + padding: 0.875rem 0; + margin-bottom: 0; + line-height: 1; + color: #69707a; + background-color: transparent; + border: solid transparent; + border-width: 1px 0; +} +.form-control-plaintext:focus { + outline: 0; +} +.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { + padding-right: 0; + padding-left: 0; +} + +.form-control-sm { + min-height: calc(1em + 1rem + 2px); + padding: 0.5rem 0.75rem; + font-size: 0.75rem; + border-radius: 0.25rem; +} +.form-control-sm::file-selector-button { + padding: 0.5rem 0.75rem; + margin: -0.5rem -0.75rem; + -webkit-margin-end: 0.75rem; + margin-inline-end: 0.75rem; +} + +.form-control-lg { + min-height: calc(1em + 2.25rem + 2px); + padding: 1.125rem 1.5rem; + font-size: 1rem; + border-radius: 0.5rem; +} +.form-control-lg::file-selector-button { + padding: 1.125rem 1.5rem; + margin: -1.125rem -1.5rem; + -webkit-margin-end: 1.5rem; + margin-inline-end: 1.5rem; +} + +textarea.form-control, textarea.datatable-input { + min-height: calc(1em + 1.75rem + 2px); +} +textarea.form-control-sm { + min-height: calc(1em + 1rem + 2px); +} +textarea.form-control-lg { + min-height: calc(1em + 2.25rem + 2px); +} + +.form-control-color { + width: 3rem; + height: calc(1em + 1.75rem + 2px); + padding: 0.875rem; +} +.form-control-color:not(:disabled):not([readonly]) { + cursor: pointer; +} +.form-control-color::-moz-color-swatch { + border: 0 !important; + border-radius: 0.35rem; +} +.form-control-color::-webkit-color-swatch { + border-radius: 0.35rem; +} +.form-control-color.form-control-sm { + height: calc(1em + 1rem + 2px); +} +.form-control-color.form-control-lg { + height: calc(1em + 2.25rem + 2px); +} + +.form-select, .datatable-selector { + display: block; + width: 100%; + padding: 0.875rem 3.375rem 0.875rem 1.125rem; + -moz-padding-start: calc(1.125rem - 3px); + font-size: 0.875rem; + font-weight: 400; + line-height: 1; + color: #69707a; + background-color: #fff; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23363d47' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right 1.125rem center; + background-size: 16px 12px; + border: 1px solid #c5ccd6; + border-radius: 0.35rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} +@media (prefers-reduced-motion: reduce) { + .form-select, .datatable-selector { + transition: none; + } +} +.form-select:focus, .datatable-selector:focus { + border-color: transparent; + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(0, 97, 242, 0.25); +} +.form-select[multiple], [multiple].datatable-selector, .form-select[size]:not([size="1"]), [size].datatable-selector:not([size="1"]) { + padding-right: 1.125rem; + background-image: none; +} +.form-select:disabled, .datatable-selector:disabled { + background-color: #e0e5ec; +} +.form-select:-moz-focusring, .datatable-selector:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 #69707a; +} + +.form-select-sm { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 0.75rem; + font-size: 0.75rem; + border-radius: 0.25rem; +} + +.form-select-lg { + padding-top: 1.125rem; + padding-bottom: 1.125rem; + padding-left: 1.5rem; + font-size: 1rem; + border-radius: 0.5rem; +} + +.form-check { + display: block; + min-height: 1.5rem; + padding-left: 1.5em; + margin-bottom: 0.125rem; +} +.form-check .form-check-input { + float: left; + margin-left: -1.5em; +} + +.form-check-reverse { + padding-right: 1.5em; + padding-left: 0; + text-align: right; +} +.form-check-reverse .form-check-input { + float: right; + margin-right: -1.5em; + margin-left: 0; +} + +.form-check-input { + width: 1em; + height: 1em; + margin-top: 0.25em; + vertical-align: top; + background-color: #fff; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + border: 1px solid rgba(0, 0, 0, 0.25); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-print-color-adjust: exact; + print-color-adjust: exact; +} +.form-check-input[type=checkbox] { + border-radius: 0.25em; +} +.form-check-input[type=radio] { + border-radius: 50%; +} +.form-check-input:active { + filter: brightness(90%); +} +.form-check-input:focus { + border-color: transparent; + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(0, 97, 242, 0.25); +} +.form-check-input:checked { + background-color: #0061f2; + border-color: #0061f2; +} +.form-check-input:checked[type=checkbox] { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e"); +} +.form-check-input:checked[type=radio] { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e"); +} +.form-check-input[type=checkbox]:indeterminate { + background-color: #0061f2; + border-color: #0061f2; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e"); +} +.form-check-input:disabled { + pointer-events: none; + filter: none; + opacity: 0.5; +} +.form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label { + cursor: default; + opacity: 0.5; +} + +.form-switch { + padding-left: 2.5em; +} +.form-switch .form-check-input { + width: 2em; + margin-left: -2.5em; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e"); + background-position: left center; + border-radius: 2em; + transition: background-position 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-switch .form-check-input { + transition: none; + } +} +.form-switch .form-check-input:focus { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='transparent'/%3e%3c/svg%3e"); +} +.form-switch .form-check-input:checked { + background-position: right center; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e"); +} +.form-switch.form-check-reverse { + padding-right: 2.5em; + padding-left: 0; +} +.form-switch.form-check-reverse .form-check-input { + margin-right: -2.5em; + margin-left: 0; +} + +.form-check-inline { + display: inline-block; + margin-right: 1rem; +} + +.btn-check { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} +.btn-check[disabled] + .btn, .btn-check:disabled + .btn { + pointer-events: none; + filter: none; + opacity: 0.65; +} + +.form-range { + width: 100%; + height: 1.5rem; + padding: 0; + background-color: transparent; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} +.form-range:focus { + outline: 0; +} +.form-range:focus::-webkit-slider-thumb { + box-shadow: 0 0 0 1px #f2f6fc, 0 0 0 0.25rem rgba(0, 97, 242, 0.25); +} +.form-range:focus::-moz-range-thumb { + box-shadow: 0 0 0 1px #f2f6fc, 0 0 0 0.25rem rgba(0, 97, 242, 0.25); +} +.form-range::-moz-focus-outer { + border: 0; +} +.form-range::-webkit-slider-thumb { + width: 1rem; + height: 1rem; + margin-top: -0.25rem; + background-color: #0061f2; + border: 0; + border-radius: 1rem; + -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + -webkit-appearance: none; + appearance: none; +} +@media (prefers-reduced-motion: reduce) { + .form-range::-webkit-slider-thumb { + -webkit-transition: none; + transition: none; + } +} +.form-range::-webkit-slider-thumb:active { + background-color: #b3d0fb; +} +.form-range::-webkit-slider-runnable-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #d4dae3; + border-color: transparent; + border-radius: 1rem; +} +.form-range::-moz-range-thumb { + width: 1rem; + height: 1rem; + background-color: #0061f2; + border: 0; + border-radius: 1rem; + -moz-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + -moz-appearance: none; + appearance: none; +} +@media (prefers-reduced-motion: reduce) { + .form-range::-moz-range-thumb { + -moz-transition: none; + transition: none; + } +} +.form-range::-moz-range-thumb:active { + background-color: #b3d0fb; +} +.form-range::-moz-range-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #d4dae3; + border-color: transparent; + border-radius: 1rem; +} +.form-range:disabled { + pointer-events: none; +} +.form-range:disabled::-webkit-slider-thumb { + background-color: #a7aeb8; +} +.form-range:disabled::-moz-range-thumb { + background-color: #a7aeb8; +} + +.form-floating { + position: relative; +} +.form-floating > .form-control, .form-floating > .datatable-input, +.form-floating > .form-control-plaintext, +.form-floating > .form-select, +.form-floating > .datatable-selector { + height: calc(3.5rem + 2px); + line-height: 1.25; +} +.form-floating > label { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + padding: 1rem 1.125rem; + overflow: hidden; + text-align: start; + text-overflow: ellipsis; + white-space: nowrap; + pointer-events: none; + border: 1px solid transparent; + transform-origin: 0 0; + transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .form-floating > label { + transition: none; + } +} +.form-floating > .form-control, .form-floating > .datatable-input, +.form-floating > .form-control-plaintext { + padding: 1rem 1.125rem; +} +.form-floating > .form-control::-moz-placeholder, .form-floating > .datatable-input::-moz-placeholder, .form-floating > .form-control-plaintext::-moz-placeholder { + color: transparent; +} +.form-floating > .form-control::placeholder, .form-floating > .datatable-input::placeholder, +.form-floating > .form-control-plaintext::placeholder { + color: transparent; +} +.form-floating > .form-control:not(:-moz-placeholder-shown), .form-floating > .datatable-input:not(:-moz-placeholder-shown), .form-floating > .form-control-plaintext:not(:-moz-placeholder-shown) { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} +.form-floating > .form-control:focus, .form-floating > .datatable-input:focus, .form-floating > .form-control:not(:placeholder-shown), .form-floating > .datatable-input:not(:placeholder-shown), +.form-floating > .form-control-plaintext:focus, +.form-floating > .form-control-plaintext:not(:placeholder-shown) { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} +.form-floating > .form-control:-webkit-autofill, .form-floating > .datatable-input:-webkit-autofill, +.form-floating > .form-control-plaintext:-webkit-autofill { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} +.form-floating > .form-select, .form-floating > .datatable-selector { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} +.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label, .form-floating > .datatable-input:not(:-moz-placeholder-shown) ~ label { + opacity: 0.65; + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} +.form-floating > .form-control:focus ~ label, .form-floating > .datatable-input:focus ~ label, +.form-floating > .form-control:not(:placeholder-shown) ~ label, +.form-floating > .datatable-input:not(:placeholder-shown) ~ label, +.form-floating > .form-control-plaintext ~ label, +.form-floating > .form-select ~ label, +.form-floating > .datatable-selector ~ label { + opacity: 0.65; + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} +.form-floating > .form-control:-webkit-autofill ~ label, .form-floating > .datatable-input:-webkit-autofill ~ label { + opacity: 0.65; + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} +.form-floating > .form-control-plaintext ~ label { + border-width: 1px 0; +} + +.input-group { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: stretch; + width: 100%; +} +.input-group > .form-control, .input-group > .datatable-input, +.input-group > .form-select, +.input-group > .datatable-selector, +.input-group > .form-floating { + position: relative; + flex: 1 1 auto; + width: 1%; + min-width: 0; +} +.input-group > .form-control:focus, .input-group > .datatable-input:focus, +.input-group > .form-select:focus, +.input-group > .datatable-selector:focus, +.input-group > .form-floating:focus-within { + z-index: 5; +} +.input-group .btn { + position: relative; + z-index: 2; +} +.input-group .btn:focus { + z-index: 5; +} + +.input-group-text { + display: flex; + align-items: center; + padding: 0.875rem 1.125rem; + font-size: 0.875rem; + font-weight: 400; + line-height: 1; + color: #69707a; + text-align: center; + white-space: nowrap; + background-color: #fff; + border: 1px solid #c5ccd6; + border-radius: 0.35rem; +} + +.input-group-lg > .form-control, .input-group-lg > .datatable-input, +.input-group-lg > .form-select, +.input-group-lg > .datatable-selector, +.input-group-lg > .input-group-text, +.input-group-lg > .btn { + padding: 1.125rem 1.5rem; + font-size: 1rem; + border-radius: 0.5rem; +} + +.input-group-sm > .form-control, .input-group-sm > .datatable-input, +.input-group-sm > .form-select, +.input-group-sm > .datatable-selector, +.input-group-sm > .input-group-text, +.input-group-sm > .btn { + padding: 0.5rem 0.75rem; + font-size: 0.75rem; + border-radius: 0.25rem; +} + +.input-group-lg > .form-select, .input-group-lg > .datatable-selector, +.input-group-sm > .form-select, +.input-group-sm > .datatable-selector { + padding-right: 4.5rem; +} + +.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), +.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3), +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-control, +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .datatable-input, +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .form-select, +.input-group:not(.has-validation) > .form-floating:not(:last-child) > .datatable-selector { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), +.input-group.has-validation > .dropdown-toggle:nth-last-child(n+4), +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-control, +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .datatable-input, +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .form-select, +.input-group.has-validation > .form-floating:nth-last-child(n+3) > .datatable-selector { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) { + margin-left: -1px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.input-group > .form-floating:not(:first-child) > .form-control, .input-group > .form-floating:not(:first-child) > .datatable-input, +.input-group > .form-floating:not(:first-child) > .form-select, +.input-group > .form-floating:not(:first-child) > .datatable-selector { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.valid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 0.875em; + color: #00ac69; +} + +.valid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: 0.1rem; + font-size: 0.875rem; + color: #fff; + background-color: rgba(0, 172, 105, 0.9); + border-radius: 0.35rem; +} + +.was-validated :valid ~ .valid-feedback, +.was-validated :valid ~ .valid-tooltip, +.is-valid ~ .valid-feedback, +.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .form-control:valid, .was-validated .datatable-input:valid, .form-control.is-valid, .is-valid.datatable-input { + border-color: #00ac69; + padding-right: calc(1em + 1.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2300ac69' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.25em + 0.4375rem) center; + background-size: calc(0.5em + 0.875rem) calc(0.5em + 0.875rem); +} +.was-validated .form-control:valid:focus, .was-validated .datatable-input:valid:focus, .form-control.is-valid:focus, .is-valid.datatable-input:focus { + border-color: #00ac69; + box-shadow: 0 0 0 0.25rem rgba(0, 172, 105, 0.25); +} + +.was-validated textarea.form-control:valid, .was-validated textarea.datatable-input:valid, textarea.form-control.is-valid, textarea.is-valid.datatable-input { + padding-right: calc(1em + 1.75rem); + background-position: top calc(0.25em + 0.4375rem) right calc(0.25em + 0.4375rem); +} + +.was-validated .form-select:valid, .was-validated .datatable-selector:valid, .form-select.is-valid, .is-valid.datatable-selector { + border-color: #00ac69; +} +.was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .datatable-selector:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size="1"], .was-validated .datatable-selector:valid:not([multiple])[size="1"], .form-select.is-valid:not([multiple]):not([size]), .is-valid.datatable-selector:not([multiple]):not([size]), .form-select.is-valid:not([multiple])[size="1"], .is-valid.datatable-selector:not([multiple])[size="1"] { + padding-right: 6.1875rem; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23363d47' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"), url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2300ac69' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"); + background-position: right 1.125rem center, center right 3.375rem; + background-size: 16px 12px, calc(0.5em + 0.875rem) calc(0.5em + 0.875rem); +} +.was-validated .form-select:valid:focus, .was-validated .datatable-selector:valid:focus, .form-select.is-valid:focus, .is-valid.datatable-selector:focus { + border-color: #00ac69; + box-shadow: 0 0 0 0.25rem rgba(0, 172, 105, 0.25); +} + +.was-validated .form-control-color:valid, .form-control-color.is-valid { + width: calc(3rem + calc(1em + 1.75rem)); +} + +.was-validated .form-check-input:valid, .form-check-input.is-valid { + border-color: #00ac69; +} +.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked { + background-color: #00ac69; +} +.was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus { + box-shadow: 0 0 0 0.25rem rgba(0, 172, 105, 0.25); +} +.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { + color: #00ac69; +} + +.form-check-inline .form-check-input ~ .valid-feedback { + margin-left: 0.5em; +} + +.was-validated .input-group > .form-control:not(:focus):valid, .was-validated .input-group > .datatable-input:not(:focus):valid, .input-group > .form-control:not(:focus).is-valid, .input-group > .datatable-input:not(:focus).is-valid, +.was-validated .input-group > .form-select:not(:focus):valid, +.was-validated .input-group > .datatable-selector:not(:focus):valid, +.input-group > .form-select:not(:focus).is-valid, +.input-group > .datatable-selector:not(:focus).is-valid, +.was-validated .input-group > .form-floating:not(:focus-within):valid, +.input-group > .form-floating:not(:focus-within).is-valid { + z-index: 3; +} + +.invalid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 0.875em; + color: #e81500; +} + +.invalid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: 0.1rem; + font-size: 0.875rem; + color: #fff; + background-color: rgba(232, 21, 0, 0.9); + border-radius: 0.35rem; +} + +.was-validated :invalid ~ .invalid-feedback, +.was-validated :invalid ~ .invalid-tooltip, +.is-invalid ~ .invalid-feedback, +.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .form-control:invalid, .was-validated .datatable-input:invalid, .form-control.is-invalid, .is-invalid.datatable-input { + border-color: #e81500; + padding-right: calc(1em + 1.75rem); + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23e81500'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23e81500' stroke='none'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right calc(0.25em + 0.4375rem) center; + background-size: calc(0.5em + 0.875rem) calc(0.5em + 0.875rem); +} +.was-validated .form-control:invalid:focus, .was-validated .datatable-input:invalid:focus, .form-control.is-invalid:focus, .is-invalid.datatable-input:focus { + border-color: #e81500; + box-shadow: 0 0 0 0.25rem rgba(232, 21, 0, 0.25); +} + +.was-validated textarea.form-control:invalid, .was-validated textarea.datatable-input:invalid, textarea.form-control.is-invalid, textarea.is-invalid.datatable-input { + padding-right: calc(1em + 1.75rem); + background-position: top calc(0.25em + 0.4375rem) right calc(0.25em + 0.4375rem); +} + +.was-validated .form-select:invalid, .was-validated .datatable-selector:invalid, .form-select.is-invalid, .is-invalid.datatable-selector { + border-color: #e81500; +} +.was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .datatable-selector:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size="1"], .was-validated .datatable-selector:invalid:not([multiple])[size="1"], .form-select.is-invalid:not([multiple]):not([size]), .is-invalid.datatable-selector:not([multiple]):not([size]), .form-select.is-invalid:not([multiple])[size="1"], .is-invalid.datatable-selector:not([multiple])[size="1"] { + padding-right: 6.1875rem; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23363d47' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"), url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23e81500'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23e81500' stroke='none'/%3e%3c/svg%3e"); + background-position: right 1.125rem center, center right 3.375rem; + background-size: 16px 12px, calc(0.5em + 0.875rem) calc(0.5em + 0.875rem); +} +.was-validated .form-select:invalid:focus, .was-validated .datatable-selector:invalid:focus, .form-select.is-invalid:focus, .is-invalid.datatable-selector:focus { + border-color: #e81500; + box-shadow: 0 0 0 0.25rem rgba(232, 21, 0, 0.25); +} + +.was-validated .form-control-color:invalid, .form-control-color.is-invalid { + width: calc(3rem + calc(1em + 1.75rem)); +} + +.was-validated .form-check-input:invalid, .form-check-input.is-invalid { + border-color: #e81500; +} +.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked { + background-color: #e81500; +} +.was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus { + box-shadow: 0 0 0 0.25rem rgba(232, 21, 0, 0.25); +} +.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { + color: #e81500; +} + +.form-check-inline .form-check-input ~ .invalid-feedback { + margin-left: 0.5em; +} + +.was-validated .input-group > .form-control:not(:focus):invalid, .was-validated .input-group > .datatable-input:not(:focus):invalid, .input-group > .form-control:not(:focus).is-invalid, .input-group > .datatable-input:not(:focus).is-invalid, +.was-validated .input-group > .form-select:not(:focus):invalid, +.was-validated .input-group > .datatable-selector:not(:focus):invalid, +.input-group > .form-select:not(:focus).is-invalid, +.input-group > .datatable-selector:not(:focus).is-invalid, +.was-validated .input-group > .form-floating:not(:focus-within):invalid, +.input-group > .form-floating:not(:focus-within).is-invalid { + z-index: 4; +} + +.btn { + --bs-btn-padding-x: 1.125rem; + --bs-btn-padding-y: 0.875rem; + --bs-btn-font-family: ; + --bs-btn-font-size: 0.875rem; + --bs-btn-font-weight: 400; + --bs-btn-line-height: 1; + --bs-btn-color: #69707a; + --bs-btn-bg: transparent; + --bs-btn-border-width: 1px; + --bs-btn-border-color: transparent; + --bs-btn-border-radius: 0.35rem; + --bs-btn-hover-border-color: transparent; + --bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075); + --bs-btn-disabled-opacity: 0.65; + --bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5); + display: inline-block; + padding: var(--bs-btn-padding-y) var(--bs-btn-padding-x); + font-family: var(--bs-btn-font-family); + font-size: var(--bs-btn-font-size); + font-weight: var(--bs-btn-font-weight); + line-height: var(--bs-btn-line-height); + color: var(--bs-btn-color); + text-align: center; + vertical-align: middle; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + border: var(--bs-btn-border-width) solid var(--bs-btn-border-color); + border-radius: var(--bs-btn-border-radius); + background-color: var(--bs-btn-bg); + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .btn { + transition: none; + } +} +.btn:hover { + color: var(--bs-btn-hover-color); + text-decoration: none; + background-color: var(--bs-btn-hover-bg); + border-color: var(--bs-btn-hover-border-color); +} +.btn-check + .btn:hover { + color: var(--bs-btn-color); + background-color: var(--bs-btn-bg); + border-color: var(--bs-btn-border-color); +} +.btn:focus-visible { + color: var(--bs-btn-hover-color); + background-color: var(--bs-btn-hover-bg); + border-color: var(--bs-btn-hover-border-color); + outline: 0; + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn-check:focus-visible + .btn { + border-color: var(--bs-btn-hover-border-color); + outline: 0; + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn-check:checked + .btn, :not(.btn-check) + .btn:active, .btn:first-child:active, .btn.active, .btn.show { + color: var(--bs-btn-active-color); + background-color: var(--bs-btn-active-bg); + border-color: var(--bs-btn-active-border-color); +} +.btn-check:checked + .btn:focus-visible, :not(.btn-check) + .btn:active:focus-visible, .btn:first-child:active:focus-visible, .btn.active:focus-visible, .btn.show:focus-visible { + box-shadow: var(--bs-btn-focus-box-shadow); +} +.btn:disabled, .btn.disabled, fieldset:disabled .btn { + color: var(--bs-btn-disabled-color); + pointer-events: none; + background-color: var(--bs-btn-disabled-bg); + border-color: var(--bs-btn-disabled-border-color); + opacity: var(--bs-btn-disabled-opacity); +} + +.btn-primary { + --bs-btn-color: #fff; + --bs-btn-bg: #0061f2; + --bs-btn-border-color: #0061f2; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #0052ce; + --bs-btn-hover-border-color: #004ec2; + --bs-btn-focus-shadow-rgb: 38, 121, 244; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #004ec2; + --bs-btn-active-border-color: #0049b6; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #0061f2; + --bs-btn-disabled-border-color: #0061f2; +} + +.btn-secondary { + --bs-btn-color: #fff; + --bs-btn-bg: #6900c7; + --bs-btn-border-color: #6900c7; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #5900a9; + --bs-btn-hover-border-color: #54009f; + --bs-btn-focus-shadow-rgb: 128, 38, 207; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #54009f; + --bs-btn-active-border-color: #4f0095; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #6900c7; + --bs-btn-disabled-border-color: #6900c7; +} + +.btn-success { + --bs-btn-color: #fff; + --bs-btn-bg: #00ac69; + --bs-btn-border-color: #00ac69; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #009259; + --bs-btn-hover-border-color: #008a54; + --bs-btn-focus-shadow-rgb: 38, 184, 128; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #008a54; + --bs-btn-active-border-color: #00814f; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #00ac69; + --bs-btn-disabled-border-color: #00ac69; +} + +.btn-info { + --bs-btn-color: #fff; + --bs-btn-bg: #00cfd5; + --bs-btn-border-color: #00cfd5; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #00b0b5; + --bs-btn-hover-border-color: #00a6aa; + --bs-btn-focus-shadow-rgb: 38, 214, 219; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #00a6aa; + --bs-btn-active-border-color: #009ba0; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #00cfd5; + --bs-btn-disabled-border-color: #00cfd5; +} + +.btn-warning { + --bs-btn-color: #fff; + --bs-btn-bg: #f4a100; + --bs-btn-border-color: #f4a100; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #cf8900; + --bs-btn-hover-border-color: #c38100; + --bs-btn-focus-shadow-rgb: 246, 175, 38; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #c38100; + --bs-btn-active-border-color: #b77900; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #f4a100; + --bs-btn-disabled-border-color: #f4a100; +} + +.btn-danger { + --bs-btn-color: #fff; + --bs-btn-bg: #e81500; + --bs-btn-border-color: #e81500; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #c51200; + --bs-btn-hover-border-color: #ba1100; + --bs-btn-focus-shadow-rgb: 235, 56, 38; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #ba1100; + --bs-btn-active-border-color: #ae1000; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #e81500; + --bs-btn-disabled-border-color: #e81500; +} + +.btn-light { + --bs-btn-color: #000; + --bs-btn-bg: #f2f6fc; + --bs-btn-border-color: #f2f6fc; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #ced1d6; + --bs-btn-hover-border-color: #c2c5ca; + --bs-btn-focus-shadow-rgb: 206, 209, 214; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #c2c5ca; + --bs-btn-active-border-color: #b6b9bd; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #f2f6fc; + --bs-btn-disabled-border-color: #f2f6fc; +} + +.btn-dark { + --bs-btn-color: #fff; + --bs-btn-bg: #212832; + --bs-btn-border-color: #212832; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #424851; + --bs-btn-hover-border-color: #373e47; + --bs-btn-focus-shadow-rgb: 66, 72, 81; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #4d535b; + --bs-btn-active-border-color: #373e47; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #212832; + --bs-btn-disabled-border-color: #212832; +} + +.btn-black { + --bs-btn-color: #fff; + --bs-btn-bg: #000; + --bs-btn-border-color: #000; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: black; + --bs-btn-hover-border-color: black; + --bs-btn-focus-shadow-rgb: 38, 38, 38; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: black; + --bs-btn-active-border-color: black; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #000; + --bs-btn-disabled-border-color: #000; +} + +.btn-white { + --bs-btn-color: #000; + --bs-btn-bg: #fff; + --bs-btn-border-color: #fff; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: white; + --bs-btn-hover-border-color: white; + --bs-btn-focus-shadow-rgb: 217, 217, 217; + --bs-btn-active-color: #000; + --bs-btn-active-bg: white; + --bs-btn-active-border-color: white; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #fff; + --bs-btn-disabled-border-color: #fff; +} + +.btn-red { + --bs-btn-color: #fff; + --bs-btn-bg: #e81500; + --bs-btn-border-color: #e81500; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #c51200; + --bs-btn-hover-border-color: #ba1100; + --bs-btn-focus-shadow-rgb: 235, 56, 38; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #ba1100; + --bs-btn-active-border-color: #ae1000; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #e81500; + --bs-btn-disabled-border-color: #e81500; +} + +.btn-orange { + --bs-btn-color: #fff; + --bs-btn-bg: #f76400; + --bs-btn-border-color: #f76400; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #d25500; + --bs-btn-hover-border-color: #c65000; + --bs-btn-focus-shadow-rgb: 248, 123, 38; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #c65000; + --bs-btn-active-border-color: #b94b00; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #f76400; + --bs-btn-disabled-border-color: #f76400; +} + +.btn-yellow { + --bs-btn-color: #fff; + --bs-btn-bg: #f4a100; + --bs-btn-border-color: #f4a100; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #cf8900; + --bs-btn-hover-border-color: #c38100; + --bs-btn-focus-shadow-rgb: 246, 175, 38; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #c38100; + --bs-btn-active-border-color: #b77900; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #f4a100; + --bs-btn-disabled-border-color: #f4a100; +} + +.btn-green { + --bs-btn-color: #fff; + --bs-btn-bg: #00ac69; + --bs-btn-border-color: #00ac69; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #009259; + --bs-btn-hover-border-color: #008a54; + --bs-btn-focus-shadow-rgb: 38, 184, 128; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #008a54; + --bs-btn-active-border-color: #00814f; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #00ac69; + --bs-btn-disabled-border-color: #00ac69; +} + +.btn-teal { + --bs-btn-color: #fff; + --bs-btn-bg: #00ba94; + --bs-btn-border-color: #00ba94; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #009e7e; + --bs-btn-hover-border-color: #009576; + --bs-btn-focus-shadow-rgb: 38, 196, 164; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #009576; + --bs-btn-active-border-color: #008c6f; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #00ba94; + --bs-btn-disabled-border-color: #00ba94; +} + +.btn-cyan { + --bs-btn-color: #fff; + --bs-btn-bg: #00cfd5; + --bs-btn-border-color: #00cfd5; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #00b0b5; + --bs-btn-hover-border-color: #00a6aa; + --bs-btn-focus-shadow-rgb: 38, 214, 219; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #00a6aa; + --bs-btn-active-border-color: #009ba0; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #00cfd5; + --bs-btn-disabled-border-color: #00cfd5; +} + +.btn-blue { + --bs-btn-color: #fff; + --bs-btn-bg: #0061f2; + --bs-btn-border-color: #0061f2; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #0052ce; + --bs-btn-hover-border-color: #004ec2; + --bs-btn-focus-shadow-rgb: 38, 121, 244; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #004ec2; + --bs-btn-active-border-color: #0049b6; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #0061f2; + --bs-btn-disabled-border-color: #0061f2; +} + +.btn-indigo { + --bs-btn-color: #fff; + --bs-btn-bg: #5800e8; + --bs-btn-border-color: #5800e8; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #4b00c5; + --bs-btn-hover-border-color: #4600ba; + --bs-btn-focus-shadow-rgb: 113, 38, 235; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #4600ba; + --bs-btn-active-border-color: #4200ae; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #5800e8; + --bs-btn-disabled-border-color: #5800e8; +} + +.btn-purple { + --bs-btn-color: #fff; + --bs-btn-bg: #6900c7; + --bs-btn-border-color: #6900c7; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #5900a9; + --bs-btn-hover-border-color: #54009f; + --bs-btn-focus-shadow-rgb: 128, 38, 207; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #54009f; + --bs-btn-active-border-color: #4f0095; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #6900c7; + --bs-btn-disabled-border-color: #6900c7; +} + +.btn-pink { + --bs-btn-color: #fff; + --bs-btn-bg: #e30059; + --bs-btn-border-color: #e30059; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #c1004c; + --bs-btn-hover-border-color: #b60047; + --bs-btn-focus-shadow-rgb: 231, 38, 114; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #b60047; + --bs-btn-active-border-color: #aa0043; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #e30059; + --bs-btn-disabled-border-color: #e30059; +} + +.btn-red-soft { + --bs-btn-color: #000; + --bs-btn-bg: #f1e0e3; + --bs-btn-border-color: #f1e0e3; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f3e5e7; + --bs-btn-hover-border-color: #f2e3e6; + --bs-btn-focus-shadow-rgb: 205, 190, 193; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f4e6e9; + --bs-btn-active-border-color: #f2e3e6; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #f1e0e3; + --bs-btn-disabled-border-color: #f1e0e3; +} + +.btn-orange-soft { + --bs-btn-color: #000; + --bs-btn-bg: #f3e7e3; + --bs-btn-border-color: #f3e7e3; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f5ebe7; + --bs-btn-hover-border-color: #f4e9e6; + --bs-btn-focus-shadow-rgb: 207, 196, 193; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f5ece9; + --bs-btn-active-border-color: #f4e9e6; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #f3e7e3; + --bs-btn-disabled-border-color: #f3e7e3; +} + +.btn-yellow-soft { + --bs-btn-color: #000; + --bs-btn-bg: #f2eee3; + --bs-btn-border-color: #f2eee3; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f4f1e7; + --bs-btn-hover-border-color: #f3f0e6; + --bs-btn-focus-shadow-rgb: 206, 202, 193; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f5f1e9; + --bs-btn-active-border-color: #f3f0e6; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #f2eee3; + --bs-btn-disabled-border-color: #f2eee3; +} + +.btn-green-soft { + --bs-btn-color: #000; + --bs-btn-bg: #daefed; + --bs-btn-border-color: #daefed; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e0f1f0; + --bs-btn-hover-border-color: #def1ef; + --bs-btn-focus-shadow-rgb: 185, 203, 201; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e1f2f1; + --bs-btn-active-border-color: #def1ef; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #daefed; + --bs-btn-disabled-border-color: #daefed; +} + +.btn-teal-soft { + --bs-btn-color: #000; + --bs-btn-bg: #daf0f2; + --bs-btn-border-color: #daf0f2; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e0f2f4; + --bs-btn-hover-border-color: #def2f3; + --bs-btn-focus-shadow-rgb: 185, 204, 206; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e1f3f5; + --bs-btn-active-border-color: #def2f3; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #daf0f2; + --bs-btn-disabled-border-color: #daf0f2; +} + +.btn-cyan-soft { + --bs-btn-color: #000; + --bs-btn-bg: #daf2f8; + --bs-btn-border-color: #daf2f8; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e0f4f9; + --bs-btn-hover-border-color: #def3f9; + --bs-btn-focus-shadow-rgb: 185, 206, 211; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e1f5f9; + --bs-btn-active-border-color: #def3f9; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #daf2f8; + --bs-btn-disabled-border-color: #daf2f8; +} + +.btn-blue-soft { + --bs-btn-color: #000; + --bs-btn-bg: #dae7fb; + --bs-btn-border-color: #dae7fb; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e0ebfc; + --bs-btn-hover-border-color: #dee9fb; + --bs-btn-focus-shadow-rgb: 185, 196, 213; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e1ecfc; + --bs-btn-active-border-color: #dee9fb; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #dae7fb; + --bs-btn-disabled-border-color: #dae7fb; +} + +.btn-indigo-soft { + --bs-btn-color: #000; + --bs-btn-bg: #e3ddfa; + --bs-btn-border-color: #e3ddfa; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e7e2fb; + --bs-btn-hover-border-color: #e6e0fb; + --bs-btn-focus-shadow-rgb: 193, 188, 213; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e9e4fb; + --bs-btn-active-border-color: #e6e0fb; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #e3ddfa; + --bs-btn-disabled-border-color: #e3ddfa; +} + +.btn-purple-soft { + --bs-btn-color: #000; + --bs-btn-bg: #e4ddf7; + --bs-btn-border-color: #e4ddf7; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e8e2f8; + --bs-btn-hover-border-color: #e7e0f8; + --bs-btn-focus-shadow-rgb: 194, 188, 210; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e9e4f9; + --bs-btn-active-border-color: #e7e0f8; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #e4ddf7; + --bs-btn-disabled-border-color: #e4ddf7; +} + +.btn-pink-soft { + --bs-btn-color: #000; + --bs-btn-bg: #f1ddec; + --bs-btn-border-color: #f1ddec; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f3e2ef; + --bs-btn-hover-border-color: #f2e0ee; + --bs-btn-focus-shadow-rgb: 205, 188, 201; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f4e4f0; + --bs-btn-active-border-color: #f2e0ee; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #f1ddec; + --bs-btn-disabled-border-color: #f1ddec; +} + +.btn-primary-soft { + --bs-btn-color: #000; + --bs-btn-bg: #dae7fb; + --bs-btn-border-color: #dae7fb; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e0ebfc; + --bs-btn-hover-border-color: #dee9fb; + --bs-btn-focus-shadow-rgb: 185, 196, 213; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e1ecfc; + --bs-btn-active-border-color: #dee9fb; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #dae7fb; + --bs-btn-disabled-border-color: #dae7fb; +} + +.btn-secondary-soft { + --bs-btn-color: #000; + --bs-btn-bg: #e4ddf7; + --bs-btn-border-color: #e4ddf7; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e8e2f8; + --bs-btn-hover-border-color: #e7e0f8; + --bs-btn-focus-shadow-rgb: 194, 188, 210; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e9e4f9; + --bs-btn-active-border-color: #e7e0f8; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #e4ddf7; + --bs-btn-disabled-border-color: #e4ddf7; +} + +.btn-success-soft { + --bs-btn-color: #000; + --bs-btn-bg: #daefed; + --bs-btn-border-color: #daefed; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e0f1f0; + --bs-btn-hover-border-color: #def1ef; + --bs-btn-focus-shadow-rgb: 185, 203, 201; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e1f2f1; + --bs-btn-active-border-color: #def1ef; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #daefed; + --bs-btn-disabled-border-color: #daefed; +} + +.btn-info-soft { + --bs-btn-color: #000; + --bs-btn-bg: #daf2f8; + --bs-btn-border-color: #daf2f8; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e0f4f9; + --bs-btn-hover-border-color: #def3f9; + --bs-btn-focus-shadow-rgb: 185, 206, 211; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e1f5f9; + --bs-btn-active-border-color: #def3f9; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #daf2f8; + --bs-btn-disabled-border-color: #daf2f8; +} + +.btn-warning-soft { + --bs-btn-color: #000; + --bs-btn-bg: #f2eee3; + --bs-btn-border-color: #f2eee3; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f4f1e7; + --bs-btn-hover-border-color: #f3f0e6; + --bs-btn-focus-shadow-rgb: 206, 202, 193; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f5f1e9; + --bs-btn-active-border-color: #f3f0e6; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #f2eee3; + --bs-btn-disabled-border-color: #f2eee3; +} + +.btn-danger-soft { + --bs-btn-color: #000; + --bs-btn-bg: #f1e0e3; + --bs-btn-border-color: #f1e0e3; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f3e5e7; + --bs-btn-hover-border-color: #f2e3e6; + --bs-btn-focus-shadow-rgb: 205, 190, 193; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f4e6e9; + --bs-btn-active-border-color: #f2e3e6; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: #f1e0e3; + --bs-btn-disabled-border-color: #f1e0e3; +} + +.btn-outline-primary { + --bs-btn-color: #0061f2; + --bs-btn-border-color: #0061f2; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #0061f2; + --bs-btn-hover-border-color: #0061f2; + --bs-btn-focus-shadow-rgb: 0, 97, 242; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #0061f2; + --bs-btn-active-border-color: #0061f2; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #0061f2; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0061f2; + --bs-gradient: none; +} + +.btn-outline-secondary { + --bs-btn-color: #6900c7; + --bs-btn-border-color: #6900c7; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #6900c7; + --bs-btn-hover-border-color: #6900c7; + --bs-btn-focus-shadow-rgb: 105, 0, 199; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #6900c7; + --bs-btn-active-border-color: #6900c7; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #6900c7; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #6900c7; + --bs-gradient: none; +} + +.btn-outline-success { + --bs-btn-color: #00ac69; + --bs-btn-border-color: #00ac69; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #00ac69; + --bs-btn-hover-border-color: #00ac69; + --bs-btn-focus-shadow-rgb: 0, 172, 105; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #00ac69; + --bs-btn-active-border-color: #00ac69; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #00ac69; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #00ac69; + --bs-gradient: none; +} + +.btn-outline-info { + --bs-btn-color: #00cfd5; + --bs-btn-border-color: #00cfd5; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #00cfd5; + --bs-btn-hover-border-color: #00cfd5; + --bs-btn-focus-shadow-rgb: 0, 207, 213; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #00cfd5; + --bs-btn-active-border-color: #00cfd5; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #00cfd5; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #00cfd5; + --bs-gradient: none; +} + +.btn-outline-warning { + --bs-btn-color: #f4a100; + --bs-btn-border-color: #f4a100; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #f4a100; + --bs-btn-hover-border-color: #f4a100; + --bs-btn-focus-shadow-rgb: 244, 161, 0; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #f4a100; + --bs-btn-active-border-color: #f4a100; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f4a100; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f4a100; + --bs-gradient: none; +} + +.btn-outline-danger { + --bs-btn-color: #e81500; + --bs-btn-border-color: #e81500; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #e81500; + --bs-btn-hover-border-color: #e81500; + --bs-btn-focus-shadow-rgb: 232, 21, 0; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #e81500; + --bs-btn-active-border-color: #e81500; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #e81500; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #e81500; + --bs-gradient: none; +} + +.btn-outline-light { + --bs-btn-color: #f2f6fc; + --bs-btn-border-color: #f2f6fc; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f2f6fc; + --bs-btn-hover-border-color: #f2f6fc; + --bs-btn-focus-shadow-rgb: 242, 246, 252; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f2f6fc; + --bs-btn-active-border-color: #f2f6fc; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f2f6fc; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f2f6fc; + --bs-gradient: none; +} + +.btn-outline-dark { + --bs-btn-color: #212832; + --bs-btn-border-color: #212832; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #212832; + --bs-btn-hover-border-color: #212832; + --bs-btn-focus-shadow-rgb: 33, 40, 50; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #212832; + --bs-btn-active-border-color: #212832; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #212832; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #212832; + --bs-gradient: none; +} + +.btn-outline-black { + --bs-btn-color: #000; + --bs-btn-border-color: #000; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #000; + --bs-btn-hover-border-color: #000; + --bs-btn-focus-shadow-rgb: 0, 0, 0; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #000; + --bs-btn-active-border-color: #000; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #000; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #000; + --bs-gradient: none; +} + +.btn-outline-white { + --bs-btn-color: #fff; + --bs-btn-border-color: #fff; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #fff; + --bs-btn-hover-border-color: #fff; + --bs-btn-focus-shadow-rgb: 255, 255, 255; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #fff; + --bs-btn-active-border-color: #fff; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #fff; + --bs-gradient: none; +} + +.btn-outline-red { + --bs-btn-color: #e81500; + --bs-btn-border-color: #e81500; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #e81500; + --bs-btn-hover-border-color: #e81500; + --bs-btn-focus-shadow-rgb: 232, 21, 0; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #e81500; + --bs-btn-active-border-color: #e81500; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #e81500; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #e81500; + --bs-gradient: none; +} + +.btn-outline-orange { + --bs-btn-color: #f76400; + --bs-btn-border-color: #f76400; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #f76400; + --bs-btn-hover-border-color: #f76400; + --bs-btn-focus-shadow-rgb: 247, 100, 0; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #f76400; + --bs-btn-active-border-color: #f76400; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f76400; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f76400; + --bs-gradient: none; +} + +.btn-outline-yellow { + --bs-btn-color: #f4a100; + --bs-btn-border-color: #f4a100; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #f4a100; + --bs-btn-hover-border-color: #f4a100; + --bs-btn-focus-shadow-rgb: 244, 161, 0; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #f4a100; + --bs-btn-active-border-color: #f4a100; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f4a100; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f4a100; + --bs-gradient: none; +} + +.btn-outline-green { + --bs-btn-color: #00ac69; + --bs-btn-border-color: #00ac69; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #00ac69; + --bs-btn-hover-border-color: #00ac69; + --bs-btn-focus-shadow-rgb: 0, 172, 105; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #00ac69; + --bs-btn-active-border-color: #00ac69; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #00ac69; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #00ac69; + --bs-gradient: none; +} + +.btn-outline-teal { + --bs-btn-color: #00ba94; + --bs-btn-border-color: #00ba94; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #00ba94; + --bs-btn-hover-border-color: #00ba94; + --bs-btn-focus-shadow-rgb: 0, 186, 148; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #00ba94; + --bs-btn-active-border-color: #00ba94; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #00ba94; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #00ba94; + --bs-gradient: none; +} + +.btn-outline-cyan { + --bs-btn-color: #00cfd5; + --bs-btn-border-color: #00cfd5; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #00cfd5; + --bs-btn-hover-border-color: #00cfd5; + --bs-btn-focus-shadow-rgb: 0, 207, 213; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #00cfd5; + --bs-btn-active-border-color: #00cfd5; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #00cfd5; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #00cfd5; + --bs-gradient: none; +} + +.btn-outline-blue { + --bs-btn-color: #0061f2; + --bs-btn-border-color: #0061f2; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #0061f2; + --bs-btn-hover-border-color: #0061f2; + --bs-btn-focus-shadow-rgb: 0, 97, 242; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #0061f2; + --bs-btn-active-border-color: #0061f2; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #0061f2; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #0061f2; + --bs-gradient: none; +} + +.btn-outline-indigo { + --bs-btn-color: #5800e8; + --bs-btn-border-color: #5800e8; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #5800e8; + --bs-btn-hover-border-color: #5800e8; + --bs-btn-focus-shadow-rgb: 88, 0, 232; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #5800e8; + --bs-btn-active-border-color: #5800e8; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #5800e8; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #5800e8; + --bs-gradient: none; +} + +.btn-outline-purple { + --bs-btn-color: #6900c7; + --bs-btn-border-color: #6900c7; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #6900c7; + --bs-btn-hover-border-color: #6900c7; + --bs-btn-focus-shadow-rgb: 105, 0, 199; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #6900c7; + --bs-btn-active-border-color: #6900c7; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #6900c7; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #6900c7; + --bs-gradient: none; +} + +.btn-outline-pink { + --bs-btn-color: #e30059; + --bs-btn-border-color: #e30059; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #e30059; + --bs-btn-hover-border-color: #e30059; + --bs-btn-focus-shadow-rgb: 227, 0, 89; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #e30059; + --bs-btn-active-border-color: #e30059; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #e30059; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #e30059; + --bs-gradient: none; +} + +.btn-outline-red-soft { + --bs-btn-color: #f1e0e3; + --bs-btn-border-color: #f1e0e3; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f1e0e3; + --bs-btn-hover-border-color: #f1e0e3; + --bs-btn-focus-shadow-rgb: 241, 224, 227; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f1e0e3; + --bs-btn-active-border-color: #f1e0e3; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f1e0e3; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f1e0e3; + --bs-gradient: none; +} + +.btn-outline-orange-soft { + --bs-btn-color: #f3e7e3; + --bs-btn-border-color: #f3e7e3; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f3e7e3; + --bs-btn-hover-border-color: #f3e7e3; + --bs-btn-focus-shadow-rgb: 243, 231, 227; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f3e7e3; + --bs-btn-active-border-color: #f3e7e3; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f3e7e3; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f3e7e3; + --bs-gradient: none; +} + +.btn-outline-yellow-soft { + --bs-btn-color: #f2eee3; + --bs-btn-border-color: #f2eee3; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f2eee3; + --bs-btn-hover-border-color: #f2eee3; + --bs-btn-focus-shadow-rgb: 242, 238, 227; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f2eee3; + --bs-btn-active-border-color: #f2eee3; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f2eee3; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f2eee3; + --bs-gradient: none; +} + +.btn-outline-green-soft { + --bs-btn-color: #daefed; + --bs-btn-border-color: #daefed; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #daefed; + --bs-btn-hover-border-color: #daefed; + --bs-btn-focus-shadow-rgb: 218, 239, 237; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #daefed; + --bs-btn-active-border-color: #daefed; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #daefed; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #daefed; + --bs-gradient: none; +} + +.btn-outline-teal-soft { + --bs-btn-color: #daf0f2; + --bs-btn-border-color: #daf0f2; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #daf0f2; + --bs-btn-hover-border-color: #daf0f2; + --bs-btn-focus-shadow-rgb: 218, 240, 242; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #daf0f2; + --bs-btn-active-border-color: #daf0f2; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #daf0f2; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #daf0f2; + --bs-gradient: none; +} + +.btn-outline-cyan-soft { + --bs-btn-color: #daf2f8; + --bs-btn-border-color: #daf2f8; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #daf2f8; + --bs-btn-hover-border-color: #daf2f8; + --bs-btn-focus-shadow-rgb: 218, 242, 248; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #daf2f8; + --bs-btn-active-border-color: #daf2f8; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #daf2f8; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #daf2f8; + --bs-gradient: none; +} + +.btn-outline-blue-soft { + --bs-btn-color: #dae7fb; + --bs-btn-border-color: #dae7fb; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #dae7fb; + --bs-btn-hover-border-color: #dae7fb; + --bs-btn-focus-shadow-rgb: 218, 231, 251; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #dae7fb; + --bs-btn-active-border-color: #dae7fb; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #dae7fb; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #dae7fb; + --bs-gradient: none; +} + +.btn-outline-indigo-soft { + --bs-btn-color: #e3ddfa; + --bs-btn-border-color: #e3ddfa; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e3ddfa; + --bs-btn-hover-border-color: #e3ddfa; + --bs-btn-focus-shadow-rgb: 227, 221, 250; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e3ddfa; + --bs-btn-active-border-color: #e3ddfa; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #e3ddfa; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #e3ddfa; + --bs-gradient: none; +} + +.btn-outline-purple-soft { + --bs-btn-color: #e4ddf7; + --bs-btn-border-color: #e4ddf7; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e4ddf7; + --bs-btn-hover-border-color: #e4ddf7; + --bs-btn-focus-shadow-rgb: 228, 221, 247; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e4ddf7; + --bs-btn-active-border-color: #e4ddf7; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #e4ddf7; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #e4ddf7; + --bs-gradient: none; +} + +.btn-outline-pink-soft { + --bs-btn-color: #f1ddec; + --bs-btn-border-color: #f1ddec; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f1ddec; + --bs-btn-hover-border-color: #f1ddec; + --bs-btn-focus-shadow-rgb: 241, 221, 236; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f1ddec; + --bs-btn-active-border-color: #f1ddec; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f1ddec; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f1ddec; + --bs-gradient: none; +} + +.btn-outline-primary-soft { + --bs-btn-color: #dae7fb; + --bs-btn-border-color: #dae7fb; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #dae7fb; + --bs-btn-hover-border-color: #dae7fb; + --bs-btn-focus-shadow-rgb: 218, 231, 251; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #dae7fb; + --bs-btn-active-border-color: #dae7fb; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #dae7fb; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #dae7fb; + --bs-gradient: none; +} + +.btn-outline-secondary-soft { + --bs-btn-color: #e4ddf7; + --bs-btn-border-color: #e4ddf7; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #e4ddf7; + --bs-btn-hover-border-color: #e4ddf7; + --bs-btn-focus-shadow-rgb: 228, 221, 247; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #e4ddf7; + --bs-btn-active-border-color: #e4ddf7; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #e4ddf7; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #e4ddf7; + --bs-gradient: none; +} + +.btn-outline-success-soft { + --bs-btn-color: #daefed; + --bs-btn-border-color: #daefed; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #daefed; + --bs-btn-hover-border-color: #daefed; + --bs-btn-focus-shadow-rgb: 218, 239, 237; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #daefed; + --bs-btn-active-border-color: #daefed; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #daefed; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #daefed; + --bs-gradient: none; +} + +.btn-outline-info-soft { + --bs-btn-color: #daf2f8; + --bs-btn-border-color: #daf2f8; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #daf2f8; + --bs-btn-hover-border-color: #daf2f8; + --bs-btn-focus-shadow-rgb: 218, 242, 248; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #daf2f8; + --bs-btn-active-border-color: #daf2f8; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #daf2f8; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #daf2f8; + --bs-gradient: none; +} + +.btn-outline-warning-soft { + --bs-btn-color: #f2eee3; + --bs-btn-border-color: #f2eee3; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f2eee3; + --bs-btn-hover-border-color: #f2eee3; + --bs-btn-focus-shadow-rgb: 242, 238, 227; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f2eee3; + --bs-btn-active-border-color: #f2eee3; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f2eee3; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f2eee3; + --bs-gradient: none; +} + +.btn-outline-danger-soft { + --bs-btn-color: #f1e0e3; + --bs-btn-border-color: #f1e0e3; + --bs-btn-hover-color: #000; + --bs-btn-hover-bg: #f1e0e3; + --bs-btn-hover-border-color: #f1e0e3; + --bs-btn-focus-shadow-rgb: 241, 224, 227; + --bs-btn-active-color: #000; + --bs-btn-active-bg: #f1e0e3; + --bs-btn-active-border-color: #f1e0e3; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #f1e0e3; + --bs-btn-disabled-bg: transparent; + --bs-btn-disabled-border-color: #f1e0e3; + --bs-gradient: none; +} + +.btn-link { + --bs-btn-font-weight: 400; + --bs-btn-color: var(--bs-link-color); + --bs-btn-bg: transparent; + --bs-btn-border-color: transparent; + --bs-btn-hover-color: var(--bs-link-hover-color); + --bs-btn-hover-border-color: transparent; + --bs-btn-active-color: var(--bs-link-hover-color); + --bs-btn-active-border-color: transparent; + --bs-btn-disabled-color: #69707a; + --bs-btn-disabled-border-color: transparent; + --bs-btn-box-shadow: none; + --bs-btn-focus-shadow-rgb: 38, 121, 244; + text-decoration: none; +} +.btn-link:hover, .btn-link:focus-visible { + text-decoration: underline; +} +.btn-link:focus-visible { + color: var(--bs-btn-color); +} +.btn-link:hover { + color: var(--bs-btn-hover-color); +} + +.btn-lg, .btn-group-lg > .btn { + --bs-btn-padding-y: 1.125rem; + --bs-btn-padding-x: 1.5rem; + --bs-btn-font-size: 1rem; + --bs-btn-border-radius: 0.5rem; +} + +.btn-sm, .btn-group-sm > .btn { + --bs-btn-padding-y: 0.5rem; + --bs-btn-padding-x: 0.75rem; + --bs-btn-font-size: 0.75rem; + --bs-btn-border-radius: 0.25rem; +} + +.fade { + transition: opacity 0.15s linear; +} +@media (prefers-reduced-motion: reduce) { + .fade { + transition: none; + } +} +.fade:not(.show) { + opacity: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + height: 0; + overflow: hidden; + transition: height 0.15s ease; +} +@media (prefers-reduced-motion: reduce) { + .collapsing { + transition: none; + } +} +.collapsing.collapse-horizontal { + width: 0; + height: auto; + transition: width 0.35s ease; +} +@media (prefers-reduced-motion: reduce) { + .collapsing.collapse-horizontal { + transition: none; + } +} + +.dropup, +.dropend, +.dropdown, +.dropstart, +.dropup-center, +.dropdown-center { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; +} +.dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid; + border-right: 0.3em solid transparent; + border-bottom: 0; + border-left: 0.3em solid transparent; +} +.dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropdown-menu { + --bs-dropdown-zindex: 1000; + --bs-dropdown-min-width: 10rem; + --bs-dropdown-padding-x: 0; + --bs-dropdown-padding-y: 0.5rem; + --bs-dropdown-spacer: 0.125rem; + --bs-dropdown-font-size: 1rem; + --bs-dropdown-color: #69707a; + --bs-dropdown-bg: #fff; + --bs-dropdown-border-color: #e0e5ec; + --bs-dropdown-border-radius: 0.35rem; + --bs-dropdown-border-width: 1px; + --bs-dropdown-inner-border-radius: calc(0.35rem - 1px); + --bs-dropdown-divider-bg: #e0e5ec; + --bs-dropdown-divider-margin-y: 0.5rem; + --bs-dropdown-box-shadow: 0 0.15rem 1.75rem 0 rgba(33, 40, 50, 0.15); + --bs-dropdown-link-color: #212832; + --bs-dropdown-link-hover-color: #1e242d; + --bs-dropdown-link-hover-bg: #e0e5ec; + --bs-dropdown-link-active-color: #fff; + --bs-dropdown-link-active-bg: #0061f2; + --bs-dropdown-link-disabled-color: #a7aeb8; + --bs-dropdown-item-padding-x: 1rem; + --bs-dropdown-item-padding-y: 0.25rem; + --bs-dropdown-header-color: #69707a; + --bs-dropdown-header-padding-x: 1rem; + --bs-dropdown-header-padding-y: 0.5rem; + position: absolute; + z-index: var(--bs-dropdown-zindex); + display: none; + min-width: var(--bs-dropdown-min-width); + padding: var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x); + margin: 0; + font-size: var(--bs-dropdown-font-size); + color: var(--bs-dropdown-color); + text-align: left; + list-style: none; + background-color: var(--bs-dropdown-bg); + background-clip: padding-box; + border: var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color); + border-radius: var(--bs-dropdown-border-radius); +} +.dropdown-menu[data-bs-popper] { + top: 100%; + left: 0; + margin-top: var(--bs-dropdown-spacer); +} + +.dropdown-menu-start { + --bs-position: start; +} +.dropdown-menu-start[data-bs-popper] { + right: auto; + left: 0; +} + +.dropdown-menu-end { + --bs-position: end; +} +.dropdown-menu-end[data-bs-popper] { + right: 0; + left: auto; +} + +@media (min-width: 576px) { + .dropdown-menu-sm-start { + --bs-position: start; + } + .dropdown-menu-sm-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-sm-end { + --bs-position: end; + } + .dropdown-menu-sm-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 768px) { + .dropdown-menu-md-start { + --bs-position: start; + } + .dropdown-menu-md-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-md-end { + --bs-position: end; + } + .dropdown-menu-md-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 992px) { + .dropdown-menu-lg-start { + --bs-position: start; + } + .dropdown-menu-lg-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-lg-end { + --bs-position: end; + } + .dropdown-menu-lg-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 1200px) { + .dropdown-menu-xl-start { + --bs-position: start; + } + .dropdown-menu-xl-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-xl-end { + --bs-position: end; + } + .dropdown-menu-xl-end[data-bs-popper] { + right: 0; + left: auto; + } +} +@media (min-width: 1500px) { + .dropdown-menu-xxl-start { + --bs-position: start; + } + .dropdown-menu-xxl-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-xxl-end { + --bs-position: end; + } + .dropdown-menu-xxl-end[data-bs-popper] { + right: 0; + left: auto; + } +} +.dropup .dropdown-menu[data-bs-popper] { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: var(--bs-dropdown-spacer); +} +.dropup .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0; + border-right: 0.3em solid transparent; + border-bottom: 0.3em solid; + border-left: 0.3em solid transparent; +} +.dropup .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropend .dropdown-menu[data-bs-popper] { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: var(--bs-dropdown-spacer); +} +.dropend .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0; + border-bottom: 0.3em solid transparent; + border-left: 0.3em solid; +} +.dropend .dropdown-toggle:empty::after { + margin-left: 0; +} +.dropend .dropdown-toggle::after { + vertical-align: 0; +} + +.dropstart .dropdown-menu[data-bs-popper] { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: var(--bs-dropdown-spacer); +} +.dropstart .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; +} +.dropstart .dropdown-toggle::after { + display: none; +} +.dropstart .dropdown-toggle::before { + display: inline-block; + margin-right: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0.3em solid; + border-bottom: 0.3em solid transparent; +} +.dropstart .dropdown-toggle:empty::after { + margin-left: 0; +} +.dropstart .dropdown-toggle::before { + vertical-align: 0; +} + +.dropdown-divider { + height: 0; + margin: var(--bs-dropdown-divider-margin-y) 0; + overflow: hidden; + border-top: 1px solid var(--bs-dropdown-divider-bg); + opacity: 1; +} + +.dropdown-item { + display: block; + width: 100%; + padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x); + clear: both; + font-weight: 400; + color: var(--bs-dropdown-link-color); + text-align: inherit; + white-space: nowrap; + background-color: transparent; + border: 0; +} +.dropdown-item:hover, .dropdown-item:focus { + color: var(--bs-dropdown-link-hover-color); + text-decoration: none; + background-color: var(--bs-dropdown-link-hover-bg); +} +.dropdown-item.active, .dropdown-item:active { + color: var(--bs-dropdown-link-active-color); + text-decoration: none; + background-color: var(--bs-dropdown-link-active-bg); +} +.dropdown-item.disabled, .dropdown-item:disabled { + color: var(--bs-dropdown-link-disabled-color); + pointer-events: none; + background-color: transparent; +} + +.dropdown-menu.show { + display: block; +} + +.dropdown-header { + display: block; + padding: var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x); + margin-bottom: 0; + font-size: 0.875rem; + color: var(--bs-dropdown-header-color); + white-space: nowrap; +} + +.dropdown-item-text { + display: block; + padding: var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x); + color: var(--bs-dropdown-link-color); +} + +.dropdown-menu-dark { + --bs-dropdown-color: #d4dae3; + --bs-dropdown-bg: #363d47; + --bs-dropdown-border-color: #e0e5ec; + --bs-dropdown-box-shadow: ; + --bs-dropdown-link-color: #d4dae3; + --bs-dropdown-link-hover-color: #fff; + --bs-dropdown-divider-bg: #e0e5ec; + --bs-dropdown-link-hover-bg: rgba(255, 255, 255, 0.15); + --bs-dropdown-link-active-color: #fff; + --bs-dropdown-link-active-bg: #0061f2; + --bs-dropdown-link-disabled-color: #a7aeb8; + --bs-dropdown-header-color: #a7aeb8; +} + +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-flex; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + flex: 1 1 auto; +} +.btn-group > .btn-check:checked + .btn, +.btn-group > .btn-check:focus + .btn, +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn-check:checked + .btn, +.btn-group-vertical > .btn-check:focus + .btn, +.btn-group-vertical > .btn:hover, +.btn-group-vertical > .btn:focus, +.btn-group-vertical > .btn:active, +.btn-group-vertical > .btn.active { + z-index: 1; +} + +.btn-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} +.btn-toolbar .input-group { + width: auto; +} + +.btn-group { + border-radius: 0.35rem; +} +.btn-group > :not(.btn-check:first-child) + .btn, +.btn-group > .btn-group:not(:first-child) { + margin-left: -1px; +} +.btn-group > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group > .btn.dropdown-toggle-split:first-child, +.btn-group > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn:nth-child(n+3), +.btn-group > :not(.btn-check) + .btn, +.btn-group > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.dropdown-toggle-split { + padding-right: 0.84375rem; + padding-left: 0.84375rem; +} +.dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after { + margin-left: 0; +} +.dropstart .dropdown-toggle-split::before { + margin-right: 0; +} + +.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { + padding-right: 0.5625rem; + padding-left: 0.5625rem; +} + +.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { + padding-right: 1.125rem; + padding-left: 1.125rem; +} + +.btn-group-vertical { + flex-direction: column; + align-items: flex-start; + justify-content: center; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group { + width: 100%; +} +.btn-group-vertical > .btn:not(:first-child), +.btn-group-vertical > .btn-group:not(:first-child) { + margin-top: -1px; +} +.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group-vertical > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn ~ .btn, +.btn-group-vertical > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav { + --bs-nav-link-padding-x: 1rem; + --bs-nav-link-padding-y: 0.5rem; + --bs-nav-link-font-weight: ; + --bs-nav-link-color: var(--bs-link-color); + --bs-nav-link-hover-color: var(--bs-link-hover-color); + --bs-nav-link-disabled-color: #69707a; + display: flex; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x); + font-size: var(--bs-nav-link-font-size); + font-weight: var(--bs-nav-link-font-weight); + color: var(--bs-nav-link-color); + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .nav-link { + transition: none; + } +} +.nav-link:hover, .nav-link:focus { + color: var(--bs-nav-link-hover-color); + text-decoration: none; +} +.nav-link.disabled { + color: var(--bs-nav-link-disabled-color); + pointer-events: none; + cursor: default; +} + +.nav-tabs { + --bs-nav-tabs-border-width: 1px; + --bs-nav-tabs-border-color: #d4dae3; + --bs-nav-tabs-border-radius: 0.35rem; + --bs-nav-tabs-link-hover-border-color: #e0e5ec #e0e5ec #d4dae3; + --bs-nav-tabs-link-active-color: #4a515b; + --bs-nav-tabs-link-active-bg: #f2f6fc; + --bs-nav-tabs-link-active-border-color: #d4dae3 #d4dae3 #f2f6fc; + border-bottom: var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color); +} +.nav-tabs .nav-link { + margin-bottom: calc(-1 * var(--bs-nav-tabs-border-width)); + background: none; + border: var(--bs-nav-tabs-border-width) solid transparent; + border-top-left-radius: var(--bs-nav-tabs-border-radius); + border-top-right-radius: var(--bs-nav-tabs-border-radius); +} +.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { + isolation: isolate; + border-color: var(--bs-nav-tabs-link-hover-border-color); +} +.nav-tabs .nav-link.disabled, .nav-tabs .nav-link:disabled { + color: var(--bs-nav-link-disabled-color); + background-color: transparent; + border-color: transparent; +} +.nav-tabs .nav-link.active, +.nav-tabs .nav-item.show .nav-link { + color: var(--bs-nav-tabs-link-active-color); + background-color: var(--bs-nav-tabs-link-active-bg); + border-color: var(--bs-nav-tabs-link-active-border-color); +} +.nav-tabs .dropdown-menu { + margin-top: calc(-1 * var(--bs-nav-tabs-border-width)); + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav-pills { + --bs-nav-pills-border-radius: 0.35rem; + --bs-nav-pills-link-active-color: #fff; + --bs-nav-pills-link-active-bg: #0061f2; +} +.nav-pills .nav-link { + background: none; + border: 0; + border-radius: var(--bs-nav-pills-border-radius); +} +.nav-pills .nav-link:disabled { + color: var(--bs-nav-link-disabled-color); + background-color: transparent; + border-color: transparent; +} +.nav-pills .nav-link.active, +.nav-pills .show > .nav-link { + color: var(--bs-nav-pills-link-active-color); + background-color: var(--bs-nav-pills-link-active-bg); +} + +.nav-fill > .nav-link, +.nav-fill .nav-item { + flex: 1 1 auto; + text-align: center; +} + +.nav-justified > .nav-link, +.nav-justified .nav-item { + flex-basis: 0; + flex-grow: 1; + text-align: center; +} + +.nav-fill .nav-item .nav-link, +.nav-justified .nav-item .nav-link { + width: 100%; +} + +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} + +.navbar { + --bs-navbar-padding-x: 0; + --bs-navbar-padding-y: 0.5rem; + --bs-navbar-color: rgba(0, 0, 0, 0.55); + --bs-navbar-hover-color: rgba(0, 0, 0, 0.7); + --bs-navbar-disabled-color: rgba(0, 0, 0, 0.3); + --bs-navbar-active-color: rgba(0, 0, 0, 0.9); + --bs-navbar-brand-padding-y: 0.3125rem; + --bs-navbar-brand-margin-end: 1rem; + --bs-navbar-brand-font-size: 1.25rem; + --bs-navbar-brand-color: rgba(0, 0, 0, 0.9); + --bs-navbar-brand-hover-color: rgba(0, 0, 0, 0.9); + --bs-navbar-nav-link-padding-x: 0.5rem; + --bs-navbar-toggler-padding-y: 0.25rem; + --bs-navbar-toggler-padding-x: 0.75rem; + --bs-navbar-toggler-font-size: 1.25rem; + --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); + --bs-navbar-toggler-border-color: rgba(0, 0, 0, 0.1); + --bs-navbar-toggler-border-radius: 0.35rem; + --bs-navbar-toggler-focus-width: 0.25rem; + --bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out; + position: relative; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + padding: var(--bs-navbar-padding-y) var(--bs-navbar-padding-x); +} +.navbar > .container, +.navbar > .container-fluid, +.navbar > .container-sm, +.navbar > .container-md, +.navbar > .container-lg, +.navbar > .container-xl, +.navbar > .container-xxl { + display: flex; + flex-wrap: inherit; + align-items: center; + justify-content: space-between; +} +.navbar-brand { + padding-top: var(--bs-navbar-brand-padding-y); + padding-bottom: var(--bs-navbar-brand-padding-y); + margin-right: var(--bs-navbar-brand-margin-end); + font-size: var(--bs-navbar-brand-font-size); + color: var(--bs-navbar-brand-color); + white-space: nowrap; +} +.navbar-brand:hover, .navbar-brand:focus { + color: var(--bs-navbar-brand-hover-color); + text-decoration: none; +} + +.navbar-nav { + --bs-nav-link-padding-x: 0; + --bs-nav-link-padding-y: 0.5rem; + --bs-nav-link-font-weight: ; + --bs-nav-link-color: var(--bs-navbar-color); + --bs-nav-link-hover-color: var(--bs-navbar-hover-color); + --bs-nav-link-disabled-color: var(--bs-navbar-disabled-color); + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} +.navbar-nav .show > .nav-link, +.navbar-nav .nav-link.active { + color: var(--bs-navbar-active-color); +} +.navbar-nav .dropdown-menu { + position: static; +} + +.navbar-text { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + color: var(--bs-navbar-color); +} +.navbar-text a, +.navbar-text a:hover, +.navbar-text a:focus { + color: var(--bs-navbar-active-color); +} + +.navbar-collapse { + flex-basis: 100%; + flex-grow: 1; + align-items: center; +} + +.navbar-toggler { + padding: var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x); + font-size: var(--bs-navbar-toggler-font-size); + line-height: 1; + color: var(--bs-navbar-color); + background-color: transparent; + border: var(--bs-border-width) solid var(--bs-navbar-toggler-border-color); + border-radius: var(--bs-navbar-toggler-border-radius); + transition: var(--bs-navbar-toggler-transition); +} +@media (prefers-reduced-motion: reduce) { + .navbar-toggler { + transition: none; + } +} +.navbar-toggler:hover { + text-decoration: none; +} +.navbar-toggler:focus { + text-decoration: none; + outline: 0; + box-shadow: 0 0 0 var(--bs-navbar-toggler-focus-width); +} + +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + background-image: var(--bs-navbar-toggler-icon-bg); + background-repeat: no-repeat; + background-position: center; + background-size: 100%; +} + +.navbar-nav-scroll { + max-height: var(--bs-scroll-height, 75vh); + overflow-y: auto; +} + +@media (min-width: 576px) { + .navbar-expand-sm { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-sm .navbar-nav { + flex-direction: row; + } + .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-sm .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-sm .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-sm .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-sm .navbar-toggler { + display: none; + } + .navbar-expand-sm .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-sm .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-sm .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 768px) { + .navbar-expand-md { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-md .navbar-nav { + flex-direction: row; + } + .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-md .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-md .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-md .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-md .navbar-toggler { + display: none; + } + .navbar-expand-md .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-md .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-md .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 992px) { + .navbar-expand-lg { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-lg .navbar-nav { + flex-direction: row; + } + .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-lg .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-lg .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-lg .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-lg .navbar-toggler { + display: none; + } + .navbar-expand-lg .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-lg .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-lg .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 1200px) { + .navbar-expand-xl { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-xl .navbar-nav { + flex-direction: row; + } + .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xl .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-xl .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-xl .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-xl .navbar-toggler { + display: none; + } + .navbar-expand-xl .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-xl .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-xl .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +@media (min-width: 1500px) { + .navbar-expand-xxl { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-xxl .navbar-nav { + flex-direction: row; + } + .navbar-expand-xxl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xxl .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); + } + .navbar-expand-xxl .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-xxl .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-xxl .navbar-toggler { + display: none; + } + .navbar-expand-xxl .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; + } + .navbar-expand-xxl .offcanvas .offcanvas-header { + display: none; + } + .navbar-expand-xxl .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} +.navbar-expand { + flex-wrap: nowrap; + justify-content: flex-start; +} +.navbar-expand .navbar-nav { + flex-direction: row; +} +.navbar-expand .navbar-nav .dropdown-menu { + position: absolute; +} +.navbar-expand .navbar-nav .nav-link { + padding-right: var(--bs-navbar-nav-link-padding-x); + padding-left: var(--bs-navbar-nav-link-padding-x); +} +.navbar-expand .navbar-nav-scroll { + overflow: visible; +} +.navbar-expand .navbar-collapse { + display: flex !important; + flex-basis: auto; +} +.navbar-expand .navbar-toggler { + display: none; +} +.navbar-expand .offcanvas { + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + transition: none; +} +.navbar-expand .offcanvas .offcanvas-header { + display: none; +} +.navbar-expand .offcanvas .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; +} + +.navbar-dark { + --bs-navbar-color: rgba(255, 255, 255, 0.55); + --bs-navbar-hover-color: rgba(255, 255, 255, 0.75); + --bs-navbar-disabled-color: rgba(255, 255, 255, 0.25); + --bs-navbar-active-color: #fff; + --bs-navbar-brand-color: #fff; + --bs-navbar-brand-hover-color: #fff; + --bs-navbar-toggler-border-color: rgba(255, 255, 255, 0.1); + --bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.card { + --bs-card-spacer-y: 1.35rem; + --bs-card-spacer-x: 1.35rem; + --bs-card-title-spacer-y: 0.5rem; + --bs-card-border-width: 1px; + --bs-card-border-color: rgba(33, 40, 50, 0.125); + --bs-card-border-radius: 0.35rem; + --bs-card-box-shadow: ; + --bs-card-inner-border-radius: 0.35rem; + --bs-card-cap-padding-y: 1rem; + --bs-card-cap-padding-x: 1.35rem; + --bs-card-cap-bg: rgba(33, 40, 50, 0.03); + --bs-card-cap-color: ; + --bs-card-height: ; + --bs-card-color: ; + --bs-card-bg: #fff; + --bs-card-img-overlay-padding: 1rem; + --bs-card-group-margin: 0.75rem; + position: relative; + display: flex; + flex-direction: column; + min-width: 0; + height: var(--bs-card-height); + word-wrap: break-word; + background-color: var(--bs-card-bg); + background-clip: border-box; + border: var(--bs-card-border-width) solid var(--bs-card-border-color); + border-radius: var(--bs-card-border-radius); +} +.card > hr { + margin-right: 0; + margin-left: 0; +} +.card > .list-group { + border-top: inherit; + border-bottom: inherit; +} +.card > .list-group:first-child { + border-top-width: 0; + border-top-left-radius: var(--bs-card-inner-border-radius); + border-top-right-radius: var(--bs-card-inner-border-radius); +} +.card > .list-group:last-child { + border-bottom-width: 0; + border-bottom-right-radius: var(--bs-card-inner-border-radius); + border-bottom-left-radius: var(--bs-card-inner-border-radius); +} +.card > .card-header + .list-group, +.card > .list-group + .card-footer { + border-top: 0; +} + +.card-body { + flex: 1 1 auto; + padding: var(--bs-card-spacer-y) var(--bs-card-spacer-x); + color: var(--bs-card-color); +} + +.card-title { + margin-bottom: var(--bs-card-title-spacer-y); +} + +.card-subtitle { + margin-top: calc(-0.5 * var(--bs-card-title-spacer-y)); + margin-bottom: 0; +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link:hover { + text-decoration: none; +} +.card-link + .card-link { + margin-left: var(--bs-card-spacer-x); +} + +.card-header { + padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x); + margin-bottom: 0; + color: var(--bs-card-cap-color); + background-color: var(--bs-card-cap-bg); + border-bottom: var(--bs-card-border-width) solid var(--bs-card-border-color); +} +.card-header:first-child { + border-radius: var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0; +} + +.card-footer { + padding: var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x); + color: var(--bs-card-cap-color); + background-color: var(--bs-card-cap-bg); + border-top: var(--bs-card-border-width) solid var(--bs-card-border-color); +} +.card-footer:last-child { + border-radius: 0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius); +} + +.card-header-tabs { + margin-right: calc(-0.5 * var(--bs-card-cap-padding-x)); + margin-bottom: calc(-1 * var(--bs-card-cap-padding-y)); + margin-left: calc(-0.5 * var(--bs-card-cap-padding-x)); + border-bottom: 0; +} +.card-header-tabs .nav-link.active { + background-color: var(--bs-card-bg); + border-bottom-color: var(--bs-card-bg); +} + +.card-header-pills { + margin-right: calc(-0.5 * var(--bs-card-cap-padding-x)); + margin-left: calc(-0.5 * var(--bs-card-cap-padding-x)); +} + +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: var(--bs-card-img-overlay-padding); + border-radius: var(--bs-card-inner-border-radius); +} + +.card-img, +.card-img-top, +.card-img-bottom { + width: 100%; +} + +.card-img, +.card-img-top { + border-top-left-radius: var(--bs-card-inner-border-radius); + border-top-right-radius: var(--bs-card-inner-border-radius); +} + +.card-img, +.card-img-bottom { + border-bottom-right-radius: var(--bs-card-inner-border-radius); + border-bottom-left-radius: var(--bs-card-inner-border-radius); +} + +.card-group > .card { + margin-bottom: var(--bs-card-group-margin); +} +@media (min-width: 576px) { + .card-group { + display: flex; + flex-flow: row wrap; + } + .card-group > .card { + flex: 1 0 0%; + margin-bottom: 0; + } + .card-group > .card + .card { + margin-left: 0; + border-left: 0; + } + .card-group > .card:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-top, + .card-group > .card:not(:last-child) .card-header { + border-top-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-bottom, + .card-group > .card:not(:last-child) .card-footer { + border-bottom-right-radius: 0; + } + .card-group > .card:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-top, + .card-group > .card:not(:first-child) .card-header { + border-top-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-bottom, + .card-group > .card:not(:first-child) .card-footer { + border-bottom-left-radius: 0; + } +} + +.accordion { + --bs-accordion-color: #69707a; + --bs-accordion-bg: #fff; + --bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease; + --bs-accordion-border-color: var(--bs-border-color); + --bs-accordion-border-width: 1px; + --bs-accordion-border-radius: 0.35rem; + --bs-accordion-inner-border-radius: calc(0.35rem - 1px); + --bs-accordion-btn-padding-x: 1.25rem; + --bs-accordion-btn-padding-y: 1rem; + --bs-accordion-btn-color: #69707a; + --bs-accordion-btn-bg: var(--bs-accordion-bg); + --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%2369707a'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-icon-width: 1.25rem; + --bs-accordion-btn-icon-transform: rotate(-180deg); + --bs-accordion-btn-icon-transition: transform 0.2s ease-in-out; + --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230057da'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + --bs-accordion-btn-focus-border-color: transparent; + --bs-accordion-btn-focus-box-shadow: 0 0 0 0.25rem rgba(0, 97, 242, 0.25); + --bs-accordion-body-padding-x: 1.25rem; + --bs-accordion-body-padding-y: 1rem; + --bs-accordion-active-color: #0057da; + --bs-accordion-active-bg: #e6effe; +} + +.accordion-button { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x); + font-size: 1rem; + color: var(--bs-accordion-btn-color); + text-align: left; + background-color: var(--bs-accordion-btn-bg); + border: 0; + border-radius: 0; + overflow-anchor: none; + transition: var(--bs-accordion-transition); +} +@media (prefers-reduced-motion: reduce) { + .accordion-button { + transition: none; + } +} +.accordion-button:not(.collapsed) { + color: var(--bs-accordion-active-color); + background-color: var(--bs-accordion-active-bg); + box-shadow: inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color); +} +.accordion-button:not(.collapsed)::after { + background-image: var(--bs-accordion-btn-active-icon); + transform: var(--bs-accordion-btn-icon-transform); +} +.accordion-button::after { + flex-shrink: 0; + width: var(--bs-accordion-btn-icon-width); + height: var(--bs-accordion-btn-icon-width); + margin-left: auto; + content: ""; + background-image: var(--bs-accordion-btn-icon); + background-repeat: no-repeat; + background-size: var(--bs-accordion-btn-icon-width); + transition: var(--bs-accordion-btn-icon-transition); +} +@media (prefers-reduced-motion: reduce) { + .accordion-button::after { + transition: none; + } +} +.accordion-button:hover { + z-index: 2; +} +.accordion-button:focus { + z-index: 3; + border-color: var(--bs-accordion-btn-focus-border-color); + outline: 0; + box-shadow: var(--bs-accordion-btn-focus-box-shadow); +} + +.accordion-header { + margin-bottom: 0; +} + +.accordion-item { + color: var(--bs-accordion-color); + background-color: var(--bs-accordion-bg); + border: var(--bs-accordion-border-width) solid var(--bs-accordion-border-color); +} +.accordion-item:first-of-type { + border-top-left-radius: var(--bs-accordion-border-radius); + border-top-right-radius: var(--bs-accordion-border-radius); +} +.accordion-item:first-of-type .accordion-button { + border-top-left-radius: var(--bs-accordion-inner-border-radius); + border-top-right-radius: var(--bs-accordion-inner-border-radius); +} +.accordion-item:not(:first-of-type) { + border-top: 0; +} +.accordion-item:last-of-type { + border-bottom-right-radius: var(--bs-accordion-border-radius); + border-bottom-left-radius: var(--bs-accordion-border-radius); +} +.accordion-item:last-of-type .accordion-button.collapsed { + border-bottom-right-radius: var(--bs-accordion-inner-border-radius); + border-bottom-left-radius: var(--bs-accordion-inner-border-radius); +} +.accordion-item:last-of-type .accordion-collapse { + border-bottom-right-radius: var(--bs-accordion-border-radius); + border-bottom-left-radius: var(--bs-accordion-border-radius); +} + +.accordion-body { + padding: var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x); +} + +.accordion-flush .accordion-collapse { + border-width: 0; +} +.accordion-flush .accordion-item { + border-right: 0; + border-left: 0; + border-radius: 0; +} +.accordion-flush .accordion-item:first-child { + border-top: 0; +} +.accordion-flush .accordion-item:last-child { + border-bottom: 0; +} +.accordion-flush .accordion-item .accordion-button, .accordion-flush .accordion-item .accordion-button.collapsed { + border-radius: 0; +} + +.breadcrumb { + --bs-breadcrumb-padding-x: 0; + --bs-breadcrumb-padding-y: 0; + --bs-breadcrumb-margin-bottom: 1rem; + --bs-breadcrumb-bg: ; + --bs-breadcrumb-border-radius: ; + --bs-breadcrumb-divider-color: #69707a; + --bs-breadcrumb-item-padding-x: 0.5rem; + --bs-breadcrumb-item-active-color: #69707a; + display: flex; + flex-wrap: wrap; + padding: var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x); + margin-bottom: var(--bs-breadcrumb-margin-bottom); + font-size: var(--bs-breadcrumb-font-size); + list-style: none; + background-color: var(--bs-breadcrumb-bg); + border-radius: var(--bs-breadcrumb-border-radius); +} + +.breadcrumb-item + .breadcrumb-item { + padding-left: var(--bs-breadcrumb-item-padding-x); +} +.breadcrumb-item + .breadcrumb-item::before { + float: left; + padding-right: var(--bs-breadcrumb-item-padding-x); + color: var(--bs-breadcrumb-divider-color); + content: var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */; +} +.breadcrumb-item.active { + color: var(--bs-breadcrumb-item-active-color); +} + +.pagination, .datatable-pagination ul { + --bs-pagination-padding-x: 0.75rem; + --bs-pagination-padding-y: 0.375rem; + --bs-pagination-font-size: 1rem; + --bs-pagination-color: var(--bs-link-color); + --bs-pagination-bg: #fff; + --bs-pagination-border-width: 1px; + --bs-pagination-border-color: #d4dae3; + --bs-pagination-border-radius: 0.35rem; + --bs-pagination-hover-color: var(--bs-link-hover-color); + --bs-pagination-hover-bg: #e0e5ec; + --bs-pagination-hover-border-color: #d4dae3; + --bs-pagination-focus-color: var(--bs-link-hover-color); + --bs-pagination-focus-bg: #e0e5ec; + --bs-pagination-focus-box-shadow: 0 0 0 0.25rem rgba(0, 97, 242, 0.25); + --bs-pagination-active-color: #fff; + --bs-pagination-active-bg: #0061f2; + --bs-pagination-active-border-color: #0061f2; + --bs-pagination-disabled-color: #69707a; + --bs-pagination-disabled-bg: #fff; + --bs-pagination-disabled-border-color: #d4dae3; + display: flex; + padding-left: 0; + list-style: none; +} + +.page-link, .datatable-pagination a { + position: relative; + display: block; + padding: var(--bs-pagination-padding-y) var(--bs-pagination-padding-x); + font-size: var(--bs-pagination-font-size); + color: var(--bs-pagination-color); + background-color: var(--bs-pagination-bg); + border: var(--bs-pagination-border-width) solid var(--bs-pagination-border-color); + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .page-link, .datatable-pagination a { + transition: none; + } +} +.page-link:hover, .datatable-pagination a:hover { + z-index: 2; + color: var(--bs-pagination-hover-color); + text-decoration: none; + background-color: var(--bs-pagination-hover-bg); + border-color: var(--bs-pagination-hover-border-color); +} +.page-link:focus, .datatable-pagination a:focus { + z-index: 3; + color: var(--bs-pagination-focus-color); + background-color: var(--bs-pagination-focus-bg); + outline: 0; + box-shadow: var(--bs-pagination-focus-box-shadow); +} +.page-link.active, .datatable-pagination a.active, .active > .page-link, .datatable-pagination .active > a { + z-index: 3; + color: var(--bs-pagination-active-color); + background-color: var(--bs-pagination-active-bg); + border-color: var(--bs-pagination-active-border-color); +} +.page-link.disabled, .datatable-pagination a.disabled, .disabled > .page-link, .datatable-pagination .disabled > a { + color: var(--bs-pagination-disabled-color); + pointer-events: none; + background-color: var(--bs-pagination-disabled-bg); + border-color: var(--bs-pagination-disabled-border-color); +} + +.page-item:not(:first-child) .page-link, .page-item:not(:first-child) .datatable-pagination a, .datatable-pagination .page-item:not(:first-child) a, .datatable-pagination li:not(:first-child) .page-link, .datatable-pagination li:not(:first-child) a { + margin-left: -1px; +} +.page-item:first-child .page-link, .page-item:first-child .datatable-pagination a, .datatable-pagination .page-item:first-child a, .datatable-pagination li:first-child .page-link, .datatable-pagination li:first-child a { + border-top-left-radius: var(--bs-pagination-border-radius); + border-bottom-left-radius: var(--bs-pagination-border-radius); +} +.page-item:last-child .page-link, .page-item:last-child .datatable-pagination a, .datatable-pagination .page-item:last-child a, .datatable-pagination li:last-child .page-link, .datatable-pagination li:last-child a { + border-top-right-radius: var(--bs-pagination-border-radius); + border-bottom-right-radius: var(--bs-pagination-border-radius); +} + +.pagination-lg { + --bs-pagination-padding-x: 1.5rem; + --bs-pagination-padding-y: 0.75rem; + --bs-pagination-font-size: 1.25rem; + --bs-pagination-border-radius: 0.5rem; +} + +.pagination-sm { + --bs-pagination-padding-x: 0.5rem; + --bs-pagination-padding-y: 0.25rem; + --bs-pagination-font-size: 0.875rem; + --bs-pagination-border-radius: 0.25rem; +} + +.badge { + --bs-badge-padding-x: 0.65em; + --bs-badge-padding-y: 0.35em; + --bs-badge-font-size: 0.75em; + --bs-badge-font-weight: 400; + --bs-badge-color: #fff; + --bs-badge-border-radius: 0.35rem; + display: inline-block; + padding: var(--bs-badge-padding-y) var(--bs-badge-padding-x); + font-size: var(--bs-badge-font-size); + font-weight: var(--bs-badge-font-weight); + line-height: 1; + color: var(--bs-badge-color); + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: var(--bs-badge-border-radius); +} +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +.alert { + --bs-alert-bg: transparent; + --bs-alert-padding-x: 1rem; + --bs-alert-padding-y: 1.25rem; + --bs-alert-margin-bottom: 1rem; + --bs-alert-color: inherit; + --bs-alert-border-color: transparent; + --bs-alert-border: 1px solid var(--bs-alert-border-color); + --bs-alert-border-radius: 0.35rem; + position: relative; + padding: var(--bs-alert-padding-y) var(--bs-alert-padding-x); + margin-bottom: var(--bs-alert-margin-bottom); + color: var(--bs-alert-color); + background-color: var(--bs-alert-bg); + border: var(--bs-alert-border); + border-radius: var(--bs-alert-border-radius); +} + +.alert-heading { + color: inherit; +} + +.alert-link { + font-weight: 500; +} + +.alert-dismissible { + padding-right: 3rem; +} +.alert-dismissible .btn-close { + position: absolute; + top: 0; + right: 0; + z-index: 2; + padding: 1.5625rem 1rem; +} + +.alert-primary { + --bs-alert-color: #003a91; + --bs-alert-bg: #ccdffc; + --bs-alert-border-color: #b3d0fb; +} +.alert-primary .alert-link { + color: #002e74; +} + +.alert-secondary { + --bs-alert-color: #3f0077; + --bs-alert-bg: #e1ccf4; + --bs-alert-border-color: #d2b3ee; +} +.alert-secondary .alert-link { + color: #32005f; +} + +.alert-success { + --bs-alert-color: #00673f; + --bs-alert-bg: #cceee1; + --bs-alert-border-color: #b3e6d2; +} +.alert-success .alert-link { + color: #005232; +} + +.alert-info { + --bs-alert-color: #007c80; + --bs-alert-bg: #ccf5f7; + --bs-alert-border-color: #b3f1f2; +} +.alert-info .alert-link { + color: #006366; +} + +.alert-warning { + --bs-alert-color: #926100; + --bs-alert-bg: #fdeccc; + --bs-alert-border-color: #fce3b3; +} +.alert-warning .alert-link { + color: #754e00; +} + +.alert-danger { + --bs-alert-color: #8b0d00; + --bs-alert-bg: #fad0cc; + --bs-alert-border-color: #f8b9b3; +} +.alert-danger .alert-link { + color: #6f0a00; +} + +.alert-light { + --bs-alert-color: #919497; + --bs-alert-bg: #fcfdfe; + --bs-alert-border-color: #fbfcfe; +} +.alert-light .alert-link { + color: #747679; +} + +.alert-dark { + --bs-alert-color: #14181e; + --bs-alert-bg: #d3d4d6; + --bs-alert-border-color: #bcbfc2; +} +.alert-dark .alert-link { + color: #101318; +} + +.alert-black { + --bs-alert-color: black; + --bs-alert-bg: #cccccc; + --bs-alert-border-color: #b3b3b3; +} +.alert-black .alert-link { + color: black; +} + +.alert-white { + --bs-alert-color: #999999; + --bs-alert-bg: white; + --bs-alert-border-color: white; +} +.alert-white .alert-link { + color: #7a7a7a; +} + +.alert-red { + --bs-alert-color: #8b0d00; + --bs-alert-bg: #fad0cc; + --bs-alert-border-color: #f8b9b3; +} +.alert-red .alert-link { + color: #6f0a00; +} + +.alert-orange { + --bs-alert-color: #943c00; + --bs-alert-bg: #fde0cc; + --bs-alert-border-color: #fdd1b3; +} +.alert-orange .alert-link { + color: #763000; +} + +.alert-yellow { + --bs-alert-color: #926100; + --bs-alert-bg: #fdeccc; + --bs-alert-border-color: #fce3b3; +} +.alert-yellow .alert-link { + color: #754e00; +} + +.alert-green { + --bs-alert-color: #00673f; + --bs-alert-bg: #cceee1; + --bs-alert-border-color: #b3e6d2; +} +.alert-green .alert-link { + color: #005232; +} + +.alert-teal { + --bs-alert-color: #007059; + --bs-alert-bg: #ccf1ea; + --bs-alert-border-color: #b3eadf; +} +.alert-teal .alert-link { + color: #005a47; +} + +.alert-cyan { + --bs-alert-color: #007c80; + --bs-alert-bg: #ccf5f7; + --bs-alert-border-color: #b3f1f2; +} +.alert-cyan .alert-link { + color: #006366; +} + +.alert-blue { + --bs-alert-color: #003a91; + --bs-alert-bg: #ccdffc; + --bs-alert-border-color: #b3d0fb; +} +.alert-blue .alert-link { + color: #002e74; +} + +.alert-indigo { + --bs-alert-color: #35008b; + --bs-alert-bg: #deccfa; + --bs-alert-border-color: #cdb3f8; +} +.alert-indigo .alert-link { + color: #2a006f; +} + +.alert-purple { + --bs-alert-color: #3f0077; + --bs-alert-bg: #e1ccf4; + --bs-alert-border-color: #d2b3ee; +} +.alert-purple .alert-link { + color: #32005f; +} + +.alert-pink { + --bs-alert-color: #880035; + --bs-alert-bg: #f9ccde; + --bs-alert-border-color: #f7b3cd; +} +.alert-pink .alert-link { + color: #6d002a; +} + +.alert-red-soft { + --bs-alert-color: #918688; + --bs-alert-bg: #fcf9f9; + --bs-alert-border-color: #fbf6f7; +} +.alert-red-soft .alert-link { + color: #746b6d; +} + +.alert-orange-soft { + --bs-alert-color: #928b88; + --bs-alert-bg: #fdfaf9; + --bs-alert-border-color: #fbf8f7; +} +.alert-orange-soft .alert-link { + color: #756f6d; +} + +.alert-yellow-soft { + --bs-alert-color: #918f88; + --bs-alert-bg: #fcfcf9; + --bs-alert-border-color: #fbfaf7; +} +.alert-yellow-soft .alert-link { + color: #74726d; +} + +.alert-green-soft { + --bs-alert-color: #838f8e; + --bs-alert-bg: #f8fcfb; + --bs-alert-border-color: #f4fafa; +} +.alert-green-soft .alert-link { + color: #697272; +} + +.alert-teal-soft { + --bs-alert-color: #839091; + --bs-alert-bg: #f8fcfc; + --bs-alert-border-color: #f4fbfb; +} +.alert-teal-soft .alert-link { + color: #697374; +} + +.alert-cyan-soft { + --bs-alert-color: #839195; + --bs-alert-bg: #f8fcfe; + --bs-alert-border-color: #f4fbfd; +} +.alert-cyan-soft .alert-link { + color: #697477; +} + +.alert-blue-soft { + --bs-alert-color: #838b97; + --bs-alert-bg: #f8fafe; + --bs-alert-border-color: #f4f8fe; +} +.alert-blue-soft .alert-link { + color: #696f79; +} + +.alert-indigo-soft { + --bs-alert-color: #888596; + --bs-alert-bg: #f9f8fe; + --bs-alert-border-color: #f7f5fe; +} +.alert-indigo-soft .alert-link { + color: #6d6a78; +} + +.alert-purple-soft { + --bs-alert-color: #898594; + --bs-alert-bg: #faf8fd; + --bs-alert-border-color: #f7f5fd; +} +.alert-purple-soft .alert-link { + color: #6e6a76; +} + +.alert-pink-soft { + --bs-alert-color: #91858e; + --bs-alert-bg: #fcf8fb; + --bs-alert-border-color: #fbf5f9; +} +.alert-pink-soft .alert-link { + color: #746a72; +} + +.alert-primary-soft { + --bs-alert-color: #838b97; + --bs-alert-bg: #f8fafe; + --bs-alert-border-color: #f4f8fe; +} +.alert-primary-soft .alert-link { + color: #696f79; +} + +.alert-secondary-soft { + --bs-alert-color: #898594; + --bs-alert-bg: #faf8fd; + --bs-alert-border-color: #f7f5fd; +} +.alert-secondary-soft .alert-link { + color: #6e6a76; +} + +.alert-success-soft { + --bs-alert-color: #838f8e; + --bs-alert-bg: #f8fcfb; + --bs-alert-border-color: #f4fafa; +} +.alert-success-soft .alert-link { + color: #697272; +} + +.alert-info-soft { + --bs-alert-color: #839195; + --bs-alert-bg: #f8fcfe; + --bs-alert-border-color: #f4fbfd; +} +.alert-info-soft .alert-link { + color: #697477; +} + +.alert-warning-soft { + --bs-alert-color: #918f88; + --bs-alert-bg: #fcfcf9; + --bs-alert-border-color: #fbfaf7; +} +.alert-warning-soft .alert-link { + color: #74726d; +} + +.alert-danger-soft { + --bs-alert-color: #918688; + --bs-alert-bg: #fcf9f9; + --bs-alert-border-color: #fbf6f7; +} +.alert-danger-soft .alert-link { + color: #746b6d; +} + +@keyframes progress-bar-stripes { + 0% { + background-position-x: 1rem; + } +} +.progress { + --bs-progress-height: 1rem; + --bs-progress-font-size: 0.75rem; + --bs-progress-bg: #e0e5ec; + --bs-progress-border-radius: 0.35rem; + --bs-progress-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075); + --bs-progress-bar-color: #fff; + --bs-progress-bar-bg: #0061f2; + --bs-progress-bar-transition: width 0.6s ease; + display: flex; + height: var(--bs-progress-height); + overflow: hidden; + font-size: var(--bs-progress-font-size); + background-color: var(--bs-progress-bg); + border-radius: var(--bs-progress-border-radius); +} + +.progress-bar { + display: flex; + flex-direction: column; + justify-content: center; + overflow: hidden; + color: var(--bs-progress-bar-color); + text-align: center; + white-space: nowrap; + background-color: var(--bs-progress-bar-bg); + transition: var(--bs-progress-bar-transition); +} +@media (prefers-reduced-motion: reduce) { + .progress-bar { + transition: none; + } +} + +.progress-bar-striped { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: var(--bs-progress-height) var(--bs-progress-height); +} + +.progress-bar-animated { + animation: 1s linear infinite progress-bar-stripes; +} +@media (prefers-reduced-motion: reduce) { + .progress-bar-animated { + animation: none; + } +} + +.list-group { + --bs-list-group-color: #212832; + --bs-list-group-bg: #fff; + --bs-list-group-border-color: rgba(0, 0, 0, 0.125); + --bs-list-group-border-width: 1px; + --bs-list-group-border-radius: 0.35rem; + --bs-list-group-item-padding-x: 1rem; + --bs-list-group-item-padding-y: 0.5rem; + --bs-list-group-action-color: #4a515b; + --bs-list-group-action-hover-color: #4a515b; + --bs-list-group-action-hover-bg: #f2f6fc; + --bs-list-group-action-active-color: #69707a; + --bs-list-group-action-active-bg: #e0e5ec; + --bs-list-group-disabled-color: #69707a; + --bs-list-group-disabled-bg: #fff; + --bs-list-group-active-color: #fff; + --bs-list-group-active-bg: #0061f2; + --bs-list-group-active-border-color: #0061f2; + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + border-radius: var(--bs-list-group-border-radius); +} + +.list-group-numbered { + list-style-type: none; + counter-reset: section; +} +.list-group-numbered > .list-group-item::before { + content: counters(section, ".") ". "; + counter-increment: section; +} + +.list-group-item-action { + width: 100%; + color: var(--bs-list-group-action-color); + text-align: inherit; +} +.list-group-item-action:hover, .list-group-item-action:focus { + z-index: 1; + color: var(--bs-list-group-action-hover-color); + text-decoration: none; + background-color: var(--bs-list-group-action-hover-bg); +} +.list-group-item-action:active { + color: var(--bs-list-group-action-active-color); + background-color: var(--bs-list-group-action-active-bg); +} + +.list-group-item { + position: relative; + display: block; + padding: var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x); + color: var(--bs-list-group-color); + background-color: var(--bs-list-group-bg); + border: var(--bs-list-group-border-width) solid var(--bs-list-group-border-color); +} +.list-group-item:first-child { + border-top-left-radius: inherit; + border-top-right-radius: inherit; +} +.list-group-item:last-child { + border-bottom-right-radius: inherit; + border-bottom-left-radius: inherit; +} +.list-group-item.disabled, .list-group-item:disabled { + color: var(--bs-list-group-disabled-color); + pointer-events: none; + background-color: var(--bs-list-group-disabled-bg); +} +.list-group-item.active { + z-index: 2; + color: var(--bs-list-group-active-color); + background-color: var(--bs-list-group-active-bg); + border-color: var(--bs-list-group-active-border-color); +} +.list-group-item + .list-group-item { + border-top-width: 0; +} +.list-group-item + .list-group-item.active { + margin-top: calc(-1 * var(--bs-list-group-border-width)); + border-top-width: var(--bs-list-group-border-width); +} + +.list-group-horizontal { + flex-direction: row; +} +.list-group-horizontal > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; +} +.list-group-horizontal > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; +} +.list-group-horizontal > .list-group-item.active { + margin-top: 0; +} +.list-group-horizontal > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; +} +.list-group-horizontal > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); +} + +@media (min-width: 576px) { + .list-group-horizontal-sm { + flex-direction: row; + } + .list-group-horizontal-sm > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-sm > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-sm > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-sm > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-sm > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 768px) { + .list-group-horizontal-md { + flex-direction: row; + } + .list-group-horizontal-md > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-md > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-md > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-md > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-md > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 992px) { + .list-group-horizontal-lg { + flex-direction: row; + } + .list-group-horizontal-lg > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-lg > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-lg > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-lg > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-lg > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 1200px) { + .list-group-horizontal-xl { + flex-direction: row; + } + .list-group-horizontal-xl > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-xl > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-xl > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-xl > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-xl > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +@media (min-width: 1500px) { + .list-group-horizontal-xxl { + flex-direction: row; + } + .list-group-horizontal-xxl > .list-group-item:first-child:not(:last-child) { + border-bottom-left-radius: var(--bs-list-group-border-radius); + border-top-right-radius: 0; + } + .list-group-horizontal-xxl > .list-group-item:last-child:not(:first-child) { + border-top-right-radius: var(--bs-list-group-border-radius); + border-bottom-left-radius: 0; + } + .list-group-horizontal-xxl > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-xxl > .list-group-item + .list-group-item { + border-top-width: var(--bs-list-group-border-width); + border-left-width: 0; + } + .list-group-horizontal-xxl > .list-group-item + .list-group-item.active { + margin-left: calc(-1 * var(--bs-list-group-border-width)); + border-left-width: var(--bs-list-group-border-width); + } +} +.list-group-flush { + border-radius: 0; +} +.list-group-flush > .list-group-item { + border-width: 0 0 var(--bs-list-group-border-width); +} +.list-group-flush > .list-group-item:last-child { + border-bottom-width: 0; +} + +.list-group-item-primary { + color: #003a91; + background-color: #ccdffc; +} +.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus { + color: #003a91; + background-color: #b8c9e3; +} +.list-group-item-primary.list-group-item-action.active { + color: #fff; + background-color: #003a91; + border-color: #003a91; +} + +.list-group-item-secondary { + color: #3f0077; + background-color: #e1ccf4; +} +.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus { + color: #3f0077; + background-color: #cbb8dc; +} +.list-group-item-secondary.list-group-item-action.active { + color: #fff; + background-color: #3f0077; + border-color: #3f0077; +} + +.list-group-item-success { + color: #00673f; + background-color: #cceee1; +} +.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus { + color: #00673f; + background-color: #b8d6cb; +} +.list-group-item-success.list-group-item-action.active { + color: #fff; + background-color: #00673f; + border-color: #00673f; +} + +.list-group-item-info { + color: #007c80; + background-color: #ccf5f7; +} +.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus { + color: #007c80; + background-color: #b8ddde; +} +.list-group-item-info.list-group-item-action.active { + color: #fff; + background-color: #007c80; + border-color: #007c80; +} + +.list-group-item-warning { + color: #926100; + background-color: #fdeccc; +} +.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus { + color: #926100; + background-color: #e4d4b8; +} +.list-group-item-warning.list-group-item-action.active { + color: #fff; + background-color: #926100; + border-color: #926100; +} + +.list-group-item-danger { + color: #8b0d00; + background-color: #fad0cc; +} +.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus { + color: #8b0d00; + background-color: #e1bbb8; +} +.list-group-item-danger.list-group-item-action.active { + color: #fff; + background-color: #8b0d00; + border-color: #8b0d00; +} + +.list-group-item-light { + color: #919497; + background-color: #fcfdfe; +} +.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus { + color: #919497; + background-color: #e3e4e5; +} +.list-group-item-light.list-group-item-action.active { + color: #fff; + background-color: #919497; + border-color: #919497; +} + +.list-group-item-dark { + color: #14181e; + background-color: #d3d4d6; +} +.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus { + color: #14181e; + background-color: #bebfc1; +} +.list-group-item-dark.list-group-item-action.active { + color: #fff; + background-color: #14181e; + border-color: #14181e; +} + +.list-group-item-black { + color: black; + background-color: #cccccc; +} +.list-group-item-black.list-group-item-action:hover, .list-group-item-black.list-group-item-action:focus { + color: black; + background-color: #b8b8b8; +} +.list-group-item-black.list-group-item-action.active { + color: #fff; + background-color: black; + border-color: black; +} + +.list-group-item-white { + color: #999999; + background-color: white; +} +.list-group-item-white.list-group-item-action:hover, .list-group-item-white.list-group-item-action:focus { + color: #999999; + background-color: #e6e6e6; +} +.list-group-item-white.list-group-item-action.active { + color: #fff; + background-color: #999999; + border-color: #999999; +} + +.list-group-item-red { + color: #8b0d00; + background-color: #fad0cc; +} +.list-group-item-red.list-group-item-action:hover, .list-group-item-red.list-group-item-action:focus { + color: #8b0d00; + background-color: #e1bbb8; +} +.list-group-item-red.list-group-item-action.active { + color: #fff; + background-color: #8b0d00; + border-color: #8b0d00; +} + +.list-group-item-orange { + color: #943c00; + background-color: #fde0cc; +} +.list-group-item-orange.list-group-item-action:hover, .list-group-item-orange.list-group-item-action:focus { + color: #943c00; + background-color: #e4cab8; +} +.list-group-item-orange.list-group-item-action.active { + color: #fff; + background-color: #943c00; + border-color: #943c00; +} + +.list-group-item-yellow { + color: #926100; + background-color: #fdeccc; +} +.list-group-item-yellow.list-group-item-action:hover, .list-group-item-yellow.list-group-item-action:focus { + color: #926100; + background-color: #e4d4b8; +} +.list-group-item-yellow.list-group-item-action.active { + color: #fff; + background-color: #926100; + border-color: #926100; +} + +.list-group-item-green { + color: #00673f; + background-color: #cceee1; +} +.list-group-item-green.list-group-item-action:hover, .list-group-item-green.list-group-item-action:focus { + color: #00673f; + background-color: #b8d6cb; +} +.list-group-item-green.list-group-item-action.active { + color: #fff; + background-color: #00673f; + border-color: #00673f; +} + +.list-group-item-teal { + color: #007059; + background-color: #ccf1ea; +} +.list-group-item-teal.list-group-item-action:hover, .list-group-item-teal.list-group-item-action:focus { + color: #007059; + background-color: #b8d9d3; +} +.list-group-item-teal.list-group-item-action.active { + color: #fff; + background-color: #007059; + border-color: #007059; +} + +.list-group-item-cyan { + color: #007c80; + background-color: #ccf5f7; +} +.list-group-item-cyan.list-group-item-action:hover, .list-group-item-cyan.list-group-item-action:focus { + color: #007c80; + background-color: #b8ddde; +} +.list-group-item-cyan.list-group-item-action.active { + color: #fff; + background-color: #007c80; + border-color: #007c80; +} + +.list-group-item-blue { + color: #003a91; + background-color: #ccdffc; +} +.list-group-item-blue.list-group-item-action:hover, .list-group-item-blue.list-group-item-action:focus { + color: #003a91; + background-color: #b8c9e3; +} +.list-group-item-blue.list-group-item-action.active { + color: #fff; + background-color: #003a91; + border-color: #003a91; +} + +.list-group-item-indigo { + color: #35008b; + background-color: #deccfa; +} +.list-group-item-indigo.list-group-item-action:hover, .list-group-item-indigo.list-group-item-action:focus { + color: #35008b; + background-color: #c8b8e1; +} +.list-group-item-indigo.list-group-item-action.active { + color: #fff; + background-color: #35008b; + border-color: #35008b; +} + +.list-group-item-purple { + color: #3f0077; + background-color: #e1ccf4; +} +.list-group-item-purple.list-group-item-action:hover, .list-group-item-purple.list-group-item-action:focus { + color: #3f0077; + background-color: #cbb8dc; +} +.list-group-item-purple.list-group-item-action.active { + color: #fff; + background-color: #3f0077; + border-color: #3f0077; +} + +.list-group-item-pink { + color: #880035; + background-color: #f9ccde; +} +.list-group-item-pink.list-group-item-action:hover, .list-group-item-pink.list-group-item-action:focus { + color: #880035; + background-color: #e0b8c8; +} +.list-group-item-pink.list-group-item-action.active { + color: #fff; + background-color: #880035; + border-color: #880035; +} + +.list-group-item-red-soft { + color: #918688; + background-color: #fcf9f9; +} +.list-group-item-red-soft.list-group-item-action:hover, .list-group-item-red-soft.list-group-item-action:focus { + color: #918688; + background-color: #e3e0e0; +} +.list-group-item-red-soft.list-group-item-action.active { + color: #fff; + background-color: #918688; + border-color: #918688; +} + +.list-group-item-orange-soft { + color: #928b88; + background-color: #fdfaf9; +} +.list-group-item-orange-soft.list-group-item-action:hover, .list-group-item-orange-soft.list-group-item-action:focus { + color: #928b88; + background-color: #e4e1e0; +} +.list-group-item-orange-soft.list-group-item-action.active { + color: #fff; + background-color: #928b88; + border-color: #928b88; +} + +.list-group-item-yellow-soft { + color: #918f88; + background-color: #fcfcf9; +} +.list-group-item-yellow-soft.list-group-item-action:hover, .list-group-item-yellow-soft.list-group-item-action:focus { + color: #918f88; + background-color: #e3e3e0; +} +.list-group-item-yellow-soft.list-group-item-action.active { + color: #fff; + background-color: #918f88; + border-color: #918f88; +} + +.list-group-item-green-soft { + color: #838f8e; + background-color: #f8fcfb; +} +.list-group-item-green-soft.list-group-item-action:hover, .list-group-item-green-soft.list-group-item-action:focus { + color: #838f8e; + background-color: #dfe3e2; +} +.list-group-item-green-soft.list-group-item-action.active { + color: #fff; + background-color: #838f8e; + border-color: #838f8e; +} + +.list-group-item-teal-soft { + color: #839091; + background-color: #f8fcfc; +} +.list-group-item-teal-soft.list-group-item-action:hover, .list-group-item-teal-soft.list-group-item-action:focus { + color: #839091; + background-color: #dfe3e3; +} +.list-group-item-teal-soft.list-group-item-action.active { + color: #fff; + background-color: #839091; + border-color: #839091; +} + +.list-group-item-cyan-soft { + color: #839195; + background-color: #f8fcfe; +} +.list-group-item-cyan-soft.list-group-item-action:hover, .list-group-item-cyan-soft.list-group-item-action:focus { + color: #839195; + background-color: #dfe3e5; +} +.list-group-item-cyan-soft.list-group-item-action.active { + color: #fff; + background-color: #839195; + border-color: #839195; +} + +.list-group-item-blue-soft { + color: #838b97; + background-color: #f8fafe; +} +.list-group-item-blue-soft.list-group-item-action:hover, .list-group-item-blue-soft.list-group-item-action:focus { + color: #838b97; + background-color: #dfe1e5; +} +.list-group-item-blue-soft.list-group-item-action.active { + color: #fff; + background-color: #838b97; + border-color: #838b97; +} + +.list-group-item-indigo-soft { + color: #888596; + background-color: #f9f8fe; +} +.list-group-item-indigo-soft.list-group-item-action:hover, .list-group-item-indigo-soft.list-group-item-action:focus { + color: #888596; + background-color: #e0dfe5; +} +.list-group-item-indigo-soft.list-group-item-action.active { + color: #fff; + background-color: #888596; + border-color: #888596; +} + +.list-group-item-purple-soft { + color: #898594; + background-color: #faf8fd; +} +.list-group-item-purple-soft.list-group-item-action:hover, .list-group-item-purple-soft.list-group-item-action:focus { + color: #898594; + background-color: #e1dfe4; +} +.list-group-item-purple-soft.list-group-item-action.active { + color: #fff; + background-color: #898594; + border-color: #898594; +} + +.list-group-item-pink-soft { + color: #91858e; + background-color: #fcf8fb; +} +.list-group-item-pink-soft.list-group-item-action:hover, .list-group-item-pink-soft.list-group-item-action:focus { + color: #91858e; + background-color: #e3dfe2; +} +.list-group-item-pink-soft.list-group-item-action.active { + color: #fff; + background-color: #91858e; + border-color: #91858e; +} + +.list-group-item-primary-soft { + color: #838b97; + background-color: #f8fafe; +} +.list-group-item-primary-soft.list-group-item-action:hover, .list-group-item-primary-soft.list-group-item-action:focus { + color: #838b97; + background-color: #dfe1e5; +} +.list-group-item-primary-soft.list-group-item-action.active { + color: #fff; + background-color: #838b97; + border-color: #838b97; +} + +.list-group-item-secondary-soft { + color: #898594; + background-color: #faf8fd; +} +.list-group-item-secondary-soft.list-group-item-action:hover, .list-group-item-secondary-soft.list-group-item-action:focus { + color: #898594; + background-color: #e1dfe4; +} +.list-group-item-secondary-soft.list-group-item-action.active { + color: #fff; + background-color: #898594; + border-color: #898594; +} + +.list-group-item-success-soft { + color: #838f8e; + background-color: #f8fcfb; +} +.list-group-item-success-soft.list-group-item-action:hover, .list-group-item-success-soft.list-group-item-action:focus { + color: #838f8e; + background-color: #dfe3e2; +} +.list-group-item-success-soft.list-group-item-action.active { + color: #fff; + background-color: #838f8e; + border-color: #838f8e; +} + +.list-group-item-info-soft { + color: #839195; + background-color: #f8fcfe; +} +.list-group-item-info-soft.list-group-item-action:hover, .list-group-item-info-soft.list-group-item-action:focus { + color: #839195; + background-color: #dfe3e5; +} +.list-group-item-info-soft.list-group-item-action.active { + color: #fff; + background-color: #839195; + border-color: #839195; +} + +.list-group-item-warning-soft { + color: #918f88; + background-color: #fcfcf9; +} +.list-group-item-warning-soft.list-group-item-action:hover, .list-group-item-warning-soft.list-group-item-action:focus { + color: #918f88; + background-color: #e3e3e0; +} +.list-group-item-warning-soft.list-group-item-action.active { + color: #fff; + background-color: #918f88; + border-color: #918f88; +} + +.list-group-item-danger-soft { + color: #918688; + background-color: #fcf9f9; +} +.list-group-item-danger-soft.list-group-item-action:hover, .list-group-item-danger-soft.list-group-item-action:focus { + color: #918688; + background-color: #e3e0e0; +} +.list-group-item-danger-soft.list-group-item-action.active { + color: #fff; + background-color: #918688; + border-color: #918688; +} + +.btn-close { + box-sizing: content-box; + width: 1em; + height: 1em; + padding: 0.25em 0.25em; + color: #000; + background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat; + border: 0; + border-radius: 0.35rem; + opacity: 0.5; +} +.btn-close:hover { + color: #000; + text-decoration: none; + opacity: 0.75; +} +.btn-close:focus { + outline: 0; + box-shadow: 0 0 0 0.25rem rgba(0, 97, 242, 0.25); + opacity: 1; +} +.btn-close:disabled, .btn-close.disabled { + pointer-events: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + opacity: 0.25; +} + +.btn-close-white { + filter: invert(1) grayscale(100%) brightness(200%); +} + +.toast { + --bs-toast-zindex: 1090; + --bs-toast-padding-x: 0.75rem; + --bs-toast-padding-y: 0.5rem; + --bs-toast-spacing: 1.5rem; + --bs-toast-max-width: 350px; + --bs-toast-font-size: 0.875rem; + --bs-toast-color: ; + --bs-toast-bg: rgba(255, 255, 255, 0.85); + --bs-toast-border-width: 1px; + --bs-toast-border-color: var(--bs-border-color-translucent); + --bs-toast-border-radius: 0.35rem; + --bs-toast-box-shadow: 0 0.15rem 1.75rem 0 rgba(33, 40, 50, 0.15); + --bs-toast-header-color: #69707a; + --bs-toast-header-bg: rgba(255, 255, 255, 0.85); + --bs-toast-header-border-color: rgba(0, 0, 0, 0.05); + width: var(--bs-toast-max-width); + max-width: 100%; + font-size: var(--bs-toast-font-size); + color: var(--bs-toast-color); + pointer-events: auto; + background-color: var(--bs-toast-bg); + background-clip: padding-box; + border: var(--bs-toast-border-width) solid var(--bs-toast-border-color); + box-shadow: var(--bs-toast-box-shadow); + border-radius: var(--bs-toast-border-radius); +} +.toast.showing { + opacity: 0; +} +.toast:not(.show) { + display: none; +} + +.toast-container { + --bs-toast-zindex: 1090; + position: absolute; + z-index: var(--bs-toast-zindex); + width: -moz-max-content; + width: max-content; + max-width: 100%; + pointer-events: none; +} +.toast-container > :not(:last-child) { + margin-bottom: var(--bs-toast-spacing); +} + +.toast-header { + display: flex; + align-items: center; + padding: var(--bs-toast-padding-y) var(--bs-toast-padding-x); + color: var(--bs-toast-header-color); + background-color: var(--bs-toast-header-bg); + background-clip: padding-box; + border-bottom: var(--bs-toast-border-width) solid var(--bs-toast-header-border-color); + border-top-left-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width)); + border-top-right-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width)); +} +.toast-header .btn-close { + margin-right: calc(-0.5 * var(--bs-toast-padding-x)); + margin-left: var(--bs-toast-padding-x); +} + +.toast-body { + padding: var(--bs-toast-padding-x); + word-wrap: break-word; +} + +.modal { + --bs-modal-zindex: 1055; + --bs-modal-width: 500px; + --bs-modal-padding: 1rem; + --bs-modal-margin: 0.5rem; + --bs-modal-color: ; + --bs-modal-bg: #fff; + --bs-modal-border-color: var(--bs-border-color-translucent); + --bs-modal-border-width: 1px; + --bs-modal-border-radius: 0.5rem; + --bs-modal-box-shadow: 0 0.125rem 0.25rem 0 rgba(33, 40, 50, 0.2); + --bs-modal-inner-border-radius: calc(0.5rem - 1px); + --bs-modal-header-padding-x: 1rem; + --bs-modal-header-padding-y: 1rem; + --bs-modal-header-padding: 1rem 1rem; + --bs-modal-header-border-color: var(--bs-border-color); + --bs-modal-header-border-width: 1px; + --bs-modal-title-line-height: 1.5; + --bs-modal-footer-gap: 0.5rem; + --bs-modal-footer-bg: ; + --bs-modal-footer-border-color: var(--bs-border-color); + --bs-modal-footer-border-width: 1px; + position: fixed; + top: 0; + left: 0; + z-index: var(--bs-modal-zindex); + display: none; + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; + outline: 0; +} + +.modal-dialog { + position: relative; + width: auto; + margin: var(--bs-modal-margin); + pointer-events: none; +} +.modal.fade .modal-dialog { + transition: transform 0.3s ease-out; + transform: translate(0, -50px); +} +@media (prefers-reduced-motion: reduce) { + .modal.fade .modal-dialog { + transition: none; + } +} +.modal.show .modal-dialog { + transform: none; +} +.modal.modal-static .modal-dialog { + transform: scale(1.02); +} + +.modal-dialog-scrollable { + height: calc(100% - var(--bs-modal-margin) * 2); +} +.modal-dialog-scrollable .modal-content { + max-height: 100%; + overflow: hidden; +} +.modal-dialog-scrollable .modal-body { + overflow-y: auto; +} + +.modal-dialog-centered { + display: flex; + align-items: center; + min-height: calc(100% - var(--bs-modal-margin) * 2); +} + +.modal-content { + position: relative; + display: flex; + flex-direction: column; + width: 100%; + color: var(--bs-modal-color); + pointer-events: auto; + background-color: var(--bs-modal-bg); + background-clip: padding-box; + border: var(--bs-modal-border-width) solid var(--bs-modal-border-color); + border-radius: var(--bs-modal-border-radius); + outline: 0; +} + +.modal-backdrop { + --bs-backdrop-zindex: 1050; + --bs-backdrop-bg: #000; + --bs-backdrop-opacity: 0.5; + position: fixed; + top: 0; + left: 0; + z-index: var(--bs-backdrop-zindex); + width: 100vw; + height: 100vh; + background-color: var(--bs-backdrop-bg); +} +.modal-backdrop.fade { + opacity: 0; +} +.modal-backdrop.show { + opacity: var(--bs-backdrop-opacity); +} + +.modal-header { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: space-between; + padding: var(--bs-modal-header-padding); + border-bottom: var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color); + border-top-left-radius: var(--bs-modal-inner-border-radius); + border-top-right-radius: var(--bs-modal-inner-border-radius); +} +.modal-header .btn-close { + padding: calc(var(--bs-modal-header-padding-y) * 0.5) calc(var(--bs-modal-header-padding-x) * 0.5); + margin: calc(-0.5 * var(--bs-modal-header-padding-y)) calc(-0.5 * var(--bs-modal-header-padding-x)) calc(-0.5 * var(--bs-modal-header-padding-y)) auto; +} + +.modal-title { + margin-bottom: 0; + line-height: var(--bs-modal-title-line-height); +} + +.modal-body { + position: relative; + flex: 1 1 auto; + padding: var(--bs-modal-padding); +} + +.modal-footer { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + align-items: center; + justify-content: flex-end; + padding: calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * 0.5); + background-color: var(--bs-modal-footer-bg); + border-top: var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color); + border-bottom-right-radius: var(--bs-modal-inner-border-radius); + border-bottom-left-radius: var(--bs-modal-inner-border-radius); +} +.modal-footer > * { + margin: calc(var(--bs-modal-footer-gap) * 0.5); +} + +@media (min-width: 576px) { + .modal { + --bs-modal-margin: 1.75rem; + --bs-modal-box-shadow: 0 0.15rem 1.75rem 0 rgba(33, 40, 50, 0.15); + } + .modal-dialog { + max-width: var(--bs-modal-width); + margin-right: auto; + margin-left: auto; + } + .modal-sm { + --bs-modal-width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg, + .modal-xl { + --bs-modal-width: 800px; + } +} +@media (min-width: 1200px) { + .modal-xl { + --bs-modal-width: 1140px; + } +} +.modal-fullscreen { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; +} +.modal-fullscreen .modal-content { + height: 100%; + border: 0; + border-radius: 0; +} +.modal-fullscreen .modal-header, +.modal-fullscreen .modal-footer { + border-radius: 0; +} +.modal-fullscreen .modal-body { + overflow-y: auto; +} + +@media (max-width: 575.98px) { + .modal-fullscreen-sm-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-sm-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-sm-down .modal-header, + .modal-fullscreen-sm-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-sm-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 767.98px) { + .modal-fullscreen-md-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-md-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-md-down .modal-header, + .modal-fullscreen-md-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-md-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 991.98px) { + .modal-fullscreen-lg-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-lg-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-lg-down .modal-header, + .modal-fullscreen-lg-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-lg-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 1199.98px) { + .modal-fullscreen-xl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-xl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-xl-down .modal-header, + .modal-fullscreen-xl-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-xl-down .modal-body { + overflow-y: auto; + } +} +@media (max-width: 1499.98px) { + .modal-fullscreen-xxl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-xxl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-xxl-down .modal-header, + .modal-fullscreen-xxl-down .modal-footer { + border-radius: 0; + } + .modal-fullscreen-xxl-down .modal-body { + overflow-y: auto; + } +} +.tooltip { + --bs-tooltip-zindex: 1080; + --bs-tooltip-max-width: 200px; + --bs-tooltip-padding-x: 0.5rem; + --bs-tooltip-padding-y: 0.25rem; + --bs-tooltip-margin: ; + --bs-tooltip-font-size: 0.875rem; + --bs-tooltip-color: #fff; + --bs-tooltip-bg: #000; + --bs-tooltip-border-radius: 0.35rem; + --bs-tooltip-opacity: 0.9; + --bs-tooltip-arrow-width: 0.8rem; + --bs-tooltip-arrow-height: 0.4rem; + z-index: var(--bs-tooltip-zindex); + display: block; + padding: var(--bs-tooltip-arrow-height); + margin: var(--bs-tooltip-margin); + font-family: "Metropolis", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; + font-size: var(--bs-tooltip-font-size); + word-wrap: break-word; + opacity: 0; +} +.tooltip.show { + opacity: var(--bs-tooltip-opacity); +} +.tooltip .tooltip-arrow { + display: block; + width: var(--bs-tooltip-arrow-width); + height: var(--bs-tooltip-arrow-height); +} +.tooltip .tooltip-arrow::before { + position: absolute; + content: ""; + border-color: transparent; + border-style: solid; +} + +.bs-tooltip-top .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow { + bottom: 0; +} +.bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before { + top: -1px; + border-width: var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0; + border-top-color: var(--bs-tooltip-bg); +} + +/* rtl:begin:ignore */ +.bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow { + left: 0; + width: var(--bs-tooltip-arrow-height); + height: var(--bs-tooltip-arrow-width); +} +.bs-tooltip-end .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before { + right: -1px; + border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * 0.5) 0; + border-right-color: var(--bs-tooltip-bg); +} + +/* rtl:end:ignore */ +.bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow { + top: 0; +} +.bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before { + bottom: -1px; + border-width: 0 calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height); + border-bottom-color: var(--bs-tooltip-bg); +} + +/* rtl:begin:ignore */ +.bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow { + right: 0; + width: var(--bs-tooltip-arrow-height); + height: var(--bs-tooltip-arrow-width); +} +.bs-tooltip-start .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before { + left: -1px; + border-width: calc(var(--bs-tooltip-arrow-width) * 0.5) 0 calc(var(--bs-tooltip-arrow-width) * 0.5) var(--bs-tooltip-arrow-height); + border-left-color: var(--bs-tooltip-bg); +} + +/* rtl:end:ignore */ +.tooltip-inner { + max-width: var(--bs-tooltip-max-width); + padding: var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x); + color: var(--bs-tooltip-color); + text-align: center; + background-color: var(--bs-tooltip-bg); + border-radius: var(--bs-tooltip-border-radius); +} + +.popover { + --bs-popover-zindex: 1070; + --bs-popover-max-width: 276px; + --bs-popover-font-size: 0.875rem; + --bs-popover-bg: #fff; + --bs-popover-border-width: 1px; + --bs-popover-border-color: var(--bs-border-color-translucent); + --bs-popover-border-radius: 0.5rem; + --bs-popover-inner-border-radius: calc(0.5rem - 1px); + --bs-popover-box-shadow: 0 0.15rem 1.75rem 0 rgba(33, 40, 50, 0.15); + --bs-popover-header-padding-x: 1rem; + --bs-popover-header-padding-y: 0.5rem; + --bs-popover-header-font-size: 1rem; + --bs-popover-header-color: #363d47; + --bs-popover-header-bg: #f0f0f0; + --bs-popover-body-padding-x: 1rem; + --bs-popover-body-padding-y: 1rem; + --bs-popover-body-color: #69707a; + --bs-popover-arrow-width: 1rem; + --bs-popover-arrow-height: 0.5rem; + --bs-popover-arrow-border: var(--bs-popover-border-color); + z-index: var(--bs-popover-zindex); + display: block; + max-width: var(--bs-popover-max-width); + font-family: "Metropolis", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-style: normal; + font-weight: 400; + line-height: 1.5; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; + font-size: var(--bs-popover-font-size); + word-wrap: break-word; + background-color: var(--bs-popover-bg); + background-clip: padding-box; + border: var(--bs-popover-border-width) solid var(--bs-popover-border-color); + border-radius: var(--bs-popover-border-radius); +} +.popover .popover-arrow { + display: block; + width: var(--bs-popover-arrow-width); + height: var(--bs-popover-arrow-height); +} +.popover .popover-arrow::before, .popover .popover-arrow::after { + position: absolute; + display: block; + content: ""; + border-color: transparent; + border-style: solid; + border-width: 0; +} + +.bs-popover-top > .popover-arrow, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow { + bottom: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); +} +.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before, .bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after { + border-width: var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0; +} +.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before { + bottom: 0; + border-top-color: var(--bs-popover-arrow-border); +} +.bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after { + bottom: var(--bs-popover-border-width); + border-top-color: var(--bs-popover-bg); +} + +/* rtl:begin:ignore */ +.bs-popover-end > .popover-arrow, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow { + left: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); + width: var(--bs-popover-arrow-height); + height: var(--bs-popover-arrow-width); +} +.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before, .bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after { + border-width: calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0; +} +.bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before { + left: 0; + border-right-color: var(--bs-popover-arrow-border); +} +.bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after { + left: var(--bs-popover-border-width); + border-right-color: var(--bs-popover-bg); +} + +/* rtl:end:ignore */ +.bs-popover-bottom > .popover-arrow, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow { + top: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); +} +.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before, .bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after { + border-width: 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height); +} +.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before { + top: 0; + border-bottom-color: var(--bs-popover-arrow-border); +} +.bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after { + top: var(--bs-popover-border-width); + border-bottom-color: var(--bs-popover-bg); +} +.bs-popover-bottom .popover-header::before, .bs-popover-auto[data-popper-placement^=bottom] .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: var(--bs-popover-arrow-width); + margin-left: calc(-0.5 * var(--bs-popover-arrow-width)); + content: ""; + border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-header-bg); +} + +/* rtl:begin:ignore */ +.bs-popover-start > .popover-arrow, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow { + right: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)); + width: var(--bs-popover-arrow-height); + height: var(--bs-popover-arrow-width); +} +.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before, .bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after { + border-width: calc(var(--bs-popover-arrow-width) * 0.5) 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height); +} +.bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before { + right: 0; + border-left-color: var(--bs-popover-arrow-border); +} +.bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after { + right: var(--bs-popover-border-width); + border-left-color: var(--bs-popover-bg); +} + +/* rtl:end:ignore */ +.popover-header { + padding: var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x); + margin-bottom: 0; + font-size: var(--bs-popover-header-font-size); + color: var(--bs-popover-header-color); + background-color: var(--bs-popover-header-bg); + border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-border-color); + border-top-left-radius: var(--bs-popover-inner-border-radius); + border-top-right-radius: var(--bs-popover-inner-border-radius); +} +.popover-header:empty { + display: none; +} + +.popover-body { + padding: var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x); + color: var(--bs-popover-body-color); +} + +.carousel { + position: relative; +} + +.carousel.pointer-event { + touch-action: pan-y; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} +.carousel-inner::after { + display: block; + clear: both; + content: ""; +} + +.carousel-item { + position: relative; + display: none; + float: left; + width: 100%; + margin-right: -100%; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transition: transform 0.6s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .carousel-item { + transition: none; + } +} + +.carousel-item.active, +.carousel-item-next, +.carousel-item-prev { + display: block; +} + +.carousel-item-next:not(.carousel-item-start), +.active.carousel-item-end { + transform: translateX(100%); +} + +.carousel-item-prev:not(.carousel-item-end), +.active.carousel-item-start { + transform: translateX(-100%); +} + +.carousel-fade .carousel-item { + opacity: 0; + transition-property: opacity; + transform: none; +} +.carousel-fade .carousel-item.active, +.carousel-fade .carousel-item-next.carousel-item-start, +.carousel-fade .carousel-item-prev.carousel-item-end { + z-index: 1; + opacity: 1; +} +.carousel-fade .active.carousel-item-start, +.carousel-fade .active.carousel-item-end { + z-index: 0; + opacity: 0; + transition: opacity 0s 0.6s; +} +@media (prefers-reduced-motion: reduce) { + .carousel-fade .active.carousel-item-start, + .carousel-fade .active.carousel-item-end { + transition: none; + } +} + +.carousel-control-prev, +.carousel-control-next { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + width: 15%; + padding: 0; + color: #fff; + text-align: center; + background: none; + border: 0; + opacity: 0.5; + transition: opacity 0.15s ease; +} +@media (prefers-reduced-motion: reduce) { + .carousel-control-prev, + .carousel-control-next { + transition: none; + } +} +.carousel-control-prev:hover, .carousel-control-prev:focus, +.carousel-control-next:hover, +.carousel-control-next:focus { + color: #fff; + text-decoration: none; + outline: 0; + opacity: 0.9; +} + +.carousel-control-prev { + left: 0; +} + +.carousel-control-next { + right: 0; +} + +.carousel-control-prev-icon, +.carousel-control-next-icon { + display: inline-block; + width: 2rem; + height: 2rem; + background-repeat: no-repeat; + background-position: 50%; + background-size: 100% 100%; +} + +/* rtl:options: { + "autoRename": true, + "stringMap":[ { + "name" : "prev-next", + "search" : "prev", + "replace" : "next" + } ] +} */ +.carousel-control-prev-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e"); +} + +.carousel-control-next-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); +} + +.carousel-indicators { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 2; + display: flex; + justify-content: center; + padding: 0; + margin-right: 15%; + margin-bottom: 1rem; + margin-left: 15%; + list-style: none; +} +.carousel-indicators [data-bs-target] { + box-sizing: content-box; + flex: 0 1 auto; + width: 30px; + height: 3px; + padding: 0; + margin-right: 3px; + margin-left: 3px; + text-indent: -999px; + cursor: pointer; + background-color: #fff; + background-clip: padding-box; + border: 0; + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + opacity: 0.5; + transition: opacity 0.6s ease; +} +@media (prefers-reduced-motion: reduce) { + .carousel-indicators [data-bs-target] { + transition: none; + } +} +.carousel-indicators .active { + opacity: 1; +} + +.carousel-caption { + position: absolute; + right: 15%; + bottom: 1.25rem; + left: 15%; + padding-top: 1.25rem; + padding-bottom: 1.25rem; + color: #fff; + text-align: center; +} + +.carousel-dark .carousel-control-prev-icon, +.carousel-dark .carousel-control-next-icon { + filter: invert(1) grayscale(100); +} +.carousel-dark .carousel-indicators [data-bs-target] { + background-color: #000; +} +.carousel-dark .carousel-caption { + color: #000; +} + +.spinner-grow, +.spinner-border { + display: inline-block; + width: var(--bs-spinner-width); + height: var(--bs-spinner-height); + vertical-align: var(--bs-spinner-vertical-align); + border-radius: 50%; + animation: var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name); +} + +@keyframes spinner-border { + to { + transform: rotate(360deg) /* rtl:ignore */; + } +} +.spinner-border { + --bs-spinner-width: 2rem; + --bs-spinner-height: 2rem; + --bs-spinner-vertical-align: -0.125em; + --bs-spinner-border-width: 0.25em; + --bs-spinner-animation-speed: 0.75s; + --bs-spinner-animation-name: spinner-border; + border: var(--bs-spinner-border-width) solid currentcolor; + border-right-color: transparent; +} + +.spinner-border-sm { + --bs-spinner-width: 1rem; + --bs-spinner-height: 1rem; + --bs-spinner-border-width: 0.2em; +} + +@keyframes spinner-grow { + 0% { + transform: scale(0); + } + 50% { + opacity: 1; + transform: none; + } +} +.spinner-grow { + --bs-spinner-width: 2rem; + --bs-spinner-height: 2rem; + --bs-spinner-vertical-align: -0.125em; + --bs-spinner-animation-speed: 0.75s; + --bs-spinner-animation-name: spinner-grow; + background-color: currentcolor; + opacity: 0; +} + +.spinner-grow-sm { + --bs-spinner-width: 1rem; + --bs-spinner-height: 1rem; +} + +@media (prefers-reduced-motion: reduce) { + .spinner-border, + .spinner-grow { + --bs-spinner-animation-speed: 1.5s; + } +} +.offcanvas, .offcanvas-xxl, .offcanvas-xl, .offcanvas-lg, .offcanvas-md, .offcanvas-sm { + --bs-offcanvas-zindex: 1045; + --bs-offcanvas-width: 400px; + --bs-offcanvas-height: 30vh; + --bs-offcanvas-padding-x: 1rem; + --bs-offcanvas-padding-y: 1rem; + --bs-offcanvas-color: ; + --bs-offcanvas-bg: #fff; + --bs-offcanvas-border-width: 1px; + --bs-offcanvas-border-color: var(--bs-border-color-translucent); + --bs-offcanvas-box-shadow: 0 0.125rem 0.25rem 0 rgba(33, 40, 50, 0.2); +} + +@media (max-width: 575.98px) { + .offcanvas-sm { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; + } +} +@media (max-width: 575.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-sm { + transition: none; + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.showing, .offcanvas-sm.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 575.98px) { + .offcanvas-sm.showing, .offcanvas-sm.hiding, .offcanvas-sm.show { + visibility: visible; + } +} +@media (min-width: 576px) { + .offcanvas-sm { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-sm .offcanvas-header { + display: none; + } + .offcanvas-sm .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 767.98px) { + .offcanvas-md { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; + } +} +@media (max-width: 767.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-md { + transition: none; + } +} +@media (max-width: 767.98px) { + .offcanvas-md.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } +} +@media (max-width: 767.98px) { + .offcanvas-md.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } +} +@media (max-width: 767.98px) { + .offcanvas-md.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } +} +@media (max-width: 767.98px) { + .offcanvas-md.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } +} +@media (max-width: 767.98px) { + .offcanvas-md.showing, .offcanvas-md.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 767.98px) { + .offcanvas-md.showing, .offcanvas-md.hiding, .offcanvas-md.show { + visibility: visible; + } +} +@media (min-width: 768px) { + .offcanvas-md { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-md .offcanvas-header { + display: none; + } + .offcanvas-md .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 991.98px) { + .offcanvas-lg { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; + } +} +@media (max-width: 991.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-lg { + transition: none; + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.showing, .offcanvas-lg.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 991.98px) { + .offcanvas-lg.showing, .offcanvas-lg.hiding, .offcanvas-lg.show { + visibility: visible; + } +} +@media (min-width: 992px) { + .offcanvas-lg { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-lg .offcanvas-header { + display: none; + } + .offcanvas-lg .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 1199.98px) { + .offcanvas-xl { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; + } +} +@media (max-width: 1199.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-xl { + transition: none; + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.showing, .offcanvas-xl.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 1199.98px) { + .offcanvas-xl.showing, .offcanvas-xl.hiding, .offcanvas-xl.show { + visibility: visible; + } +} +@media (min-width: 1200px) { + .offcanvas-xl { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-xl .offcanvas-header { + display: none; + } + .offcanvas-xl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +@media (max-width: 1499.98px) { + .offcanvas-xxl { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; + } +} +@media (max-width: 1499.98px) and (prefers-reduced-motion: reduce) { + .offcanvas-xxl { + transition: none; + } +} +@media (max-width: 1499.98px) { + .offcanvas-xxl.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); + } +} +@media (max-width: 1499.98px) { + .offcanvas-xxl.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); + } +} +@media (max-width: 1499.98px) { + .offcanvas-xxl.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); + } +} +@media (max-width: 1499.98px) { + .offcanvas-xxl.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); + } +} +@media (max-width: 1499.98px) { + .offcanvas-xxl.showing, .offcanvas-xxl.show:not(.hiding) { + transform: none; + } +} +@media (max-width: 1499.98px) { + .offcanvas-xxl.showing, .offcanvas-xxl.hiding, .offcanvas-xxl.show { + visibility: visible; + } +} +@media (min-width: 1500px) { + .offcanvas-xxl { + --bs-offcanvas-height: auto; + --bs-offcanvas-border-width: 0; + background-color: transparent !important; + } + .offcanvas-xxl .offcanvas-header { + display: none; + } + .offcanvas-xxl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + background-color: transparent !important; + } +} + +.offcanvas { + position: fixed; + bottom: 0; + z-index: var(--bs-offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--bs-offcanvas-color); + visibility: hidden; + background-color: var(--bs-offcanvas-bg); + background-clip: padding-box; + outline: 0; + transition: transform 0.3s ease-in-out; +} +@media (prefers-reduced-motion: reduce) { + .offcanvas { + transition: none; + } +} +.offcanvas.offcanvas-start { + top: 0; + left: 0; + width: var(--bs-offcanvas-width); + border-right: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(-100%); +} +.offcanvas.offcanvas-end { + top: 0; + right: 0; + width: var(--bs-offcanvas-width); + border-left: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateX(100%); +} +.offcanvas.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-bottom: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(-100%); +} +.offcanvas.offcanvas-bottom { + right: 0; + left: 0; + height: var(--bs-offcanvas-height); + max-height: 100%; + border-top: var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color); + transform: translateY(100%); +} +.offcanvas.showing, .offcanvas.show:not(.hiding) { + transform: none; +} +.offcanvas.showing, .offcanvas.hiding, .offcanvas.show { + visibility: visible; +} + +.offcanvas-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1040; + width: 100vw; + height: 100vh; + background-color: #000; +} +.offcanvas-backdrop.fade { + opacity: 0; +} +.offcanvas-backdrop.show { + opacity: 0.5; +} + +.offcanvas-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x); +} +.offcanvas-header .btn-close { + padding: calc(var(--bs-offcanvas-padding-y) * 0.5) calc(var(--bs-offcanvas-padding-x) * 0.5); + margin-top: calc(-0.5 * var(--bs-offcanvas-padding-y)); + margin-right: calc(-0.5 * var(--bs-offcanvas-padding-x)); + margin-bottom: calc(-0.5 * var(--bs-offcanvas-padding-y)); +} + +.offcanvas-title { + margin-bottom: 0; + line-height: 1.5; +} + +.offcanvas-body { + flex-grow: 1; + padding: var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x); + overflow-y: auto; +} + +.placeholder { + display: inline-block; + min-height: 1em; + vertical-align: middle; + cursor: wait; + background-color: currentcolor; + opacity: 0.5; +} +.placeholder.btn::before { + display: inline-block; + content: ""; +} + +.placeholder-xs { + min-height: 0.6em; +} + +.placeholder-sm { + min-height: 0.8em; +} + +.placeholder-lg { + min-height: 1.2em; +} + +.placeholder-glow .placeholder { + animation: placeholder-glow 2s ease-in-out infinite; +} + +@keyframes placeholder-glow { + 50% { + opacity: 0.2; + } +} +.placeholder-wave { + -webkit-mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%); + mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%); + -webkit-mask-size: 200% 100%; + mask-size: 200% 100%; + animation: placeholder-wave 2s linear infinite; +} + +@keyframes placeholder-wave { + 100% { + -webkit-mask-position: -200% 0%; + mask-position: -200% 0%; + } +} +.clearfix::after { + display: block; + clear: both; + content: ""; +} + +.text-bg-primary { + color: #fff !important; + background-color: RGBA(0, 97, 242, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-secondary { + color: #fff !important; + background-color: RGBA(105, 0, 199, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-success { + color: #fff !important; + background-color: RGBA(0, 172, 105, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-info { + color: #fff !important; + background-color: RGBA(0, 207, 213, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-warning { + color: #fff !important; + background-color: RGBA(244, 161, 0, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-danger { + color: #fff !important; + background-color: RGBA(232, 21, 0, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-light { + color: #000 !important; + background-color: RGBA(242, 246, 252, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-dark { + color: #fff !important; + background-color: RGBA(33, 40, 50, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-black { + color: #fff !important; + background-color: RGBA(0, 0, 0, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-white { + color: #000 !important; + background-color: RGBA(255, 255, 255, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-red { + color: #fff !important; + background-color: RGBA(232, 21, 0, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-orange { + color: #fff !important; + background-color: RGBA(247, 100, 0, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-yellow { + color: #fff !important; + background-color: RGBA(244, 161, 0, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-green { + color: #fff !important; + background-color: RGBA(0, 172, 105, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-teal { + color: #fff !important; + background-color: RGBA(0, 186, 148, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-cyan { + color: #fff !important; + background-color: RGBA(0, 207, 213, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-blue { + color: #fff !important; + background-color: RGBA(0, 97, 242, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-indigo { + color: #fff !important; + background-color: RGBA(88, 0, 232, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-purple { + color: #fff !important; + background-color: RGBA(105, 0, 199, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-pink { + color: #fff !important; + background-color: RGBA(227, 0, 89, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-red-soft { + color: #000 !important; + background-color: RGBA(241, 224, 227, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-orange-soft { + color: #000 !important; + background-color: RGBA(243, 231, 227, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-yellow-soft { + color: #000 !important; + background-color: RGBA(242, 238, 227, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-green-soft { + color: #000 !important; + background-color: RGBA(218, 239, 237, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-teal-soft { + color: #000 !important; + background-color: RGBA(218, 240, 242, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-cyan-soft { + color: #000 !important; + background-color: RGBA(218, 242, 248, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-blue-soft { + color: #000 !important; + background-color: RGBA(218, 231, 251, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-indigo-soft { + color: #000 !important; + background-color: RGBA(227, 221, 250, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-purple-soft { + color: #000 !important; + background-color: RGBA(228, 221, 247, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-pink-soft { + color: #000 !important; + background-color: RGBA(241, 221, 236, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-primary-soft { + color: #000 !important; + background-color: RGBA(218, 231, 251, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-secondary-soft { + color: #000 !important; + background-color: RGBA(228, 221, 247, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-success-soft { + color: #000 !important; + background-color: RGBA(218, 239, 237, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-info-soft { + color: #000 !important; + background-color: RGBA(218, 242, 248, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-warning-soft { + color: #000 !important; + background-color: RGBA(242, 238, 227, var(--bs-bg-opacity, 1)) !important; +} + +.text-bg-danger-soft { + color: #000 !important; + background-color: RGBA(241, 224, 227, var(--bs-bg-opacity, 1)) !important; +} + +.link-primary { + color: #0061f2 !important; +} +.link-primary:hover, .link-primary:focus { + color: #004ec2 !important; +} + +.link-secondary { + color: #6900c7 !important; +} +.link-secondary:hover, .link-secondary:focus { + color: #54009f !important; +} + +.link-success { + color: #00ac69 !important; +} +.link-success:hover, .link-success:focus { + color: #008a54 !important; +} + +.link-info { + color: #00cfd5 !important; +} +.link-info:hover, .link-info:focus { + color: #00a6aa !important; +} + +.link-warning { + color: #f4a100 !important; +} +.link-warning:hover, .link-warning:focus { + color: #c38100 !important; +} + +.link-danger { + color: #e81500 !important; +} +.link-danger:hover, .link-danger:focus { + color: #ba1100 !important; +} + +.link-light { + color: #f2f6fc !important; +} +.link-light:hover, .link-light:focus { + color: #f5f8fd !important; +} + +.link-dark { + color: #212832 !important; +} +.link-dark:hover, .link-dark:focus { + color: #1a2028 !important; +} + +.link-black { + color: #000 !important; +} +.link-black:hover, .link-black:focus { + color: black !important; +} + +.link-white { + color: #fff !important; +} +.link-white:hover, .link-white:focus { + color: white !important; +} + +.link-red { + color: #e81500 !important; +} +.link-red:hover, .link-red:focus { + color: #ba1100 !important; +} + +.link-orange { + color: #f76400 !important; +} +.link-orange:hover, .link-orange:focus { + color: #c65000 !important; +} + +.link-yellow { + color: #f4a100 !important; +} +.link-yellow:hover, .link-yellow:focus { + color: #c38100 !important; +} + +.link-green { + color: #00ac69 !important; +} +.link-green:hover, .link-green:focus { + color: #008a54 !important; +} + +.link-teal { + color: #00ba94 !important; +} +.link-teal:hover, .link-teal:focus { + color: #009576 !important; +} + +.link-cyan { + color: #00cfd5 !important; +} +.link-cyan:hover, .link-cyan:focus { + color: #00a6aa !important; +} + +.link-blue { + color: #0061f2 !important; +} +.link-blue:hover, .link-blue:focus { + color: #004ec2 !important; +} + +.link-indigo { + color: #5800e8 !important; +} +.link-indigo:hover, .link-indigo:focus { + color: #4600ba !important; +} + +.link-purple { + color: #6900c7 !important; +} +.link-purple:hover, .link-purple:focus { + color: #54009f !important; +} + +.link-pink { + color: #e30059 !important; +} +.link-pink:hover, .link-pink:focus { + color: #b60047 !important; +} + +.link-red-soft { + color: #f1e0e3 !important; +} +.link-red-soft:hover, .link-red-soft:focus { + color: #f4e6e9 !important; +} + +.link-orange-soft { + color: #f3e7e3 !important; +} +.link-orange-soft:hover, .link-orange-soft:focus { + color: #f5ece9 !important; +} + +.link-yellow-soft { + color: #f2eee3 !important; +} +.link-yellow-soft:hover, .link-yellow-soft:focus { + color: #f5f1e9 !important; +} + +.link-green-soft { + color: #daefed !important; +} +.link-green-soft:hover, .link-green-soft:focus { + color: #e1f2f1 !important; +} + +.link-teal-soft { + color: #daf0f2 !important; +} +.link-teal-soft:hover, .link-teal-soft:focus { + color: #e1f3f5 !important; +} + +.link-cyan-soft { + color: #daf2f8 !important; +} +.link-cyan-soft:hover, .link-cyan-soft:focus { + color: #e1f5f9 !important; +} + +.link-blue-soft { + color: #dae7fb !important; +} +.link-blue-soft:hover, .link-blue-soft:focus { + color: #e1ecfc !important; +} + +.link-indigo-soft { + color: #e3ddfa !important; +} +.link-indigo-soft:hover, .link-indigo-soft:focus { + color: #e9e4fb !important; +} + +.link-purple-soft { + color: #e4ddf7 !important; +} +.link-purple-soft:hover, .link-purple-soft:focus { + color: #e9e4f9 !important; +} + +.link-pink-soft { + color: #f1ddec !important; +} +.link-pink-soft:hover, .link-pink-soft:focus { + color: #f4e4f0 !important; +} + +.link-primary-soft { + color: #dae7fb !important; +} +.link-primary-soft:hover, .link-primary-soft:focus { + color: #e1ecfc !important; +} + +.link-secondary-soft { + color: #e4ddf7 !important; +} +.link-secondary-soft:hover, .link-secondary-soft:focus { + color: #e9e4f9 !important; +} + +.link-success-soft { + color: #daefed !important; +} +.link-success-soft:hover, .link-success-soft:focus { + color: #e1f2f1 !important; +} + +.link-info-soft { + color: #daf2f8 !important; +} +.link-info-soft:hover, .link-info-soft:focus { + color: #e1f5f9 !important; +} + +.link-warning-soft { + color: #f2eee3 !important; +} +.link-warning-soft:hover, .link-warning-soft:focus { + color: #f5f1e9 !important; +} + +.link-danger-soft { + color: #f1e0e3 !important; +} +.link-danger-soft:hover, .link-danger-soft:focus { + color: #f4e6e9 !important; +} + +.ratio { + position: relative; + width: 100%; +} +.ratio::before { + display: block; + padding-top: var(--bs-aspect-ratio); + content: ""; +} +.ratio > * { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.ratio-1x1 { + --bs-aspect-ratio: 100%; +} + +.ratio-4x3 { + --bs-aspect-ratio: 75%; +} + +.ratio-16x9 { + --bs-aspect-ratio: 56.25%; +} + +.ratio-21x9 { + --bs-aspect-ratio: 42.8571428571%; +} + +.fixed-top, .nav-fixed #layoutSidenav #layoutSidenav_nav, .nav-fixed .topnav { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; +} + +.sticky-top, .nav-sticky { + position: sticky; + top: 0; + z-index: 1020; +} + +.sticky-bottom { + position: sticky; + bottom: 0; + z-index: 1020; +} + +@media (min-width: 576px) { + .sticky-sm-top { + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-sm-bottom { + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 768px) { + .sticky-md-top { + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-md-bottom { + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 992px) { + .sticky-lg-top { + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-lg-bottom { + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 1200px) { + .sticky-xl-top { + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-xl-bottom { + position: sticky; + bottom: 0; + z-index: 1020; + } +} +@media (min-width: 1500px) { + .sticky-xxl-top { + position: sticky; + top: 0; + z-index: 1020; + } + .sticky-xxl-bottom { + position: sticky; + bottom: 0; + z-index: 1020; + } +} +.hstack { + display: flex; + flex-direction: row; + align-items: center; + align-self: stretch; +} + +.vstack { + display: flex; + flex: 1 1 auto; + flex-direction: column; + align-self: stretch; +} + +.visually-hidden, +.visually-hidden-focusable:not(:focus):not(:focus-within) { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} + +.stretched-link::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + content: ""; +} + +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.vr { + display: inline-block; + align-self: stretch; + width: 1px; + min-height: 1em; + background-color: currentcolor; + opacity: 0.25; +} + +.align-baseline { + vertical-align: baseline !important; +} + +.align-top { + vertical-align: top !important; +} + +.align-middle { + vertical-align: middle !important; +} + +.align-bottom { + vertical-align: bottom !important; +} + +.align-text-bottom { + vertical-align: text-bottom !important; +} + +.align-text-top { + vertical-align: text-top !important; +} + +.float-start { + float: left !important; +} + +.float-end { + float: right !important; +} + +.float-none { + float: none !important; +} + +.opacity-0 { + opacity: 0 !important; +} + +.opacity-25 { + opacity: 0.25 !important; +} + +.opacity-50 { + opacity: 0.5 !important; +} + +.opacity-75 { + opacity: 0.75 !important; +} + +.opacity-100 { + opacity: 1 !important; +} + +.overflow-auto { + overflow: auto !important; +} + +.overflow-hidden { + overflow: hidden !important; +} + +.overflow-visible { + overflow: visible !important; +} + +.overflow-scroll { + overflow: scroll !important; +} + +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-grid { + display: grid !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: flex !important; +} + +.d-inline-flex { + display: inline-flex !important; +} + +.d-none { + display: none !important; +} + +.shadow { + box-shadow: 0 0.15rem 1.75rem 0 rgba(33, 40, 50, 0.15) !important; +} + +.shadow-sm { + box-shadow: 0 0.125rem 0.25rem 0 rgba(33, 40, 50, 0.2) !important; +} + +.shadow-lg { + box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; +} + +.shadow-none { + box-shadow: none !important; +} + +.position-static { + position: static !important; +} + +.position-relative { + position: relative !important; +} + +.position-absolute { + position: absolute !important; +} + +.position-fixed { + position: fixed !important; +} + +.position-sticky { + position: sticky !important; +} + +.top-0 { + top: 0 !important; +} + +.top-50 { + top: 50% !important; +} + +.top-100 { + top: 100% !important; +} + +.bottom-0 { + bottom: 0 !important; +} + +.bottom-50 { + bottom: 50% !important; +} + +.bottom-100 { + bottom: 100% !important; +} + +.start-0 { + left: 0 !important; +} + +.start-50 { + left: 50% !important; +} + +.start-100 { + left: 100% !important; +} + +.end-0 { + right: 0 !important; +} + +.end-50 { + right: 50% !important; +} + +.end-100 { + right: 100% !important; +} + +.translate-middle { + transform: translate(-50%, -50%) !important; +} + +.translate-middle-x { + transform: translateX(-50%) !important; +} + +.translate-middle-y { + transform: translateY(-50%) !important; +} + +.border { + border: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-0 { + border: 0 !important; +} + +.border-top { + border-top: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-top-0 { + border-top: 0 !important; +} + +.border-end { + border-right: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-end-0 { + border-right: 0 !important; +} + +.border-bottom { + border-bottom: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-bottom-0 { + border-bottom: 0 !important; +} + +.border-start { + border-left: var(--bs-border-width) var(--bs-border-style) var(--bs-border-color) !important; +} + +.border-start-0 { + border-left: 0 !important; +} + +.border-primary { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-primary-rgb), var(--bs-border-opacity)) !important; +} + +.border-secondary { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-secondary-rgb), var(--bs-border-opacity)) !important; +} + +.border-success { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-success-rgb), var(--bs-border-opacity)) !important; +} + +.border-info { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-info-rgb), var(--bs-border-opacity)) !important; +} + +.border-warning { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-warning-rgb), var(--bs-border-opacity)) !important; +} + +.border-danger { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important; +} + +.border-light { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important; +} + +.border-dark { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-dark-rgb), var(--bs-border-opacity)) !important; +} + +.border-black { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-black-rgb), var(--bs-border-opacity)) !important; +} + +.border-white { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-white-rgb), var(--bs-border-opacity)) !important; +} + +.border-red { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-red-rgb), var(--bs-border-opacity)) !important; +} + +.border-orange { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-orange-rgb), var(--bs-border-opacity)) !important; +} + +.border-yellow { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-yellow-rgb), var(--bs-border-opacity)) !important; +} + +.border-green { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-green-rgb), var(--bs-border-opacity)) !important; +} + +.border-teal { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-teal-rgb), var(--bs-border-opacity)) !important; +} + +.border-cyan { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-cyan-rgb), var(--bs-border-opacity)) !important; +} + +.border-blue { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-blue-rgb), var(--bs-border-opacity)) !important; +} + +.border-indigo { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-indigo-rgb), var(--bs-border-opacity)) !important; +} + +.border-purple { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-purple-rgb), var(--bs-border-opacity)) !important; +} + +.border-pink { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-pink-rgb), var(--bs-border-opacity)) !important; +} + +.border-red-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-red-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-orange-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-orange-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-yellow-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-yellow-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-green-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-green-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-teal-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-teal-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-cyan-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-cyan-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-blue-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-blue-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-indigo-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-indigo-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-purple-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-purple-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-pink-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-pink-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-primary-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-primary-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-secondary-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-secondary-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-success-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-success-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-info-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-info-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-warning-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-warning-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-danger-soft { + --bs-border-opacity: 1; + border-color: rgba(var(--bs-danger-soft-rgb), var(--bs-border-opacity)) !important; +} + +.border-1 { + --bs-border-width: 1px; +} + +.border-2 { + --bs-border-width: 2px; +} + +.border-3 { + --bs-border-width: 3px; +} + +.border-4 { + --bs-border-width: 4px; +} + +.border-5 { + --bs-border-width: 5px; +} + +.border-opacity-10 { + --bs-border-opacity: 0.1; +} + +.border-opacity-25 { + --bs-border-opacity: 0.25; +} + +.border-opacity-50 { + --bs-border-opacity: 0.5; +} + +.border-opacity-75 { + --bs-border-opacity: 0.75; +} + +.border-opacity-100 { + --bs-border-opacity: 1; +} + +.w-25 { + width: 25% !important; +} + +.w-50 { + width: 50% !important; +} + +.w-75 { + width: 75% !important; +} + +.w-100 { + width: 100% !important; +} + +.w-auto { + width: auto !important; +} + +.mw-100 { + max-width: 100% !important; +} + +.vw-100 { + width: 100vw !important; +} + +.min-vw-100 { + min-width: 100vw !important; +} + +.h-25 { + height: 25% !important; +} + +.h-50 { + height: 50% !important; +} + +.h-75 { + height: 75% !important; +} + +.h-100 { + height: 100% !important; +} + +.h-auto { + height: auto !important; +} + +.mh-100 { + max-height: 100% !important; +} + +.vh-100 { + height: 100vh !important; +} + +.min-vh-100 { + min-height: 100vh !important; +} + +.flex-fill { + flex: 1 1 auto !important; +} + +.flex-row { + flex-direction: row !important; +} + +.flex-column { + flex-direction: column !important; +} + +.flex-row-reverse { + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + flex-direction: column-reverse !important; +} + +.flex-grow-0 { + flex-grow: 0 !important; +} + +.flex-grow-1 { + flex-grow: 1 !important; +} + +.flex-shrink-0 { + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + flex-shrink: 1 !important; +} + +.flex-wrap { + flex-wrap: wrap !important; +} + +.flex-nowrap { + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + flex-wrap: wrap-reverse !important; +} + +.justify-content-start { + justify-content: flex-start !important; +} + +.justify-content-end { + justify-content: flex-end !important; +} + +.justify-content-center { + justify-content: center !important; +} + +.justify-content-between { + justify-content: space-between !important; +} + +.justify-content-around { + justify-content: space-around !important; +} + +.justify-content-evenly { + justify-content: space-evenly !important; +} + +.align-items-start { + align-items: flex-start !important; +} + +.align-items-end { + align-items: flex-end !important; +} + +.align-items-center { + align-items: center !important; +} + +.align-items-baseline { + align-items: baseline !important; +} + +.align-items-stretch { + align-items: stretch !important; +} + +.align-content-start { + align-content: flex-start !important; +} + +.align-content-end { + align-content: flex-end !important; +} + +.align-content-center { + align-content: center !important; +} + +.align-content-between { + align-content: space-between !important; +} + +.align-content-around { + align-content: space-around !important; +} + +.align-content-stretch { + align-content: stretch !important; +} + +.align-self-auto { + align-self: auto !important; +} + +.align-self-start { + align-self: flex-start !important; +} + +.align-self-end { + align-self: flex-end !important; +} + +.align-self-center { + align-self: center !important; +} + +.align-self-baseline { + align-self: baseline !important; +} + +.align-self-stretch { + align-self: stretch !important; +} + +.order-first { + order: -1 !important; +} + +.order-0 { + order: 0 !important; +} + +.order-1 { + order: 1 !important; +} + +.order-2 { + order: 2 !important; +} + +.order-3 { + order: 3 !important; +} + +.order-4 { + order: 4 !important; +} + +.order-5 { + order: 5 !important; +} + +.order-last { + order: 6 !important; +} + +.m-0 { + margin: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.m-5 { + margin: 2.5rem !important; +} + +.m-10 { + margin: 6rem !important; +} + +.m-15 { + margin: 9rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mx-0 { + margin-right: 0 !important; + margin-left: 0 !important; +} + +.mx-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; +} + +.mx-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; +} + +.mx-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; +} + +.mx-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; +} + +.mx-5 { + margin-right: 2.5rem !important; + margin-left: 2.5rem !important; +} + +.mx-10 { + margin-right: 6rem !important; + margin-left: 6rem !important; +} + +.mx-15 { + margin-right: 9rem !important; + margin-left: 9rem !important; +} + +.mx-auto { + margin-right: auto !important; + margin-left: auto !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.my-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.my-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.my-5 { + margin-top: 2.5rem !important; + margin-bottom: 2.5rem !important; +} + +.my-10 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; +} + +.my-15 { + margin-top: 9rem !important; + margin-bottom: 9rem !important; +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mt-3 { + margin-top: 1rem !important; +} + +.mt-4 { + margin-top: 1.5rem !important; +} + +.mt-5 { + margin-top: 2.5rem !important; +} + +.mt-10 { + margin-top: 6rem !important; +} + +.mt-15 { + margin-top: 9rem !important; +} + +.mt-auto { + margin-top: auto !important; +} + +.me-0 { + margin-right: 0 !important; +} + +.me-1 { + margin-right: 0.25rem !important; +} + +.me-2 { + margin-right: 0.5rem !important; +} + +.me-3 { + margin-right: 1rem !important; +} + +.me-4 { + margin-right: 1.5rem !important; +} + +.me-5 { + margin-right: 2.5rem !important; +} + +.me-10 { + margin-right: 6rem !important; +} + +.me-15 { + margin-right: 9rem !important; +} + +.me-auto { + margin-right: auto !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.mb-3 { + margin-bottom: 1rem !important; +} + +.mb-4 { + margin-bottom: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 2.5rem !important; +} + +.mb-10 { + margin-bottom: 6rem !important; +} + +.mb-15 { + margin-bottom: 9rem !important; +} + +.mb-auto { + margin-bottom: auto !important; +} + +.ms-0 { + margin-left: 0 !important; +} + +.ms-1 { + margin-left: 0.25rem !important; +} + +.ms-2 { + margin-left: 0.5rem !important; +} + +.ms-3 { + margin-left: 1rem !important; +} + +.ms-4 { + margin-left: 1.5rem !important; +} + +.ms-5 { + margin-left: 2.5rem !important; +} + +.ms-10 { + margin-left: 6rem !important; +} + +.ms-15 { + margin-left: 9rem !important; +} + +.ms-auto { + margin-left: auto !important; +} + +.m-n1 { + margin: -0.25rem !important; +} + +.m-n2 { + margin: -0.5rem !important; +} + +.m-n3 { + margin: -1rem !important; +} + +.m-n4 { + margin: -1.5rem !important; +} + +.m-n5 { + margin: -2.5rem !important; +} + +.m-n10 { + margin: -6rem !important; +} + +.m-n15 { + margin: -9rem !important; +} + +.mx-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; +} + +.mx-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; +} + +.mx-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; +} + +.mx-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; +} + +.mx-n5 { + margin-right: -2.5rem !important; + margin-left: -2.5rem !important; +} + +.mx-n10 { + margin-right: -6rem !important; + margin-left: -6rem !important; +} + +.mx-n15 { + margin-right: -9rem !important; + margin-left: -9rem !important; +} + +.my-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; +} + +.my-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; +} + +.my-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; +} + +.my-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; +} + +.my-n5 { + margin-top: -2.5rem !important; + margin-bottom: -2.5rem !important; +} + +.my-n10 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; +} + +.my-n15 { + margin-top: -9rem !important; + margin-bottom: -9rem !important; +} + +.mt-n1 { + margin-top: -0.25rem !important; +} + +.mt-n2 { + margin-top: -0.5rem !important; +} + +.mt-n3 { + margin-top: -1rem !important; +} + +.mt-n4 { + margin-top: -1.5rem !important; +} + +.mt-n5 { + margin-top: -2.5rem !important; +} + +.mt-n10 { + margin-top: -6rem !important; +} + +.mt-n15 { + margin-top: -9rem !important; +} + +.me-n1 { + margin-right: -0.25rem !important; +} + +.me-n2 { + margin-right: -0.5rem !important; +} + +.me-n3 { + margin-right: -1rem !important; +} + +.me-n4 { + margin-right: -1.5rem !important; +} + +.me-n5 { + margin-right: -2.5rem !important; +} + +.me-n10 { + margin-right: -6rem !important; +} + +.me-n15 { + margin-right: -9rem !important; +} + +.mb-n1 { + margin-bottom: -0.25rem !important; +} + +.mb-n2 { + margin-bottom: -0.5rem !important; +} + +.mb-n3 { + margin-bottom: -1rem !important; +} + +.mb-n4 { + margin-bottom: -1.5rem !important; +} + +.mb-n5 { + margin-bottom: -2.5rem !important; +} + +.mb-n10 { + margin-bottom: -6rem !important; +} + +.mb-n15 { + margin-bottom: -9rem !important; +} + +.ms-n1 { + margin-left: -0.25rem !important; +} + +.ms-n2 { + margin-left: -0.5rem !important; +} + +.ms-n3 { + margin-left: -1rem !important; +} + +.ms-n4 { + margin-left: -1.5rem !important; +} + +.ms-n5 { + margin-left: -2.5rem !important; +} + +.ms-n10 { + margin-left: -6rem !important; +} + +.ms-n15 { + margin-left: -9rem !important; +} + +.p-0 { + padding: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.p-5 { + padding: 2.5rem !important; +} + +.p-10 { + padding: 6rem !important; +} + +.p-15 { + padding: 9rem !important; +} + +.px-0 { + padding-right: 0 !important; + padding-left: 0 !important; +} + +.px-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; +} + +.px-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; +} + +.px-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; +} + +.px-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; +} + +.px-5 { + padding-right: 2.5rem !important; + padding-left: 2.5rem !important; +} + +.px-10 { + padding-right: 6rem !important; + padding-left: 6rem !important; +} + +.px-15 { + padding-right: 9rem !important; + padding-left: 9rem !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.py-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.py-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.py-5 { + padding-top: 2.5rem !important; + padding-bottom: 2.5rem !important; +} + +.py-10 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; +} + +.py-15 { + padding-top: 9rem !important; + padding-bottom: 9rem !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pt-3 { + padding-top: 1rem !important; +} + +.pt-4 { + padding-top: 1.5rem !important; +} + +.pt-5 { + padding-top: 2.5rem !important; +} + +.pt-10 { + padding-top: 6rem !important; +} + +.pt-15 { + padding-top: 9rem !important; +} + +.pe-0 { + padding-right: 0 !important; +} + +.pe-1 { + padding-right: 0.25rem !important; +} + +.pe-2 { + padding-right: 0.5rem !important; +} + +.pe-3 { + padding-right: 1rem !important; +} + +.pe-4 { + padding-right: 1.5rem !important; +} + +.pe-5 { + padding-right: 2.5rem !important; +} + +.pe-10 { + padding-right: 6rem !important; +} + +.pe-15 { + padding-right: 9rem !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pb-3 { + padding-bottom: 1rem !important; +} + +.pb-4 { + padding-bottom: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 2.5rem !important; +} + +.pb-10 { + padding-bottom: 6rem !important; +} + +.pb-15 { + padding-bottom: 9rem !important; +} + +.ps-0 { + padding-left: 0 !important; +} + +.ps-1 { + padding-left: 0.25rem !important; +} + +.ps-2 { + padding-left: 0.5rem !important; +} + +.ps-3 { + padding-left: 1rem !important; +} + +.ps-4 { + padding-left: 1.5rem !important; +} + +.ps-5 { + padding-left: 2.5rem !important; +} + +.ps-10 { + padding-left: 6rem !important; +} + +.ps-15 { + padding-left: 9rem !important; +} + +.gap-0 { + gap: 0 !important; +} + +.gap-1 { + gap: 0.25rem !important; +} + +.gap-2 { + gap: 0.5rem !important; +} + +.gap-3 { + gap: 1rem !important; +} + +.gap-4 { + gap: 1.5rem !important; +} + +.gap-5 { + gap: 2.5rem !important; +} + +.gap-10 { + gap: 6rem !important; +} + +.gap-15 { + gap: 9rem !important; +} + +.font-monospace { + font-family: var(--bs-font-monospace) !important; +} + +.fs-1 { + font-size: calc(1.275rem + 0.3vw) !important; +} + +.fs-2 { + font-size: calc(1.265rem + 0.18vw) !important; +} + +.fs-3 { + font-size: calc(1.255rem + 0.06vw) !important; +} + +.fs-4 { + font-size: 1.2rem !important; +} + +.fs-5 { + font-size: 1.1rem !important; +} + +.fs-6 { + font-size: 1rem !important; +} + +.fst-italic { + font-style: italic !important; +} + +.fst-normal { + font-style: normal !important; +} + +.fw-light { + font-weight: 300 !important; +} + +.fw-lighter { + font-weight: lighter !important; +} + +.fw-normal { + font-weight: 400 !important; +} + +.fw-bold { + font-weight: 500 !important; +} + +.fw-semibold { + font-weight: 600 !important; +} + +.fw-bolder { + font-weight: bolder !important; +} + +.lh-1 { + line-height: 1 !important; +} + +.lh-sm { + line-height: 1.25 !important; +} + +.lh-base { + line-height: 1.5 !important; +} + +.lh-lg { + line-height: 2 !important; +} + +.text-start { + text-align: left !important; +} + +.text-end { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +.text-decoration-none { + text-decoration: none !important; +} + +.text-decoration-underline { + text-decoration: underline !important; +} + +.text-decoration-line-through { + text-decoration: line-through !important; +} + +.text-lowercase { + text-transform: lowercase !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +.text-capitalize { + text-transform: capitalize !important; +} + +.text-wrap { + white-space: normal !important; +} + +.text-nowrap { + white-space: nowrap !important; +} + +/* rtl:begin:remove */ +.text-break { + word-wrap: break-word !important; + word-break: break-word !important; +} + +/* rtl:end:remove */ +.text-primary { + --bs-text-opacity: 1; + color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important; +} + +.text-secondary { + --bs-text-opacity: 1; + color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important; +} + +.text-success { + --bs-text-opacity: 1; + color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important; +} + +.text-info { + --bs-text-opacity: 1; + color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important; +} + +.text-warning { + --bs-text-opacity: 1; + color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important; +} + +.text-danger { + --bs-text-opacity: 1; + color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important; +} + +.text-light { + --bs-text-opacity: 1; + color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important; +} + +.text-dark { + --bs-text-opacity: 1; + color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important; +} + +.text-black { + --bs-text-opacity: 1; + color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important; +} + +.text-white { + --bs-text-opacity: 1; + color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important; +} + +.text-red { + --bs-text-opacity: 1; + color: rgba(var(--bs-red-rgb), var(--bs-text-opacity)) !important; +} + +.text-orange { + --bs-text-opacity: 1; + color: rgba(var(--bs-orange-rgb), var(--bs-text-opacity)) !important; +} + +.text-yellow { + --bs-text-opacity: 1; + color: rgba(var(--bs-yellow-rgb), var(--bs-text-opacity)) !important; +} + +.text-green { + --bs-text-opacity: 1; + color: rgba(var(--bs-green-rgb), var(--bs-text-opacity)) !important; +} + +.text-teal { + --bs-text-opacity: 1; + color: rgba(var(--bs-teal-rgb), var(--bs-text-opacity)) !important; +} + +.text-cyan { + --bs-text-opacity: 1; + color: rgba(var(--bs-cyan-rgb), var(--bs-text-opacity)) !important; +} + +.text-blue { + --bs-text-opacity: 1; + color: rgba(var(--bs-blue-rgb), var(--bs-text-opacity)) !important; +} + +.text-indigo { + --bs-text-opacity: 1; + color: rgba(var(--bs-indigo-rgb), var(--bs-text-opacity)) !important; +} + +.text-purple { + --bs-text-opacity: 1; + color: rgba(var(--bs-purple-rgb), var(--bs-text-opacity)) !important; +} + +.text-pink { + --bs-text-opacity: 1; + color: rgba(var(--bs-pink-rgb), var(--bs-text-opacity)) !important; +} + +.text-red-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-red-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-orange-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-orange-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-yellow-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-yellow-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-green-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-green-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-teal-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-teal-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-cyan-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-cyan-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-blue-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-blue-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-indigo-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-indigo-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-purple-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-purple-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-pink-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-pink-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-primary-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-primary-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-secondary-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-secondary-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-success-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-success-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-info-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-info-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-warning-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-warning-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-danger-soft { + --bs-text-opacity: 1; + color: rgba(var(--bs-danger-soft-rgb), var(--bs-text-opacity)) !important; +} + +.text-body { + --bs-text-opacity: 1; + color: rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important; +} + +.text-muted { + --bs-text-opacity: 1; + color: #a7aeb8 !important; +} + +.text-black-50 { + --bs-text-opacity: 1; + color: rgba(0, 0, 0, 0.5) !important; +} + +.text-white-50 { + --bs-text-opacity: 1; + color: rgba(255, 255, 255, 0.5) !important; +} + +.text-reset, .footer-admin a { + --bs-text-opacity: 1; + color: inherit !important; +} + +.text-opacity-25 { + --bs-text-opacity: 0.25; +} + +.text-opacity-50 { + --bs-text-opacity: 0.5; +} + +.text-opacity-75 { + --bs-text-opacity: 0.75; +} + +.text-opacity-100 { + --bs-text-opacity: 1; +} + +.bg-primary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-secondary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-success { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-info { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-warning { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-danger { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-light { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-dark { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-black { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-white { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-red { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-red-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-orange { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-orange-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-yellow { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-yellow-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-green { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-green-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-teal { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-teal-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-cyan { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-cyan-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-blue { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-blue-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-indigo { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-indigo-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-purple { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-purple-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-pink { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-pink-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-red-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-red-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-orange-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-orange-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-yellow-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-yellow-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-green-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-green-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-teal-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-teal-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-cyan-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-cyan-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-blue-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-blue-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-indigo-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-indigo-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-purple-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-purple-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-pink-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-pink-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-primary-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-primary-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-secondary-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-secondary-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-success-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-success-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-info-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-info-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-warning-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-warning-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-danger-soft { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-danger-soft-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-body { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-transparent { + --bs-bg-opacity: 1; + background-color: transparent !important; +} + +.bg-opacity-10 { + --bs-bg-opacity: 0.1; +} + +.bg-opacity-25 { + --bs-bg-opacity: 0.25; +} + +.bg-opacity-50 { + --bs-bg-opacity: 0.5; +} + +.bg-opacity-75 { + --bs-bg-opacity: 0.75; +} + +.bg-opacity-100 { + --bs-bg-opacity: 1; +} + +.bg-gradient { + background-image: var(--bs-gradient) !important; +} + +.user-select-all { + -webkit-user-select: all !important; + -moz-user-select: all !important; + user-select: all !important; +} + +.user-select-auto { + -webkit-user-select: auto !important; + -moz-user-select: auto !important; + user-select: auto !important; +} + +.user-select-none { + -webkit-user-select: none !important; + -moz-user-select: none !important; + user-select: none !important; +} + +.pe-none { + pointer-events: none !important; +} + +.pe-auto { + pointer-events: auto !important; +} + +.rounded { + border-radius: var(--bs-border-radius) !important; +} + +.rounded-0 { + border-radius: 0 !important; +} + +.rounded-1 { + border-radius: var(--bs-border-radius-sm) !important; +} + +.rounded-2 { + border-radius: var(--bs-border-radius) !important; +} + +.rounded-3 { + border-radius: var(--bs-border-radius-lg) !important; +} + +.rounded-4 { + border-radius: var(--bs-border-radius-xl) !important; +} + +.rounded-5 { + border-radius: var(--bs-border-radius-2xl) !important; +} + +.rounded-circle { + border-radius: 50% !important; +} + +.rounded-pill { + border-radius: var(--bs-border-radius-pill) !important; +} + +.rounded-top { + border-top-left-radius: var(--bs-border-radius) !important; + border-top-right-radius: var(--bs-border-radius) !important; +} + +.rounded-end { + border-top-right-radius: var(--bs-border-radius) !important; + border-bottom-right-radius: var(--bs-border-radius) !important; +} + +.rounded-bottom { + border-bottom-right-radius: var(--bs-border-radius) !important; + border-bottom-left-radius: var(--bs-border-radius) !important; +} + +.rounded-start { + border-bottom-left-radius: var(--bs-border-radius) !important; + border-top-left-radius: var(--bs-border-radius) !important; +} + +.visible { + visibility: visible !important; +} + +.invisible { + visibility: hidden !important; +} + +@media (min-width: 576px) { + .float-sm-start { + float: left !important; + } + .float-sm-end { + float: right !important; + } + .float-sm-none { + float: none !important; + } + .d-sm-inline { + display: inline !important; + } + .d-sm-inline-block { + display: inline-block !important; + } + .d-sm-block { + display: block !important; + } + .d-sm-grid { + display: grid !important; + } + .d-sm-table { + display: table !important; + } + .d-sm-table-row { + display: table-row !important; + } + .d-sm-table-cell { + display: table-cell !important; + } + .d-sm-flex { + display: flex !important; + } + .d-sm-inline-flex { + display: inline-flex !important; + } + .d-sm-none { + display: none !important; + } + .flex-sm-fill { + flex: 1 1 auto !important; + } + .flex-sm-row { + flex-direction: row !important; + } + .flex-sm-column { + flex-direction: column !important; + } + .flex-sm-row-reverse { + flex-direction: row-reverse !important; + } + .flex-sm-column-reverse { + flex-direction: column-reverse !important; + } + .flex-sm-grow-0 { + flex-grow: 0 !important; + } + .flex-sm-grow-1 { + flex-grow: 1 !important; + } + .flex-sm-shrink-0 { + flex-shrink: 0 !important; + } + .flex-sm-shrink-1 { + flex-shrink: 1 !important; + } + .flex-sm-wrap { + flex-wrap: wrap !important; + } + .flex-sm-nowrap { + flex-wrap: nowrap !important; + } + .flex-sm-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-sm-start { + justify-content: flex-start !important; + } + .justify-content-sm-end { + justify-content: flex-end !important; + } + .justify-content-sm-center { + justify-content: center !important; + } + .justify-content-sm-between { + justify-content: space-between !important; + } + .justify-content-sm-around { + justify-content: space-around !important; + } + .justify-content-sm-evenly { + justify-content: space-evenly !important; + } + .align-items-sm-start { + align-items: flex-start !important; + } + .align-items-sm-end { + align-items: flex-end !important; + } + .align-items-sm-center { + align-items: center !important; + } + .align-items-sm-baseline { + align-items: baseline !important; + } + .align-items-sm-stretch { + align-items: stretch !important; + } + .align-content-sm-start { + align-content: flex-start !important; + } + .align-content-sm-end { + align-content: flex-end !important; + } + .align-content-sm-center { + align-content: center !important; + } + .align-content-sm-between { + align-content: space-between !important; + } + .align-content-sm-around { + align-content: space-around !important; + } + .align-content-sm-stretch { + align-content: stretch !important; + } + .align-self-sm-auto { + align-self: auto !important; + } + .align-self-sm-start { + align-self: flex-start !important; + } + .align-self-sm-end { + align-self: flex-end !important; + } + .align-self-sm-center { + align-self: center !important; + } + .align-self-sm-baseline { + align-self: baseline !important; + } + .align-self-sm-stretch { + align-self: stretch !important; + } + .order-sm-first { + order: -1 !important; + } + .order-sm-0 { + order: 0 !important; + } + .order-sm-1 { + order: 1 !important; + } + .order-sm-2 { + order: 2 !important; + } + .order-sm-3 { + order: 3 !important; + } + .order-sm-4 { + order: 4 !important; + } + .order-sm-5 { + order: 5 !important; + } + .order-sm-last { + order: 6 !important; + } + .m-sm-0 { + margin: 0 !important; + } + .m-sm-1 { + margin: 0.25rem !important; + } + .m-sm-2 { + margin: 0.5rem !important; + } + .m-sm-3 { + margin: 1rem !important; + } + .m-sm-4 { + margin: 1.5rem !important; + } + .m-sm-5 { + margin: 2.5rem !important; + } + .m-sm-10 { + margin: 6rem !important; + } + .m-sm-15 { + margin: 9rem !important; + } + .m-sm-auto { + margin: auto !important; + } + .mx-sm-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-sm-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-sm-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-sm-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-sm-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-sm-5 { + margin-right: 2.5rem !important; + margin-left: 2.5rem !important; + } + .mx-sm-10 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-sm-15 { + margin-right: 9rem !important; + margin-left: 9rem !important; + } + .mx-sm-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-sm-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-sm-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-sm-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-sm-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-sm-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-sm-5 { + margin-top: 2.5rem !important; + margin-bottom: 2.5rem !important; + } + .my-sm-10 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-sm-15 { + margin-top: 9rem !important; + margin-bottom: 9rem !important; + } + .my-sm-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-sm-0 { + margin-top: 0 !important; + } + .mt-sm-1 { + margin-top: 0.25rem !important; + } + .mt-sm-2 { + margin-top: 0.5rem !important; + } + .mt-sm-3 { + margin-top: 1rem !important; + } + .mt-sm-4 { + margin-top: 1.5rem !important; + } + .mt-sm-5 { + margin-top: 2.5rem !important; + } + .mt-sm-10 { + margin-top: 6rem !important; + } + .mt-sm-15 { + margin-top: 9rem !important; + } + .mt-sm-auto { + margin-top: auto !important; + } + .me-sm-0 { + margin-right: 0 !important; + } + .me-sm-1 { + margin-right: 0.25rem !important; + } + .me-sm-2 { + margin-right: 0.5rem !important; + } + .me-sm-3 { + margin-right: 1rem !important; + } + .me-sm-4 { + margin-right: 1.5rem !important; + } + .me-sm-5 { + margin-right: 2.5rem !important; + } + .me-sm-10 { + margin-right: 6rem !important; + } + .me-sm-15 { + margin-right: 9rem !important; + } + .me-sm-auto { + margin-right: auto !important; + } + .mb-sm-0 { + margin-bottom: 0 !important; + } + .mb-sm-1 { + margin-bottom: 0.25rem !important; + } + .mb-sm-2 { + margin-bottom: 0.5rem !important; + } + .mb-sm-3 { + margin-bottom: 1rem !important; + } + .mb-sm-4 { + margin-bottom: 1.5rem !important; + } + .mb-sm-5 { + margin-bottom: 2.5rem !important; + } + .mb-sm-10 { + margin-bottom: 6rem !important; + } + .mb-sm-15 { + margin-bottom: 9rem !important; + } + .mb-sm-auto { + margin-bottom: auto !important; + } + .ms-sm-0 { + margin-left: 0 !important; + } + .ms-sm-1 { + margin-left: 0.25rem !important; + } + .ms-sm-2 { + margin-left: 0.5rem !important; + } + .ms-sm-3 { + margin-left: 1rem !important; + } + .ms-sm-4 { + margin-left: 1.5rem !important; + } + .ms-sm-5 { + margin-left: 2.5rem !important; + } + .ms-sm-10 { + margin-left: 6rem !important; + } + .ms-sm-15 { + margin-left: 9rem !important; + } + .ms-sm-auto { + margin-left: auto !important; + } + .m-sm-n1 { + margin: -0.25rem !important; + } + .m-sm-n2 { + margin: -0.5rem !important; + } + .m-sm-n3 { + margin: -1rem !important; + } + .m-sm-n4 { + margin: -1.5rem !important; + } + .m-sm-n5 { + margin: -2.5rem !important; + } + .m-sm-n10 { + margin: -6rem !important; + } + .m-sm-n15 { + margin: -9rem !important; + } + .mx-sm-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-sm-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-sm-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-sm-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-sm-n5 { + margin-right: -2.5rem !important; + margin-left: -2.5rem !important; + } + .mx-sm-n10 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .mx-sm-n15 { + margin-right: -9rem !important; + margin-left: -9rem !important; + } + .my-sm-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-sm-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-sm-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-sm-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-sm-n5 { + margin-top: -2.5rem !important; + margin-bottom: -2.5rem !important; + } + .my-sm-n10 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .my-sm-n15 { + margin-top: -9rem !important; + margin-bottom: -9rem !important; + } + .mt-sm-n1 { + margin-top: -0.25rem !important; + } + .mt-sm-n2 { + margin-top: -0.5rem !important; + } + .mt-sm-n3 { + margin-top: -1rem !important; + } + .mt-sm-n4 { + margin-top: -1.5rem !important; + } + .mt-sm-n5 { + margin-top: -2.5rem !important; + } + .mt-sm-n10 { + margin-top: -6rem !important; + } + .mt-sm-n15 { + margin-top: -9rem !important; + } + .me-sm-n1 { + margin-right: -0.25rem !important; + } + .me-sm-n2 { + margin-right: -0.5rem !important; + } + .me-sm-n3 { + margin-right: -1rem !important; + } + .me-sm-n4 { + margin-right: -1.5rem !important; + } + .me-sm-n5 { + margin-right: -2.5rem !important; + } + .me-sm-n10 { + margin-right: -6rem !important; + } + .me-sm-n15 { + margin-right: -9rem !important; + } + .mb-sm-n1 { + margin-bottom: -0.25rem !important; + } + .mb-sm-n2 { + margin-bottom: -0.5rem !important; + } + .mb-sm-n3 { + margin-bottom: -1rem !important; + } + .mb-sm-n4 { + margin-bottom: -1.5rem !important; + } + .mb-sm-n5 { + margin-bottom: -2.5rem !important; + } + .mb-sm-n10 { + margin-bottom: -6rem !important; + } + .mb-sm-n15 { + margin-bottom: -9rem !important; + } + .ms-sm-n1 { + margin-left: -0.25rem !important; + } + .ms-sm-n2 { + margin-left: -0.5rem !important; + } + .ms-sm-n3 { + margin-left: -1rem !important; + } + .ms-sm-n4 { + margin-left: -1.5rem !important; + } + .ms-sm-n5 { + margin-left: -2.5rem !important; + } + .ms-sm-n10 { + margin-left: -6rem !important; + } + .ms-sm-n15 { + margin-left: -9rem !important; + } + .p-sm-0 { + padding: 0 !important; + } + .p-sm-1 { + padding: 0.25rem !important; + } + .p-sm-2 { + padding: 0.5rem !important; + } + .p-sm-3 { + padding: 1rem !important; + } + .p-sm-4 { + padding: 1.5rem !important; + } + .p-sm-5 { + padding: 2.5rem !important; + } + .p-sm-10 { + padding: 6rem !important; + } + .p-sm-15 { + padding: 9rem !important; + } + .px-sm-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-sm-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-sm-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-sm-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-sm-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-sm-5 { + padding-right: 2.5rem !important; + padding-left: 2.5rem !important; + } + .px-sm-10 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .px-sm-15 { + padding-right: 9rem !important; + padding-left: 9rem !important; + } + .py-sm-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-sm-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-sm-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-sm-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-sm-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-sm-5 { + padding-top: 2.5rem !important; + padding-bottom: 2.5rem !important; + } + .py-sm-10 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .py-sm-15 { + padding-top: 9rem !important; + padding-bottom: 9rem !important; + } + .pt-sm-0 { + padding-top: 0 !important; + } + .pt-sm-1 { + padding-top: 0.25rem !important; + } + .pt-sm-2 { + padding-top: 0.5rem !important; + } + .pt-sm-3 { + padding-top: 1rem !important; + } + .pt-sm-4 { + padding-top: 1.5rem !important; + } + .pt-sm-5 { + padding-top: 2.5rem !important; + } + .pt-sm-10 { + padding-top: 6rem !important; + } + .pt-sm-15 { + padding-top: 9rem !important; + } + .pe-sm-0 { + padding-right: 0 !important; + } + .pe-sm-1 { + padding-right: 0.25rem !important; + } + .pe-sm-2 { + padding-right: 0.5rem !important; + } + .pe-sm-3 { + padding-right: 1rem !important; + } + .pe-sm-4 { + padding-right: 1.5rem !important; + } + .pe-sm-5 { + padding-right: 2.5rem !important; + } + .pe-sm-10 { + padding-right: 6rem !important; + } + .pe-sm-15 { + padding-right: 9rem !important; + } + .pb-sm-0 { + padding-bottom: 0 !important; + } + .pb-sm-1 { + padding-bottom: 0.25rem !important; + } + .pb-sm-2 { + padding-bottom: 0.5rem !important; + } + .pb-sm-3 { + padding-bottom: 1rem !important; + } + .pb-sm-4 { + padding-bottom: 1.5rem !important; + } + .pb-sm-5 { + padding-bottom: 2.5rem !important; + } + .pb-sm-10 { + padding-bottom: 6rem !important; + } + .pb-sm-15 { + padding-bottom: 9rem !important; + } + .ps-sm-0 { + padding-left: 0 !important; + } + .ps-sm-1 { + padding-left: 0.25rem !important; + } + .ps-sm-2 { + padding-left: 0.5rem !important; + } + .ps-sm-3 { + padding-left: 1rem !important; + } + .ps-sm-4 { + padding-left: 1.5rem !important; + } + .ps-sm-5 { + padding-left: 2.5rem !important; + } + .ps-sm-10 { + padding-left: 6rem !important; + } + .ps-sm-15 { + padding-left: 9rem !important; + } + .gap-sm-0 { + gap: 0 !important; + } + .gap-sm-1 { + gap: 0.25rem !important; + } + .gap-sm-2 { + gap: 0.5rem !important; + } + .gap-sm-3 { + gap: 1rem !important; + } + .gap-sm-4 { + gap: 1.5rem !important; + } + .gap-sm-5 { + gap: 2.5rem !important; + } + .gap-sm-10 { + gap: 6rem !important; + } + .gap-sm-15 { + gap: 9rem !important; + } + .text-sm-start { + text-align: left !important; + } + .text-sm-end { + text-align: right !important; + } + .text-sm-center { + text-align: center !important; + } +} +@media (min-width: 768px) { + .float-md-start { + float: left !important; + } + .float-md-end { + float: right !important; + } + .float-md-none { + float: none !important; + } + .d-md-inline { + display: inline !important; + } + .d-md-inline-block { + display: inline-block !important; + } + .d-md-block { + display: block !important; + } + .d-md-grid { + display: grid !important; + } + .d-md-table { + display: table !important; + } + .d-md-table-row { + display: table-row !important; + } + .d-md-table-cell { + display: table-cell !important; + } + .d-md-flex { + display: flex !important; + } + .d-md-inline-flex { + display: inline-flex !important; + } + .d-md-none { + display: none !important; + } + .flex-md-fill { + flex: 1 1 auto !important; + } + .flex-md-row { + flex-direction: row !important; + } + .flex-md-column { + flex-direction: column !important; + } + .flex-md-row-reverse { + flex-direction: row-reverse !important; + } + .flex-md-column-reverse { + flex-direction: column-reverse !important; + } + .flex-md-grow-0 { + flex-grow: 0 !important; + } + .flex-md-grow-1 { + flex-grow: 1 !important; + } + .flex-md-shrink-0 { + flex-shrink: 0 !important; + } + .flex-md-shrink-1 { + flex-shrink: 1 !important; + } + .flex-md-wrap { + flex-wrap: wrap !important; + } + .flex-md-nowrap { + flex-wrap: nowrap !important; + } + .flex-md-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-md-start { + justify-content: flex-start !important; + } + .justify-content-md-end { + justify-content: flex-end !important; + } + .justify-content-md-center { + justify-content: center !important; + } + .justify-content-md-between { + justify-content: space-between !important; + } + .justify-content-md-around { + justify-content: space-around !important; + } + .justify-content-md-evenly { + justify-content: space-evenly !important; + } + .align-items-md-start { + align-items: flex-start !important; + } + .align-items-md-end { + align-items: flex-end !important; + } + .align-items-md-center { + align-items: center !important; + } + .align-items-md-baseline { + align-items: baseline !important; + } + .align-items-md-stretch { + align-items: stretch !important; + } + .align-content-md-start { + align-content: flex-start !important; + } + .align-content-md-end { + align-content: flex-end !important; + } + .align-content-md-center { + align-content: center !important; + } + .align-content-md-between { + align-content: space-between !important; + } + .align-content-md-around { + align-content: space-around !important; + } + .align-content-md-stretch { + align-content: stretch !important; + } + .align-self-md-auto { + align-self: auto !important; + } + .align-self-md-start { + align-self: flex-start !important; + } + .align-self-md-end { + align-self: flex-end !important; + } + .align-self-md-center { + align-self: center !important; + } + .align-self-md-baseline { + align-self: baseline !important; + } + .align-self-md-stretch { + align-self: stretch !important; + } + .order-md-first { + order: -1 !important; + } + .order-md-0 { + order: 0 !important; + } + .order-md-1 { + order: 1 !important; + } + .order-md-2 { + order: 2 !important; + } + .order-md-3 { + order: 3 !important; + } + .order-md-4 { + order: 4 !important; + } + .order-md-5 { + order: 5 !important; + } + .order-md-last { + order: 6 !important; + } + .m-md-0 { + margin: 0 !important; + } + .m-md-1 { + margin: 0.25rem !important; + } + .m-md-2 { + margin: 0.5rem !important; + } + .m-md-3 { + margin: 1rem !important; + } + .m-md-4 { + margin: 1.5rem !important; + } + .m-md-5 { + margin: 2.5rem !important; + } + .m-md-10 { + margin: 6rem !important; + } + .m-md-15 { + margin: 9rem !important; + } + .m-md-auto { + margin: auto !important; + } + .mx-md-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-md-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-md-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-md-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-md-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-md-5 { + margin-right: 2.5rem !important; + margin-left: 2.5rem !important; + } + .mx-md-10 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-md-15 { + margin-right: 9rem !important; + margin-left: 9rem !important; + } + .mx-md-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-md-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-md-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-md-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-md-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-md-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-md-5 { + margin-top: 2.5rem !important; + margin-bottom: 2.5rem !important; + } + .my-md-10 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-md-15 { + margin-top: 9rem !important; + margin-bottom: 9rem !important; + } + .my-md-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-md-0 { + margin-top: 0 !important; + } + .mt-md-1 { + margin-top: 0.25rem !important; + } + .mt-md-2 { + margin-top: 0.5rem !important; + } + .mt-md-3 { + margin-top: 1rem !important; + } + .mt-md-4 { + margin-top: 1.5rem !important; + } + .mt-md-5 { + margin-top: 2.5rem !important; + } + .mt-md-10 { + margin-top: 6rem !important; + } + .mt-md-15 { + margin-top: 9rem !important; + } + .mt-md-auto { + margin-top: auto !important; + } + .me-md-0 { + margin-right: 0 !important; + } + .me-md-1 { + margin-right: 0.25rem !important; + } + .me-md-2 { + margin-right: 0.5rem !important; + } + .me-md-3 { + margin-right: 1rem !important; + } + .me-md-4 { + margin-right: 1.5rem !important; + } + .me-md-5 { + margin-right: 2.5rem !important; + } + .me-md-10 { + margin-right: 6rem !important; + } + .me-md-15 { + margin-right: 9rem !important; + } + .me-md-auto { + margin-right: auto !important; + } + .mb-md-0 { + margin-bottom: 0 !important; + } + .mb-md-1 { + margin-bottom: 0.25rem !important; + } + .mb-md-2 { + margin-bottom: 0.5rem !important; + } + .mb-md-3 { + margin-bottom: 1rem !important; + } + .mb-md-4 { + margin-bottom: 1.5rem !important; + } + .mb-md-5 { + margin-bottom: 2.5rem !important; + } + .mb-md-10 { + margin-bottom: 6rem !important; + } + .mb-md-15 { + margin-bottom: 9rem !important; + } + .mb-md-auto { + margin-bottom: auto !important; + } + .ms-md-0 { + margin-left: 0 !important; + } + .ms-md-1 { + margin-left: 0.25rem !important; + } + .ms-md-2 { + margin-left: 0.5rem !important; + } + .ms-md-3 { + margin-left: 1rem !important; + } + .ms-md-4 { + margin-left: 1.5rem !important; + } + .ms-md-5 { + margin-left: 2.5rem !important; + } + .ms-md-10 { + margin-left: 6rem !important; + } + .ms-md-15 { + margin-left: 9rem !important; + } + .ms-md-auto { + margin-left: auto !important; + } + .m-md-n1 { + margin: -0.25rem !important; + } + .m-md-n2 { + margin: -0.5rem !important; + } + .m-md-n3 { + margin: -1rem !important; + } + .m-md-n4 { + margin: -1.5rem !important; + } + .m-md-n5 { + margin: -2.5rem !important; + } + .m-md-n10 { + margin: -6rem !important; + } + .m-md-n15 { + margin: -9rem !important; + } + .mx-md-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-md-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-md-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-md-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-md-n5 { + margin-right: -2.5rem !important; + margin-left: -2.5rem !important; + } + .mx-md-n10 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .mx-md-n15 { + margin-right: -9rem !important; + margin-left: -9rem !important; + } + .my-md-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-md-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-md-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-md-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-md-n5 { + margin-top: -2.5rem !important; + margin-bottom: -2.5rem !important; + } + .my-md-n10 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .my-md-n15 { + margin-top: -9rem !important; + margin-bottom: -9rem !important; + } + .mt-md-n1 { + margin-top: -0.25rem !important; + } + .mt-md-n2 { + margin-top: -0.5rem !important; + } + .mt-md-n3 { + margin-top: -1rem !important; + } + .mt-md-n4 { + margin-top: -1.5rem !important; + } + .mt-md-n5 { + margin-top: -2.5rem !important; + } + .mt-md-n10 { + margin-top: -6rem !important; + } + .mt-md-n15 { + margin-top: -9rem !important; + } + .me-md-n1 { + margin-right: -0.25rem !important; + } + .me-md-n2 { + margin-right: -0.5rem !important; + } + .me-md-n3 { + margin-right: -1rem !important; + } + .me-md-n4 { + margin-right: -1.5rem !important; + } + .me-md-n5 { + margin-right: -2.5rem !important; + } + .me-md-n10 { + margin-right: -6rem !important; + } + .me-md-n15 { + margin-right: -9rem !important; + } + .mb-md-n1 { + margin-bottom: -0.25rem !important; + } + .mb-md-n2 { + margin-bottom: -0.5rem !important; + } + .mb-md-n3 { + margin-bottom: -1rem !important; + } + .mb-md-n4 { + margin-bottom: -1.5rem !important; + } + .mb-md-n5 { + margin-bottom: -2.5rem !important; + } + .mb-md-n10 { + margin-bottom: -6rem !important; + } + .mb-md-n15 { + margin-bottom: -9rem !important; + } + .ms-md-n1 { + margin-left: -0.25rem !important; + } + .ms-md-n2 { + margin-left: -0.5rem !important; + } + .ms-md-n3 { + margin-left: -1rem !important; + } + .ms-md-n4 { + margin-left: -1.5rem !important; + } + .ms-md-n5 { + margin-left: -2.5rem !important; + } + .ms-md-n10 { + margin-left: -6rem !important; + } + .ms-md-n15 { + margin-left: -9rem !important; + } + .p-md-0 { + padding: 0 !important; + } + .p-md-1 { + padding: 0.25rem !important; + } + .p-md-2 { + padding: 0.5rem !important; + } + .p-md-3 { + padding: 1rem !important; + } + .p-md-4 { + padding: 1.5rem !important; + } + .p-md-5 { + padding: 2.5rem !important; + } + .p-md-10 { + padding: 6rem !important; + } + .p-md-15 { + padding: 9rem !important; + } + .px-md-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-md-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-md-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-md-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-md-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-md-5 { + padding-right: 2.5rem !important; + padding-left: 2.5rem !important; + } + .px-md-10 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .px-md-15 { + padding-right: 9rem !important; + padding-left: 9rem !important; + } + .py-md-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-md-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-md-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-md-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-md-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-md-5 { + padding-top: 2.5rem !important; + padding-bottom: 2.5rem !important; + } + .py-md-10 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .py-md-15 { + padding-top: 9rem !important; + padding-bottom: 9rem !important; + } + .pt-md-0 { + padding-top: 0 !important; + } + .pt-md-1 { + padding-top: 0.25rem !important; + } + .pt-md-2 { + padding-top: 0.5rem !important; + } + .pt-md-3 { + padding-top: 1rem !important; + } + .pt-md-4 { + padding-top: 1.5rem !important; + } + .pt-md-5 { + padding-top: 2.5rem !important; + } + .pt-md-10 { + padding-top: 6rem !important; + } + .pt-md-15 { + padding-top: 9rem !important; + } + .pe-md-0 { + padding-right: 0 !important; + } + .pe-md-1 { + padding-right: 0.25rem !important; + } + .pe-md-2 { + padding-right: 0.5rem !important; + } + .pe-md-3 { + padding-right: 1rem !important; + } + .pe-md-4 { + padding-right: 1.5rem !important; + } + .pe-md-5 { + padding-right: 2.5rem !important; + } + .pe-md-10 { + padding-right: 6rem !important; + } + .pe-md-15 { + padding-right: 9rem !important; + } + .pb-md-0 { + padding-bottom: 0 !important; + } + .pb-md-1 { + padding-bottom: 0.25rem !important; + } + .pb-md-2 { + padding-bottom: 0.5rem !important; + } + .pb-md-3 { + padding-bottom: 1rem !important; + } + .pb-md-4 { + padding-bottom: 1.5rem !important; + } + .pb-md-5 { + padding-bottom: 2.5rem !important; + } + .pb-md-10 { + padding-bottom: 6rem !important; + } + .pb-md-15 { + padding-bottom: 9rem !important; + } + .ps-md-0 { + padding-left: 0 !important; + } + .ps-md-1 { + padding-left: 0.25rem !important; + } + .ps-md-2 { + padding-left: 0.5rem !important; + } + .ps-md-3 { + padding-left: 1rem !important; + } + .ps-md-4 { + padding-left: 1.5rem !important; + } + .ps-md-5 { + padding-left: 2.5rem !important; + } + .ps-md-10 { + padding-left: 6rem !important; + } + .ps-md-15 { + padding-left: 9rem !important; + } + .gap-md-0 { + gap: 0 !important; + } + .gap-md-1 { + gap: 0.25rem !important; + } + .gap-md-2 { + gap: 0.5rem !important; + } + .gap-md-3 { + gap: 1rem !important; + } + .gap-md-4 { + gap: 1.5rem !important; + } + .gap-md-5 { + gap: 2.5rem !important; + } + .gap-md-10 { + gap: 6rem !important; + } + .gap-md-15 { + gap: 9rem !important; + } + .text-md-start { + text-align: left !important; + } + .text-md-end { + text-align: right !important; + } + .text-md-center { + text-align: center !important; + } +} +@media (min-width: 992px) { + .float-lg-start { + float: left !important; + } + .float-lg-end { + float: right !important; + } + .float-lg-none { + float: none !important; + } + .d-lg-inline { + display: inline !important; + } + .d-lg-inline-block { + display: inline-block !important; + } + .d-lg-block { + display: block !important; + } + .d-lg-grid { + display: grid !important; + } + .d-lg-table { + display: table !important; + } + .d-lg-table-row { + display: table-row !important; + } + .d-lg-table-cell { + display: table-cell !important; + } + .d-lg-flex { + display: flex !important; + } + .d-lg-inline-flex { + display: inline-flex !important; + } + .d-lg-none { + display: none !important; + } + .flex-lg-fill { + flex: 1 1 auto !important; + } + .flex-lg-row { + flex-direction: row !important; + } + .flex-lg-column { + flex-direction: column !important; + } + .flex-lg-row-reverse { + flex-direction: row-reverse !important; + } + .flex-lg-column-reverse { + flex-direction: column-reverse !important; + } + .flex-lg-grow-0 { + flex-grow: 0 !important; + } + .flex-lg-grow-1 { + flex-grow: 1 !important; + } + .flex-lg-shrink-0 { + flex-shrink: 0 !important; + } + .flex-lg-shrink-1 { + flex-shrink: 1 !important; + } + .flex-lg-wrap { + flex-wrap: wrap !important; + } + .flex-lg-nowrap { + flex-wrap: nowrap !important; + } + .flex-lg-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-lg-start { + justify-content: flex-start !important; + } + .justify-content-lg-end { + justify-content: flex-end !important; + } + .justify-content-lg-center { + justify-content: center !important; + } + .justify-content-lg-between { + justify-content: space-between !important; + } + .justify-content-lg-around { + justify-content: space-around !important; + } + .justify-content-lg-evenly { + justify-content: space-evenly !important; + } + .align-items-lg-start { + align-items: flex-start !important; + } + .align-items-lg-end { + align-items: flex-end !important; + } + .align-items-lg-center { + align-items: center !important; + } + .align-items-lg-baseline { + align-items: baseline !important; + } + .align-items-lg-stretch { + align-items: stretch !important; + } + .align-content-lg-start { + align-content: flex-start !important; + } + .align-content-lg-end { + align-content: flex-end !important; + } + .align-content-lg-center { + align-content: center !important; + } + .align-content-lg-between { + align-content: space-between !important; + } + .align-content-lg-around { + align-content: space-around !important; + } + .align-content-lg-stretch { + align-content: stretch !important; + } + .align-self-lg-auto { + align-self: auto !important; + } + .align-self-lg-start { + align-self: flex-start !important; + } + .align-self-lg-end { + align-self: flex-end !important; + } + .align-self-lg-center { + align-self: center !important; + } + .align-self-lg-baseline { + align-self: baseline !important; + } + .align-self-lg-stretch { + align-self: stretch !important; + } + .order-lg-first { + order: -1 !important; + } + .order-lg-0 { + order: 0 !important; + } + .order-lg-1 { + order: 1 !important; + } + .order-lg-2 { + order: 2 !important; + } + .order-lg-3 { + order: 3 !important; + } + .order-lg-4 { + order: 4 !important; + } + .order-lg-5 { + order: 5 !important; + } + .order-lg-last { + order: 6 !important; + } + .m-lg-0 { + margin: 0 !important; + } + .m-lg-1 { + margin: 0.25rem !important; + } + .m-lg-2 { + margin: 0.5rem !important; + } + .m-lg-3 { + margin: 1rem !important; + } + .m-lg-4 { + margin: 1.5rem !important; + } + .m-lg-5 { + margin: 2.5rem !important; + } + .m-lg-10 { + margin: 6rem !important; + } + .m-lg-15 { + margin: 9rem !important; + } + .m-lg-auto { + margin: auto !important; + } + .mx-lg-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-lg-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-lg-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-lg-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-lg-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-lg-5 { + margin-right: 2.5rem !important; + margin-left: 2.5rem !important; + } + .mx-lg-10 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-lg-15 { + margin-right: 9rem !important; + margin-left: 9rem !important; + } + .mx-lg-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-lg-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-lg-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-lg-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-lg-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-lg-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-lg-5 { + margin-top: 2.5rem !important; + margin-bottom: 2.5rem !important; + } + .my-lg-10 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-lg-15 { + margin-top: 9rem !important; + margin-bottom: 9rem !important; + } + .my-lg-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-lg-0 { + margin-top: 0 !important; + } + .mt-lg-1 { + margin-top: 0.25rem !important; + } + .mt-lg-2 { + margin-top: 0.5rem !important; + } + .mt-lg-3 { + margin-top: 1rem !important; + } + .mt-lg-4 { + margin-top: 1.5rem !important; + } + .mt-lg-5 { + margin-top: 2.5rem !important; + } + .mt-lg-10 { + margin-top: 6rem !important; + } + .mt-lg-15 { + margin-top: 9rem !important; + } + .mt-lg-auto { + margin-top: auto !important; + } + .me-lg-0 { + margin-right: 0 !important; + } + .me-lg-1 { + margin-right: 0.25rem !important; + } + .me-lg-2 { + margin-right: 0.5rem !important; + } + .me-lg-3 { + margin-right: 1rem !important; + } + .me-lg-4 { + margin-right: 1.5rem !important; + } + .me-lg-5 { + margin-right: 2.5rem !important; + } + .me-lg-10 { + margin-right: 6rem !important; + } + .me-lg-15 { + margin-right: 9rem !important; + } + .me-lg-auto { + margin-right: auto !important; + } + .mb-lg-0 { + margin-bottom: 0 !important; + } + .mb-lg-1 { + margin-bottom: 0.25rem !important; + } + .mb-lg-2 { + margin-bottom: 0.5rem !important; + } + .mb-lg-3 { + margin-bottom: 1rem !important; + } + .mb-lg-4 { + margin-bottom: 1.5rem !important; + } + .mb-lg-5 { + margin-bottom: 2.5rem !important; + } + .mb-lg-10 { + margin-bottom: 6rem !important; + } + .mb-lg-15 { + margin-bottom: 9rem !important; + } + .mb-lg-auto { + margin-bottom: auto !important; + } + .ms-lg-0 { + margin-left: 0 !important; + } + .ms-lg-1 { + margin-left: 0.25rem !important; + } + .ms-lg-2 { + margin-left: 0.5rem !important; + } + .ms-lg-3 { + margin-left: 1rem !important; + } + .ms-lg-4 { + margin-left: 1.5rem !important; + } + .ms-lg-5 { + margin-left: 2.5rem !important; + } + .ms-lg-10 { + margin-left: 6rem !important; + } + .ms-lg-15 { + margin-left: 9rem !important; + } + .ms-lg-auto { + margin-left: auto !important; + } + .m-lg-n1 { + margin: -0.25rem !important; + } + .m-lg-n2 { + margin: -0.5rem !important; + } + .m-lg-n3 { + margin: -1rem !important; + } + .m-lg-n4 { + margin: -1.5rem !important; + } + .m-lg-n5 { + margin: -2.5rem !important; + } + .m-lg-n10 { + margin: -6rem !important; + } + .m-lg-n15 { + margin: -9rem !important; + } + .mx-lg-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-lg-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-lg-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-lg-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-lg-n5 { + margin-right: -2.5rem !important; + margin-left: -2.5rem !important; + } + .mx-lg-n10 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .mx-lg-n15 { + margin-right: -9rem !important; + margin-left: -9rem !important; + } + .my-lg-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-lg-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-lg-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-lg-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-lg-n5 { + margin-top: -2.5rem !important; + margin-bottom: -2.5rem !important; + } + .my-lg-n10 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .my-lg-n15 { + margin-top: -9rem !important; + margin-bottom: -9rem !important; + } + .mt-lg-n1 { + margin-top: -0.25rem !important; + } + .mt-lg-n2 { + margin-top: -0.5rem !important; + } + .mt-lg-n3 { + margin-top: -1rem !important; + } + .mt-lg-n4 { + margin-top: -1.5rem !important; + } + .mt-lg-n5 { + margin-top: -2.5rem !important; + } + .mt-lg-n10 { + margin-top: -6rem !important; + } + .mt-lg-n15 { + margin-top: -9rem !important; + } + .me-lg-n1 { + margin-right: -0.25rem !important; + } + .me-lg-n2 { + margin-right: -0.5rem !important; + } + .me-lg-n3 { + margin-right: -1rem !important; + } + .me-lg-n4 { + margin-right: -1.5rem !important; + } + .me-lg-n5 { + margin-right: -2.5rem !important; + } + .me-lg-n10 { + margin-right: -6rem !important; + } + .me-lg-n15 { + margin-right: -9rem !important; + } + .mb-lg-n1 { + margin-bottom: -0.25rem !important; + } + .mb-lg-n2 { + margin-bottom: -0.5rem !important; + } + .mb-lg-n3 { + margin-bottom: -1rem !important; + } + .mb-lg-n4 { + margin-bottom: -1.5rem !important; + } + .mb-lg-n5 { + margin-bottom: -2.5rem !important; + } + .mb-lg-n10 { + margin-bottom: -6rem !important; + } + .mb-lg-n15 { + margin-bottom: -9rem !important; + } + .ms-lg-n1 { + margin-left: -0.25rem !important; + } + .ms-lg-n2 { + margin-left: -0.5rem !important; + } + .ms-lg-n3 { + margin-left: -1rem !important; + } + .ms-lg-n4 { + margin-left: -1.5rem !important; + } + .ms-lg-n5 { + margin-left: -2.5rem !important; + } + .ms-lg-n10 { + margin-left: -6rem !important; + } + .ms-lg-n15 { + margin-left: -9rem !important; + } + .p-lg-0 { + padding: 0 !important; + } + .p-lg-1 { + padding: 0.25rem !important; + } + .p-lg-2 { + padding: 0.5rem !important; + } + .p-lg-3 { + padding: 1rem !important; + } + .p-lg-4 { + padding: 1.5rem !important; + } + .p-lg-5 { + padding: 2.5rem !important; + } + .p-lg-10 { + padding: 6rem !important; + } + .p-lg-15 { + padding: 9rem !important; + } + .px-lg-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-lg-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-lg-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-lg-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-lg-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-lg-5 { + padding-right: 2.5rem !important; + padding-left: 2.5rem !important; + } + .px-lg-10 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .px-lg-15 { + padding-right: 9rem !important; + padding-left: 9rem !important; + } + .py-lg-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-lg-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-lg-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-lg-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-lg-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-lg-5 { + padding-top: 2.5rem !important; + padding-bottom: 2.5rem !important; + } + .py-lg-10 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .py-lg-15 { + padding-top: 9rem !important; + padding-bottom: 9rem !important; + } + .pt-lg-0 { + padding-top: 0 !important; + } + .pt-lg-1 { + padding-top: 0.25rem !important; + } + .pt-lg-2 { + padding-top: 0.5rem !important; + } + .pt-lg-3 { + padding-top: 1rem !important; + } + .pt-lg-4 { + padding-top: 1.5rem !important; + } + .pt-lg-5 { + padding-top: 2.5rem !important; + } + .pt-lg-10 { + padding-top: 6rem !important; + } + .pt-lg-15 { + padding-top: 9rem !important; + } + .pe-lg-0 { + padding-right: 0 !important; + } + .pe-lg-1 { + padding-right: 0.25rem !important; + } + .pe-lg-2 { + padding-right: 0.5rem !important; + } + .pe-lg-3 { + padding-right: 1rem !important; + } + .pe-lg-4 { + padding-right: 1.5rem !important; + } + .pe-lg-5 { + padding-right: 2.5rem !important; + } + .pe-lg-10 { + padding-right: 6rem !important; + } + .pe-lg-15 { + padding-right: 9rem !important; + } + .pb-lg-0 { + padding-bottom: 0 !important; + } + .pb-lg-1 { + padding-bottom: 0.25rem !important; + } + .pb-lg-2 { + padding-bottom: 0.5rem !important; + } + .pb-lg-3 { + padding-bottom: 1rem !important; + } + .pb-lg-4 { + padding-bottom: 1.5rem !important; + } + .pb-lg-5 { + padding-bottom: 2.5rem !important; + } + .pb-lg-10 { + padding-bottom: 6rem !important; + } + .pb-lg-15 { + padding-bottom: 9rem !important; + } + .ps-lg-0 { + padding-left: 0 !important; + } + .ps-lg-1 { + padding-left: 0.25rem !important; + } + .ps-lg-2 { + padding-left: 0.5rem !important; + } + .ps-lg-3 { + padding-left: 1rem !important; + } + .ps-lg-4 { + padding-left: 1.5rem !important; + } + .ps-lg-5 { + padding-left: 2.5rem !important; + } + .ps-lg-10 { + padding-left: 6rem !important; + } + .ps-lg-15 { + padding-left: 9rem !important; + } + .gap-lg-0 { + gap: 0 !important; + } + .gap-lg-1 { + gap: 0.25rem !important; + } + .gap-lg-2 { + gap: 0.5rem !important; + } + .gap-lg-3 { + gap: 1rem !important; + } + .gap-lg-4 { + gap: 1.5rem !important; + } + .gap-lg-5 { + gap: 2.5rem !important; + } + .gap-lg-10 { + gap: 6rem !important; + } + .gap-lg-15 { + gap: 9rem !important; + } + .text-lg-start { + text-align: left !important; + } + .text-lg-end { + text-align: right !important; + } + .text-lg-center { + text-align: center !important; + } +} +@media (min-width: 1200px) { + .float-xl-start { + float: left !important; + } + .float-xl-end { + float: right !important; + } + .float-xl-none { + float: none !important; + } + .d-xl-inline { + display: inline !important; + } + .d-xl-inline-block { + display: inline-block !important; + } + .d-xl-block { + display: block !important; + } + .d-xl-grid { + display: grid !important; + } + .d-xl-table { + display: table !important; + } + .d-xl-table-row { + display: table-row !important; + } + .d-xl-table-cell { + display: table-cell !important; + } + .d-xl-flex { + display: flex !important; + } + .d-xl-inline-flex { + display: inline-flex !important; + } + .d-xl-none { + display: none !important; + } + .flex-xl-fill { + flex: 1 1 auto !important; + } + .flex-xl-row { + flex-direction: row !important; + } + .flex-xl-column { + flex-direction: column !important; + } + .flex-xl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xl-grow-0 { + flex-grow: 0 !important; + } + .flex-xl-grow-1 { + flex-grow: 1 !important; + } + .flex-xl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xl-wrap { + flex-wrap: wrap !important; + } + .flex-xl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-xl-start { + justify-content: flex-start !important; + } + .justify-content-xl-end { + justify-content: flex-end !important; + } + .justify-content-xl-center { + justify-content: center !important; + } + .justify-content-xl-between { + justify-content: space-between !important; + } + .justify-content-xl-around { + justify-content: space-around !important; + } + .justify-content-xl-evenly { + justify-content: space-evenly !important; + } + .align-items-xl-start { + align-items: flex-start !important; + } + .align-items-xl-end { + align-items: flex-end !important; + } + .align-items-xl-center { + align-items: center !important; + } + .align-items-xl-baseline { + align-items: baseline !important; + } + .align-items-xl-stretch { + align-items: stretch !important; + } + .align-content-xl-start { + align-content: flex-start !important; + } + .align-content-xl-end { + align-content: flex-end !important; + } + .align-content-xl-center { + align-content: center !important; + } + .align-content-xl-between { + align-content: space-between !important; + } + .align-content-xl-around { + align-content: space-around !important; + } + .align-content-xl-stretch { + align-content: stretch !important; + } + .align-self-xl-auto { + align-self: auto !important; + } + .align-self-xl-start { + align-self: flex-start !important; + } + .align-self-xl-end { + align-self: flex-end !important; + } + .align-self-xl-center { + align-self: center !important; + } + .align-self-xl-baseline { + align-self: baseline !important; + } + .align-self-xl-stretch { + align-self: stretch !important; + } + .order-xl-first { + order: -1 !important; + } + .order-xl-0 { + order: 0 !important; + } + .order-xl-1 { + order: 1 !important; + } + .order-xl-2 { + order: 2 !important; + } + .order-xl-3 { + order: 3 !important; + } + .order-xl-4 { + order: 4 !important; + } + .order-xl-5 { + order: 5 !important; + } + .order-xl-last { + order: 6 !important; + } + .m-xl-0 { + margin: 0 !important; + } + .m-xl-1 { + margin: 0.25rem !important; + } + .m-xl-2 { + margin: 0.5rem !important; + } + .m-xl-3 { + margin: 1rem !important; + } + .m-xl-4 { + margin: 1.5rem !important; + } + .m-xl-5 { + margin: 2.5rem !important; + } + .m-xl-10 { + margin: 6rem !important; + } + .m-xl-15 { + margin: 9rem !important; + } + .m-xl-auto { + margin: auto !important; + } + .mx-xl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xl-5 { + margin-right: 2.5rem !important; + margin-left: 2.5rem !important; + } + .mx-xl-10 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-xl-15 { + margin-right: 9rem !important; + margin-left: 9rem !important; + } + .mx-xl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xl-5 { + margin-top: 2.5rem !important; + margin-bottom: 2.5rem !important; + } + .my-xl-10 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-xl-15 { + margin-top: 9rem !important; + margin-bottom: 9rem !important; + } + .my-xl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xl-0 { + margin-top: 0 !important; + } + .mt-xl-1 { + margin-top: 0.25rem !important; + } + .mt-xl-2 { + margin-top: 0.5rem !important; + } + .mt-xl-3 { + margin-top: 1rem !important; + } + .mt-xl-4 { + margin-top: 1.5rem !important; + } + .mt-xl-5 { + margin-top: 2.5rem !important; + } + .mt-xl-10 { + margin-top: 6rem !important; + } + .mt-xl-15 { + margin-top: 9rem !important; + } + .mt-xl-auto { + margin-top: auto !important; + } + .me-xl-0 { + margin-right: 0 !important; + } + .me-xl-1 { + margin-right: 0.25rem !important; + } + .me-xl-2 { + margin-right: 0.5rem !important; + } + .me-xl-3 { + margin-right: 1rem !important; + } + .me-xl-4 { + margin-right: 1.5rem !important; + } + .me-xl-5 { + margin-right: 2.5rem !important; + } + .me-xl-10 { + margin-right: 6rem !important; + } + .me-xl-15 { + margin-right: 9rem !important; + } + .me-xl-auto { + margin-right: auto !important; + } + .mb-xl-0 { + margin-bottom: 0 !important; + } + .mb-xl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xl-3 { + margin-bottom: 1rem !important; + } + .mb-xl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xl-5 { + margin-bottom: 2.5rem !important; + } + .mb-xl-10 { + margin-bottom: 6rem !important; + } + .mb-xl-15 { + margin-bottom: 9rem !important; + } + .mb-xl-auto { + margin-bottom: auto !important; + } + .ms-xl-0 { + margin-left: 0 !important; + } + .ms-xl-1 { + margin-left: 0.25rem !important; + } + .ms-xl-2 { + margin-left: 0.5rem !important; + } + .ms-xl-3 { + margin-left: 1rem !important; + } + .ms-xl-4 { + margin-left: 1.5rem !important; + } + .ms-xl-5 { + margin-left: 2.5rem !important; + } + .ms-xl-10 { + margin-left: 6rem !important; + } + .ms-xl-15 { + margin-left: 9rem !important; + } + .ms-xl-auto { + margin-left: auto !important; + } + .m-xl-n1 { + margin: -0.25rem !important; + } + .m-xl-n2 { + margin: -0.5rem !important; + } + .m-xl-n3 { + margin: -1rem !important; + } + .m-xl-n4 { + margin: -1.5rem !important; + } + .m-xl-n5 { + margin: -2.5rem !important; + } + .m-xl-n10 { + margin: -6rem !important; + } + .m-xl-n15 { + margin: -9rem !important; + } + .mx-xl-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-xl-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-xl-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-xl-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-xl-n5 { + margin-right: -2.5rem !important; + margin-left: -2.5rem !important; + } + .mx-xl-n10 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .mx-xl-n15 { + margin-right: -9rem !important; + margin-left: -9rem !important; + } + .my-xl-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-xl-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-xl-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-xl-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-xl-n5 { + margin-top: -2.5rem !important; + margin-bottom: -2.5rem !important; + } + .my-xl-n10 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .my-xl-n15 { + margin-top: -9rem !important; + margin-bottom: -9rem !important; + } + .mt-xl-n1 { + margin-top: -0.25rem !important; + } + .mt-xl-n2 { + margin-top: -0.5rem !important; + } + .mt-xl-n3 { + margin-top: -1rem !important; + } + .mt-xl-n4 { + margin-top: -1.5rem !important; + } + .mt-xl-n5 { + margin-top: -2.5rem !important; + } + .mt-xl-n10 { + margin-top: -6rem !important; + } + .mt-xl-n15 { + margin-top: -9rem !important; + } + .me-xl-n1 { + margin-right: -0.25rem !important; + } + .me-xl-n2 { + margin-right: -0.5rem !important; + } + .me-xl-n3 { + margin-right: -1rem !important; + } + .me-xl-n4 { + margin-right: -1.5rem !important; + } + .me-xl-n5 { + margin-right: -2.5rem !important; + } + .me-xl-n10 { + margin-right: -6rem !important; + } + .me-xl-n15 { + margin-right: -9rem !important; + } + .mb-xl-n1 { + margin-bottom: -0.25rem !important; + } + .mb-xl-n2 { + margin-bottom: -0.5rem !important; + } + .mb-xl-n3 { + margin-bottom: -1rem !important; + } + .mb-xl-n4 { + margin-bottom: -1.5rem !important; + } + .mb-xl-n5 { + margin-bottom: -2.5rem !important; + } + .mb-xl-n10 { + margin-bottom: -6rem !important; + } + .mb-xl-n15 { + margin-bottom: -9rem !important; + } + .ms-xl-n1 { + margin-left: -0.25rem !important; + } + .ms-xl-n2 { + margin-left: -0.5rem !important; + } + .ms-xl-n3 { + margin-left: -1rem !important; + } + .ms-xl-n4 { + margin-left: -1.5rem !important; + } + .ms-xl-n5 { + margin-left: -2.5rem !important; + } + .ms-xl-n10 { + margin-left: -6rem !important; + } + .ms-xl-n15 { + margin-left: -9rem !important; + } + .p-xl-0 { + padding: 0 !important; + } + .p-xl-1 { + padding: 0.25rem !important; + } + .p-xl-2 { + padding: 0.5rem !important; + } + .p-xl-3 { + padding: 1rem !important; + } + .p-xl-4 { + padding: 1.5rem !important; + } + .p-xl-5 { + padding: 2.5rem !important; + } + .p-xl-10 { + padding: 6rem !important; + } + .p-xl-15 { + padding: 9rem !important; + } + .px-xl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xl-5 { + padding-right: 2.5rem !important; + padding-left: 2.5rem !important; + } + .px-xl-10 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .px-xl-15 { + padding-right: 9rem !important; + padding-left: 9rem !important; + } + .py-xl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xl-5 { + padding-top: 2.5rem !important; + padding-bottom: 2.5rem !important; + } + .py-xl-10 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .py-xl-15 { + padding-top: 9rem !important; + padding-bottom: 9rem !important; + } + .pt-xl-0 { + padding-top: 0 !important; + } + .pt-xl-1 { + padding-top: 0.25rem !important; + } + .pt-xl-2 { + padding-top: 0.5rem !important; + } + .pt-xl-3 { + padding-top: 1rem !important; + } + .pt-xl-4 { + padding-top: 1.5rem !important; + } + .pt-xl-5 { + padding-top: 2.5rem !important; + } + .pt-xl-10 { + padding-top: 6rem !important; + } + .pt-xl-15 { + padding-top: 9rem !important; + } + .pe-xl-0 { + padding-right: 0 !important; + } + .pe-xl-1 { + padding-right: 0.25rem !important; + } + .pe-xl-2 { + padding-right: 0.5rem !important; + } + .pe-xl-3 { + padding-right: 1rem !important; + } + .pe-xl-4 { + padding-right: 1.5rem !important; + } + .pe-xl-5 { + padding-right: 2.5rem !important; + } + .pe-xl-10 { + padding-right: 6rem !important; + } + .pe-xl-15 { + padding-right: 9rem !important; + } + .pb-xl-0 { + padding-bottom: 0 !important; + } + .pb-xl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xl-3 { + padding-bottom: 1rem !important; + } + .pb-xl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xl-5 { + padding-bottom: 2.5rem !important; + } + .pb-xl-10 { + padding-bottom: 6rem !important; + } + .pb-xl-15 { + padding-bottom: 9rem !important; + } + .ps-xl-0 { + padding-left: 0 !important; + } + .ps-xl-1 { + padding-left: 0.25rem !important; + } + .ps-xl-2 { + padding-left: 0.5rem !important; + } + .ps-xl-3 { + padding-left: 1rem !important; + } + .ps-xl-4 { + padding-left: 1.5rem !important; + } + .ps-xl-5 { + padding-left: 2.5rem !important; + } + .ps-xl-10 { + padding-left: 6rem !important; + } + .ps-xl-15 { + padding-left: 9rem !important; + } + .gap-xl-0 { + gap: 0 !important; + } + .gap-xl-1 { + gap: 0.25rem !important; + } + .gap-xl-2 { + gap: 0.5rem !important; + } + .gap-xl-3 { + gap: 1rem !important; + } + .gap-xl-4 { + gap: 1.5rem !important; + } + .gap-xl-5 { + gap: 2.5rem !important; + } + .gap-xl-10 { + gap: 6rem !important; + } + .gap-xl-15 { + gap: 9rem !important; + } + .text-xl-start { + text-align: left !important; + } + .text-xl-end { + text-align: right !important; + } + .text-xl-center { + text-align: center !important; + } +} +@media (min-width: 1500px) { + .float-xxl-start { + float: left !important; + } + .float-xxl-end { + float: right !important; + } + .float-xxl-none { + float: none !important; + } + .d-xxl-inline { + display: inline !important; + } + .d-xxl-inline-block { + display: inline-block !important; + } + .d-xxl-block { + display: block !important; + } + .d-xxl-grid { + display: grid !important; + } + .d-xxl-table { + display: table !important; + } + .d-xxl-table-row { + display: table-row !important; + } + .d-xxl-table-cell { + display: table-cell !important; + } + .d-xxl-flex { + display: flex !important; + } + .d-xxl-inline-flex { + display: inline-flex !important; + } + .d-xxl-none { + display: none !important; + } + .flex-xxl-fill { + flex: 1 1 auto !important; + } + .flex-xxl-row { + flex-direction: row !important; + } + .flex-xxl-column { + flex-direction: column !important; + } + .flex-xxl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xxl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xxl-grow-0 { + flex-grow: 0 !important; + } + .flex-xxl-grow-1 { + flex-grow: 1 !important; + } + .flex-xxl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xxl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xxl-wrap { + flex-wrap: wrap !important; + } + .flex-xxl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xxl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .justify-content-xxl-start { + justify-content: flex-start !important; + } + .justify-content-xxl-end { + justify-content: flex-end !important; + } + .justify-content-xxl-center { + justify-content: center !important; + } + .justify-content-xxl-between { + justify-content: space-between !important; + } + .justify-content-xxl-around { + justify-content: space-around !important; + } + .justify-content-xxl-evenly { + justify-content: space-evenly !important; + } + .align-items-xxl-start { + align-items: flex-start !important; + } + .align-items-xxl-end { + align-items: flex-end !important; + } + .align-items-xxl-center { + align-items: center !important; + } + .align-items-xxl-baseline { + align-items: baseline !important; + } + .align-items-xxl-stretch { + align-items: stretch !important; + } + .align-content-xxl-start { + align-content: flex-start !important; + } + .align-content-xxl-end { + align-content: flex-end !important; + } + .align-content-xxl-center { + align-content: center !important; + } + .align-content-xxl-between { + align-content: space-between !important; + } + .align-content-xxl-around { + align-content: space-around !important; + } + .align-content-xxl-stretch { + align-content: stretch !important; + } + .align-self-xxl-auto { + align-self: auto !important; + } + .align-self-xxl-start { + align-self: flex-start !important; + } + .align-self-xxl-end { + align-self: flex-end !important; + } + .align-self-xxl-center { + align-self: center !important; + } + .align-self-xxl-baseline { + align-self: baseline !important; + } + .align-self-xxl-stretch { + align-self: stretch !important; + } + .order-xxl-first { + order: -1 !important; + } + .order-xxl-0 { + order: 0 !important; + } + .order-xxl-1 { + order: 1 !important; + } + .order-xxl-2 { + order: 2 !important; + } + .order-xxl-3 { + order: 3 !important; + } + .order-xxl-4 { + order: 4 !important; + } + .order-xxl-5 { + order: 5 !important; + } + .order-xxl-last { + order: 6 !important; + } + .m-xxl-0 { + margin: 0 !important; + } + .m-xxl-1 { + margin: 0.25rem !important; + } + .m-xxl-2 { + margin: 0.5rem !important; + } + .m-xxl-3 { + margin: 1rem !important; + } + .m-xxl-4 { + margin: 1.5rem !important; + } + .m-xxl-5 { + margin: 2.5rem !important; + } + .m-xxl-10 { + margin: 6rem !important; + } + .m-xxl-15 { + margin: 9rem !important; + } + .m-xxl-auto { + margin: auto !important; + } + .mx-xxl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xxl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xxl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xxl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xxl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xxl-5 { + margin-right: 2.5rem !important; + margin-left: 2.5rem !important; + } + .mx-xxl-10 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-xxl-15 { + margin-right: 9rem !important; + margin-left: 9rem !important; + } + .mx-xxl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xxl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xxl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xxl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xxl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xxl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xxl-5 { + margin-top: 2.5rem !important; + margin-bottom: 2.5rem !important; + } + .my-xxl-10 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-xxl-15 { + margin-top: 9rem !important; + margin-bottom: 9rem !important; + } + .my-xxl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xxl-0 { + margin-top: 0 !important; + } + .mt-xxl-1 { + margin-top: 0.25rem !important; + } + .mt-xxl-2 { + margin-top: 0.5rem !important; + } + .mt-xxl-3 { + margin-top: 1rem !important; + } + .mt-xxl-4 { + margin-top: 1.5rem !important; + } + .mt-xxl-5 { + margin-top: 2.5rem !important; + } + .mt-xxl-10 { + margin-top: 6rem !important; + } + .mt-xxl-15 { + margin-top: 9rem !important; + } + .mt-xxl-auto { + margin-top: auto !important; + } + .me-xxl-0 { + margin-right: 0 !important; + } + .me-xxl-1 { + margin-right: 0.25rem !important; + } + .me-xxl-2 { + margin-right: 0.5rem !important; + } + .me-xxl-3 { + margin-right: 1rem !important; + } + .me-xxl-4 { + margin-right: 1.5rem !important; + } + .me-xxl-5 { + margin-right: 2.5rem !important; + } + .me-xxl-10 { + margin-right: 6rem !important; + } + .me-xxl-15 { + margin-right: 9rem !important; + } + .me-xxl-auto { + margin-right: auto !important; + } + .mb-xxl-0 { + margin-bottom: 0 !important; + } + .mb-xxl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xxl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xxl-3 { + margin-bottom: 1rem !important; + } + .mb-xxl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xxl-5 { + margin-bottom: 2.5rem !important; + } + .mb-xxl-10 { + margin-bottom: 6rem !important; + } + .mb-xxl-15 { + margin-bottom: 9rem !important; + } + .mb-xxl-auto { + margin-bottom: auto !important; + } + .ms-xxl-0 { + margin-left: 0 !important; + } + .ms-xxl-1 { + margin-left: 0.25rem !important; + } + .ms-xxl-2 { + margin-left: 0.5rem !important; + } + .ms-xxl-3 { + margin-left: 1rem !important; + } + .ms-xxl-4 { + margin-left: 1.5rem !important; + } + .ms-xxl-5 { + margin-left: 2.5rem !important; + } + .ms-xxl-10 { + margin-left: 6rem !important; + } + .ms-xxl-15 { + margin-left: 9rem !important; + } + .ms-xxl-auto { + margin-left: auto !important; + } + .m-xxl-n1 { + margin: -0.25rem !important; + } + .m-xxl-n2 { + margin: -0.5rem !important; + } + .m-xxl-n3 { + margin: -1rem !important; + } + .m-xxl-n4 { + margin: -1.5rem !important; + } + .m-xxl-n5 { + margin: -2.5rem !important; + } + .m-xxl-n10 { + margin: -6rem !important; + } + .m-xxl-n15 { + margin: -9rem !important; + } + .mx-xxl-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-xxl-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-xxl-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-xxl-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-xxl-n5 { + margin-right: -2.5rem !important; + margin-left: -2.5rem !important; + } + .mx-xxl-n10 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .mx-xxl-n15 { + margin-right: -9rem !important; + margin-left: -9rem !important; + } + .my-xxl-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-xxl-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-xxl-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-xxl-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-xxl-n5 { + margin-top: -2.5rem !important; + margin-bottom: -2.5rem !important; + } + .my-xxl-n10 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .my-xxl-n15 { + margin-top: -9rem !important; + margin-bottom: -9rem !important; + } + .mt-xxl-n1 { + margin-top: -0.25rem !important; + } + .mt-xxl-n2 { + margin-top: -0.5rem !important; + } + .mt-xxl-n3 { + margin-top: -1rem !important; + } + .mt-xxl-n4 { + margin-top: -1.5rem !important; + } + .mt-xxl-n5 { + margin-top: -2.5rem !important; + } + .mt-xxl-n10 { + margin-top: -6rem !important; + } + .mt-xxl-n15 { + margin-top: -9rem !important; + } + .me-xxl-n1 { + margin-right: -0.25rem !important; + } + .me-xxl-n2 { + margin-right: -0.5rem !important; + } + .me-xxl-n3 { + margin-right: -1rem !important; + } + .me-xxl-n4 { + margin-right: -1.5rem !important; + } + .me-xxl-n5 { + margin-right: -2.5rem !important; + } + .me-xxl-n10 { + margin-right: -6rem !important; + } + .me-xxl-n15 { + margin-right: -9rem !important; + } + .mb-xxl-n1 { + margin-bottom: -0.25rem !important; + } + .mb-xxl-n2 { + margin-bottom: -0.5rem !important; + } + .mb-xxl-n3 { + margin-bottom: -1rem !important; + } + .mb-xxl-n4 { + margin-bottom: -1.5rem !important; + } + .mb-xxl-n5 { + margin-bottom: -2.5rem !important; + } + .mb-xxl-n10 { + margin-bottom: -6rem !important; + } + .mb-xxl-n15 { + margin-bottom: -9rem !important; + } + .ms-xxl-n1 { + margin-left: -0.25rem !important; + } + .ms-xxl-n2 { + margin-left: -0.5rem !important; + } + .ms-xxl-n3 { + margin-left: -1rem !important; + } + .ms-xxl-n4 { + margin-left: -1.5rem !important; + } + .ms-xxl-n5 { + margin-left: -2.5rem !important; + } + .ms-xxl-n10 { + margin-left: -6rem !important; + } + .ms-xxl-n15 { + margin-left: -9rem !important; + } + .p-xxl-0 { + padding: 0 !important; + } + .p-xxl-1 { + padding: 0.25rem !important; + } + .p-xxl-2 { + padding: 0.5rem !important; + } + .p-xxl-3 { + padding: 1rem !important; + } + .p-xxl-4 { + padding: 1.5rem !important; + } + .p-xxl-5 { + padding: 2.5rem !important; + } + .p-xxl-10 { + padding: 6rem !important; + } + .p-xxl-15 { + padding: 9rem !important; + } + .px-xxl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xxl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xxl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xxl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xxl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xxl-5 { + padding-right: 2.5rem !important; + padding-left: 2.5rem !important; + } + .px-xxl-10 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .px-xxl-15 { + padding-right: 9rem !important; + padding-left: 9rem !important; + } + .py-xxl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xxl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xxl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xxl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xxl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xxl-5 { + padding-top: 2.5rem !important; + padding-bottom: 2.5rem !important; + } + .py-xxl-10 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .py-xxl-15 { + padding-top: 9rem !important; + padding-bottom: 9rem !important; + } + .pt-xxl-0 { + padding-top: 0 !important; + } + .pt-xxl-1 { + padding-top: 0.25rem !important; + } + .pt-xxl-2 { + padding-top: 0.5rem !important; + } + .pt-xxl-3 { + padding-top: 1rem !important; + } + .pt-xxl-4 { + padding-top: 1.5rem !important; + } + .pt-xxl-5 { + padding-top: 2.5rem !important; + } + .pt-xxl-10 { + padding-top: 6rem !important; + } + .pt-xxl-15 { + padding-top: 9rem !important; + } + .pe-xxl-0 { + padding-right: 0 !important; + } + .pe-xxl-1 { + padding-right: 0.25rem !important; + } + .pe-xxl-2 { + padding-right: 0.5rem !important; + } + .pe-xxl-3 { + padding-right: 1rem !important; + } + .pe-xxl-4 { + padding-right: 1.5rem !important; + } + .pe-xxl-5 { + padding-right: 2.5rem !important; + } + .pe-xxl-10 { + padding-right: 6rem !important; + } + .pe-xxl-15 { + padding-right: 9rem !important; + } + .pb-xxl-0 { + padding-bottom: 0 !important; + } + .pb-xxl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xxl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xxl-3 { + padding-bottom: 1rem !important; + } + .pb-xxl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xxl-5 { + padding-bottom: 2.5rem !important; + } + .pb-xxl-10 { + padding-bottom: 6rem !important; + } + .pb-xxl-15 { + padding-bottom: 9rem !important; + } + .ps-xxl-0 { + padding-left: 0 !important; + } + .ps-xxl-1 { + padding-left: 0.25rem !important; + } + .ps-xxl-2 { + padding-left: 0.5rem !important; + } + .ps-xxl-3 { + padding-left: 1rem !important; + } + .ps-xxl-4 { + padding-left: 1.5rem !important; + } + .ps-xxl-5 { + padding-left: 2.5rem !important; + } + .ps-xxl-10 { + padding-left: 6rem !important; + } + .ps-xxl-15 { + padding-left: 9rem !important; + } + .gap-xxl-0 { + gap: 0 !important; + } + .gap-xxl-1 { + gap: 0.25rem !important; + } + .gap-xxl-2 { + gap: 0.5rem !important; + } + .gap-xxl-3 { + gap: 1rem !important; + } + .gap-xxl-4 { + gap: 1.5rem !important; + } + .gap-xxl-5 { + gap: 2.5rem !important; + } + .gap-xxl-10 { + gap: 6rem !important; + } + .gap-xxl-15 { + gap: 9rem !important; + } + .text-xxl-start { + text-align: left !important; + } + .text-xxl-end { + text-align: right !important; + } + .text-xxl-center { + text-align: center !important; + } +} +@media (min-width: 1200px) { + .fs-1 { + font-size: 1.5rem !important; + } + .fs-2 { + font-size: 1.4rem !important; + } + .fs-3 { + font-size: 1.3rem !important; + } +} +@media print { + .d-print-inline { + display: inline !important; + } + .d-print-inline-block { + display: inline-block !important; + } + .d-print-block { + display: block !important; + } + .d-print-grid { + display: grid !important; + } + .d-print-table { + display: table !important; + } + .d-print-table-row { + display: table-row !important; + } + .d-print-table-cell { + display: table-cell !important; + } + .d-print-flex { + display: flex !important; + } + .d-print-inline-flex { + display: inline-flex !important; + } + .d-print-none { + display: none !important; + } +} +html, +body { + height: 100%; +} + +body { + overflow-x: hidden; +} + +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-Thin.otf"); + font-weight: 100; + font-style: normal; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-ThinItalic.otf"); + font-weight: 100; + font-style: italic; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-ExtraLight.otf"); + font-weight: 200; + font-style: normal; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-ExtraLightItalic.otf"); + font-weight: 200; + font-style: italic; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-Light.otf"); + font-weight: 300; + font-style: normal; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-LightItalic.otf"); + font-weight: 300; + font-style: italic; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-Regular.otf"); + font-weight: 400; + font-style: normal; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-RegularItalic.otf"); + font-weight: 400; + font-style: italic; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-Medium.otf"); + font-weight: 500; + font-style: normal; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-MediumItalic.otf"); + font-weight: 500; + font-style: italic; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-SemiBold.otf"); + font-weight: 600; + font-style: normal; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-SemiBoldItalic.otf"); + font-weight: 600; + font-style: italic; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-Bold.otf"); + font-weight: 700; + font-style: normal; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-BoldItalic.otf"); + font-weight: 700; + font-style: italic; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-ExtraBold.otf"); + font-weight: 800; + font-style: normal; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-ExtraBoldItalic.otf"); + font-weight: 800; + font-style: italic; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-Black.otf"); + font-weight: 800; + font-style: normal; +} +@font-face { + font-family: "Metropolis"; + src: url("../assets/fonts/metropolis/Metropolis-BlackItalic.otf"); + font-weight: 800; + font-style: italic; +} +#layoutAuthentication { + display: flex; + flex-direction: column; + min-height: 100vh; +} +#layoutAuthentication #layoutAuthentication_content { + min-width: 0; + flex-grow: 1; +} +#layoutAuthentication #layoutAuthentication_footer { + min-width: 0; +} + +#layoutError { + display: flex; + flex-direction: column; + min-height: 100vh; +} +#layoutError #layoutError_content { + min-width: 0; + flex-grow: 1; +} +#layoutError #layoutError_footer { + min-width: 0; +} + +.img-error { + max-width: 20rem; +} + +@keyframes fadeInUp { + 0% { + opacity: 0; + margin-top: 0.75rem; + } + 100% { + opacity: 1; + margin-top: 0; + } +} +.animated--fade-in-up { + animation-name: fadeInUp; + animation-duration: 300ms; + animation-timing-function: margin cubic-bezier(0.18, 1.25, 0.4, 1), opacity cubic-bezier(0, 1, 0.4, 1); +} +.animated--fade-in-up.dropdown-menu { + margin-top: 0; + top: 0.125rem !important; +} + +@keyframes fadeIn { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +.animated--fade-in { + animation-name: fadeIn; + animation-duration: 300ms; + animation-timing-function: opacity cubic-bezier(0, 1, 0.4, 1); +} + +.bg-gradient-primary-to-secondary { + background-color: #0061f2 !important; + background-image: linear-gradient(135deg, #0061f2 0%, rgba(105, 0, 199, 0.8) 100%) !important; +} + +.bg-transparent-light { + color: rgba(255, 255, 255, 0.5) !important; + background-color: rgba(0, 0, 0, 0.1) !important; +} + +.bg-transparent-dark { + color: rgba(33, 40, 50, 0.5) !important; + background-color: rgba(33, 40, 50, 0.8) !important; +} + +.bg-gray-100 { + background-color: #f2f6fc !important; +} + +.bg-gray-200 { + background-color: #e0e5ec !important; +} + +.bg-gray-300 { + background-color: #d4dae3 !important; +} + +.bg-gray-400 { + background-color: #c5ccd6 !important; +} + +.bg-gray-500 { + background-color: #a7aeb8 !important; +} + +.bg-gray-600 { + background-color: #69707a !important; +} + +.bg-gray-700 { + background-color: #4a515b !important; +} + +.bg-gray-800 { + background-color: #363d47 !important; +} + +.bg-gray-900 { + background-color: #212832 !important; +} + +.bg-white-25 { + background-color: rgba(255, 255, 255, 0.25) !important; +} + +.bg-img-cover { + background-position: center; + background-size: cover; + background-repeat: no-repeat; +} + +.bg-img-repeat { + background-position: top left; + background-repeat: repeat; +} + +.overlay { + position: relative; +} +.overlay:before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #000; + opacity: 0.5; +} + +.overlay-primary:before { + background-color: #0061f2 !important; +} + +.overlay-secondary:before { + background-color: #6900c7 !important; +} + +.overlay-success:before { + background-color: #00ac69 !important; +} + +.overlay-info:before { + background-color: #00cfd5 !important; +} + +.overlay-warning:before { + background-color: #f4a100 !important; +} + +.overlay-danger:before { + background-color: #e81500 !important; +} + +.overlay-light:before { + background-color: #f2f6fc !important; +} + +.overlay-dark:before { + background-color: #212832 !important; +} + +.overlay-black:before { + background-color: #000 !important; +} + +.overlay-white:before { + background-color: #fff !important; +} + +.overlay-red:before { + background-color: #e81500 !important; +} + +.overlay-orange:before { + background-color: #f76400 !important; +} + +.overlay-yellow:before { + background-color: #f4a100 !important; +} + +.overlay-green:before { + background-color: #00ac69 !important; +} + +.overlay-teal:before { + background-color: #00ba94 !important; +} + +.overlay-cyan:before { + background-color: #00cfd5 !important; +} + +.overlay-blue:before { + background-color: #0061f2 !important; +} + +.overlay-indigo:before { + background-color: #5800e8 !important; +} + +.overlay-purple:before { + background-color: #6900c7 !important; +} + +.overlay-pink:before { + background-color: #e30059 !important; +} + +.overlay-red-soft:before { + background-color: #f1e0e3 !important; +} + +.overlay-orange-soft:before { + background-color: #f3e7e3 !important; +} + +.overlay-yellow-soft:before { + background-color: #f2eee3 !important; +} + +.overlay-green-soft:before { + background-color: #daefed !important; +} + +.overlay-teal-soft:before { + background-color: #daf0f2 !important; +} + +.overlay-cyan-soft:before { + background-color: #daf2f8 !important; +} + +.overlay-blue-soft:before { + background-color: #dae7fb !important; +} + +.overlay-indigo-soft:before { + background-color: #e3ddfa !important; +} + +.overlay-purple-soft:before { + background-color: #e4ddf7 !important; +} + +.overlay-pink-soft:before { + background-color: #f1ddec !important; +} + +.overlay-primary-soft:before { + background-color: #dae7fb !important; +} + +.overlay-secondary-soft:before { + background-color: #e4ddf7 !important; +} + +.overlay-success-soft:before { + background-color: #daefed !important; +} + +.overlay-info-soft:before { + background-color: #daf2f8 !important; +} + +.overlay-warning-soft:before { + background-color: #f2eee3 !important; +} + +.overlay-danger-soft:before { + background-color: #f1e0e3 !important; +} + +.overlay-10:before { + opacity: 0.1; +} + +.overlay-20:before { + opacity: 0.2; +} + +.overlay-30:before { + opacity: 0.3; +} + +.overlay-40:before { + opacity: 0.4; +} + +.overlay-50:before { + opacity: 0.5; +} + +.overlay-60:before { + opacity: 0.6; +} + +.overlay-70:before { + opacity: 0.7; +} + +.overlay-80:before { + opacity: 0.8; +} + +.overlay-90:before { + opacity: 0.9; +} + +.border-lg { + border-width: 0.25rem !important; +} + +.border-top-lg { + border-top-width: 0.25rem !important; +} + +.border-end-lg { + border-right-width: 0.25rem !important; +} + +.border-bottom-lg { + border-bottom-width: 0.25rem !important; +} + +.border-start-lg { + border-left-width: 0.25rem !important; +} + +.border-primary { + border-color: #0061f2 !important; +} + +.border-secondary { + border-color: #6900c7 !important; +} + +.border-success { + border-color: #00ac69 !important; +} + +.border-info { + border-color: #00cfd5 !important; +} + +.border-warning { + border-color: #f4a100 !important; +} + +.border-danger { + border-color: #e81500 !important; +} + +.border-light { + border-color: #f2f6fc !important; +} + +.border-dark { + border-color: #212832 !important; +} + +.border-black { + border-color: #000 !important; +} + +.border-white { + border-color: #fff !important; +} + +.border-red { + border-color: #e81500 !important; +} + +.border-orange { + border-color: #f76400 !important; +} + +.border-yellow { + border-color: #f4a100 !important; +} + +.border-green { + border-color: #00ac69 !important; +} + +.border-teal { + border-color: #00ba94 !important; +} + +.border-cyan { + border-color: #00cfd5 !important; +} + +.border-blue { + border-color: #0061f2 !important; +} + +.border-indigo { + border-color: #5800e8 !important; +} + +.border-purple { + border-color: #6900c7 !important; +} + +.border-pink { + border-color: #e30059 !important; +} + +.border-red-soft { + border-color: #f1e0e3 !important; +} + +.border-orange-soft { + border-color: #f3e7e3 !important; +} + +.border-yellow-soft { + border-color: #f2eee3 !important; +} + +.border-green-soft { + border-color: #daefed !important; +} + +.border-teal-soft { + border-color: #daf0f2 !important; +} + +.border-cyan-soft { + border-color: #daf2f8 !important; +} + +.border-blue-soft { + border-color: #dae7fb !important; +} + +.border-indigo-soft { + border-color: #e3ddfa !important; +} + +.border-purple-soft { + border-color: #e4ddf7 !important; +} + +.border-pink-soft { + border-color: #f1ddec !important; +} + +.border-primary-soft { + border-color: #dae7fb !important; +} + +.border-secondary-soft { + border-color: #e4ddf7 !important; +} + +.border-success-soft { + border-color: #daefed !important; +} + +.border-info-soft { + border-color: #daf2f8 !important; +} + +.border-warning-soft { + border-color: #f2eee3 !important; +} + +.border-danger-soft { + border-color: #f1e0e3 !important; +} + +.border-start-primary { + border-left-color: #0061f2 !important; +} + +.border-start-secondary { + border-left-color: #6900c7 !important; +} + +.border-start-success { + border-left-color: #00ac69 !important; +} + +.border-start-info { + border-left-color: #00cfd5 !important; +} + +.border-start-warning { + border-left-color: #f4a100 !important; +} + +.border-start-danger { + border-left-color: #e81500 !important; +} + +.border-start-light { + border-left-color: #f2f6fc !important; +} + +.border-start-dark { + border-left-color: #212832 !important; +} + +.border-start-black { + border-left-color: #000 !important; +} + +.border-start-white { + border-left-color: #fff !important; +} + +.border-start-red { + border-left-color: #e81500 !important; +} + +.border-start-orange { + border-left-color: #f76400 !important; +} + +.border-start-yellow { + border-left-color: #f4a100 !important; +} + +.border-start-green { + border-left-color: #00ac69 !important; +} + +.border-start-teal { + border-left-color: #00ba94 !important; +} + +.border-start-cyan { + border-left-color: #00cfd5 !important; +} + +.border-start-blue { + border-left-color: #0061f2 !important; +} + +.border-start-indigo { + border-left-color: #5800e8 !important; +} + +.border-start-purple { + border-left-color: #6900c7 !important; +} + +.border-start-pink { + border-left-color: #e30059 !important; +} + +.border-start-red-soft { + border-left-color: #f1e0e3 !important; +} + +.border-start-orange-soft { + border-left-color: #f3e7e3 !important; +} + +.border-start-yellow-soft { + border-left-color: #f2eee3 !important; +} + +.border-start-green-soft { + border-left-color: #daefed !important; +} + +.border-start-teal-soft { + border-left-color: #daf0f2 !important; +} + +.border-start-cyan-soft { + border-left-color: #daf2f8 !important; +} + +.border-start-blue-soft { + border-left-color: #dae7fb !important; +} + +.border-start-indigo-soft { + border-left-color: #e3ddfa !important; +} + +.border-start-purple-soft { + border-left-color: #e4ddf7 !important; +} + +.border-start-pink-soft { + border-left-color: #f1ddec !important; +} + +.border-start-primary-soft { + border-left-color: #dae7fb !important; +} + +.border-start-secondary-soft { + border-left-color: #e4ddf7 !important; +} + +.border-start-success-soft { + border-left-color: #daefed !important; +} + +.border-start-info-soft { + border-left-color: #daf2f8 !important; +} + +.border-start-warning-soft { + border-left-color: #f2eee3 !important; +} + +.border-start-danger-soft { + border-left-color: #f1e0e3 !important; +} + +.border-end-primary { + border-right-color: #0061f2 !important; +} + +.border-end-secondary { + border-right-color: #6900c7 !important; +} + +.border-end-success { + border-right-color: #00ac69 !important; +} + +.border-end-info { + border-right-color: #00cfd5 !important; +} + +.border-end-warning { + border-right-color: #f4a100 !important; +} + +.border-end-danger { + border-right-color: #e81500 !important; +} + +.border-end-light { + border-right-color: #f2f6fc !important; +} + +.border-end-dark { + border-right-color: #212832 !important; +} + +.border-end-black { + border-right-color: #000 !important; +} + +.border-end-white { + border-right-color: #fff !important; +} + +.border-end-red { + border-right-color: #e81500 !important; +} + +.border-end-orange { + border-right-color: #f76400 !important; +} + +.border-end-yellow { + border-right-color: #f4a100 !important; +} + +.border-end-green { + border-right-color: #00ac69 !important; +} + +.border-end-teal { + border-right-color: #00ba94 !important; +} + +.border-end-cyan { + border-right-color: #00cfd5 !important; +} + +.border-end-blue { + border-right-color: #0061f2 !important; +} + +.border-end-indigo { + border-right-color: #5800e8 !important; +} + +.border-end-purple { + border-right-color: #6900c7 !important; +} + +.border-end-pink { + border-right-color: #e30059 !important; +} + +.border-end-red-soft { + border-right-color: #f1e0e3 !important; +} + +.border-end-orange-soft { + border-right-color: #f3e7e3 !important; +} + +.border-end-yellow-soft { + border-right-color: #f2eee3 !important; +} + +.border-end-green-soft { + border-right-color: #daefed !important; +} + +.border-end-teal-soft { + border-right-color: #daf0f2 !important; +} + +.border-end-cyan-soft { + border-right-color: #daf2f8 !important; +} + +.border-end-blue-soft { + border-right-color: #dae7fb !important; +} + +.border-end-indigo-soft { + border-right-color: #e3ddfa !important; +} + +.border-end-purple-soft { + border-right-color: #e4ddf7 !important; +} + +.border-end-pink-soft { + border-right-color: #f1ddec !important; +} + +.border-end-primary-soft { + border-right-color: #dae7fb !important; +} + +.border-end-secondary-soft { + border-right-color: #e4ddf7 !important; +} + +.border-end-success-soft { + border-right-color: #daefed !important; +} + +.border-end-info-soft { + border-right-color: #daf2f8 !important; +} + +.border-end-warning-soft { + border-right-color: #f2eee3 !important; +} + +.border-end-danger-soft { + border-right-color: #f1e0e3 !important; +} + +.border-top-primary { + border-top-color: #0061f2 !important; +} + +.border-top-secondary { + border-top-color: #6900c7 !important; +} + +.border-top-success { + border-top-color: #00ac69 !important; +} + +.border-top-info { + border-top-color: #00cfd5 !important; +} + +.border-top-warning { + border-top-color: #f4a100 !important; +} + +.border-top-danger { + border-top-color: #e81500 !important; +} + +.border-top-light { + border-top-color: #f2f6fc !important; +} + +.border-top-dark { + border-top-color: #212832 !important; +} + +.border-top-black { + border-top-color: #000 !important; +} + +.border-top-white { + border-top-color: #fff !important; +} + +.border-top-red { + border-top-color: #e81500 !important; +} + +.border-top-orange { + border-top-color: #f76400 !important; +} + +.border-top-yellow { + border-top-color: #f4a100 !important; +} + +.border-top-green { + border-top-color: #00ac69 !important; +} + +.border-top-teal { + border-top-color: #00ba94 !important; +} + +.border-top-cyan { + border-top-color: #00cfd5 !important; +} + +.border-top-blue { + border-top-color: #0061f2 !important; +} + +.border-top-indigo { + border-top-color: #5800e8 !important; +} + +.border-top-purple { + border-top-color: #6900c7 !important; +} + +.border-top-pink { + border-top-color: #e30059 !important; +} + +.border-top-red-soft { + border-top-color: #f1e0e3 !important; +} + +.border-top-orange-soft { + border-top-color: #f3e7e3 !important; +} + +.border-top-yellow-soft { + border-top-color: #f2eee3 !important; +} + +.border-top-green-soft { + border-top-color: #daefed !important; +} + +.border-top-teal-soft { + border-top-color: #daf0f2 !important; +} + +.border-top-cyan-soft { + border-top-color: #daf2f8 !important; +} + +.border-top-blue-soft { + border-top-color: #dae7fb !important; +} + +.border-top-indigo-soft { + border-top-color: #e3ddfa !important; +} + +.border-top-purple-soft { + border-top-color: #e4ddf7 !important; +} + +.border-top-pink-soft { + border-top-color: #f1ddec !important; +} + +.border-top-primary-soft { + border-top-color: #dae7fb !important; +} + +.border-top-secondary-soft { + border-top-color: #e4ddf7 !important; +} + +.border-top-success-soft { + border-top-color: #daefed !important; +} + +.border-top-info-soft { + border-top-color: #daf2f8 !important; +} + +.border-top-warning-soft { + border-top-color: #f2eee3 !important; +} + +.border-top-danger-soft { + border-top-color: #f1e0e3 !important; +} + +.border-bottom-primary { + border-bottom-color: #0061f2 !important; +} + +.border-bottom-secondary { + border-bottom-color: #6900c7 !important; +} + +.border-bottom-success { + border-bottom-color: #00ac69 !important; +} + +.border-bottom-info { + border-bottom-color: #00cfd5 !important; +} + +.border-bottom-warning { + border-bottom-color: #f4a100 !important; +} + +.border-bottom-danger { + border-bottom-color: #e81500 !important; +} + +.border-bottom-light { + border-bottom-color: #f2f6fc !important; +} + +.border-bottom-dark { + border-bottom-color: #212832 !important; +} + +.border-bottom-black { + border-bottom-color: #000 !important; +} + +.border-bottom-white { + border-bottom-color: #fff !important; +} + +.border-bottom-red { + border-bottom-color: #e81500 !important; +} + +.border-bottom-orange { + border-bottom-color: #f76400 !important; +} + +.border-bottom-yellow { + border-bottom-color: #f4a100 !important; +} + +.border-bottom-green { + border-bottom-color: #00ac69 !important; +} + +.border-bottom-teal { + border-bottom-color: #00ba94 !important; +} + +.border-bottom-cyan { + border-bottom-color: #00cfd5 !important; +} + +.border-bottom-blue { + border-bottom-color: #0061f2 !important; +} + +.border-bottom-indigo { + border-bottom-color: #5800e8 !important; +} + +.border-bottom-purple { + border-bottom-color: #6900c7 !important; +} + +.border-bottom-pink { + border-bottom-color: #e30059 !important; +} + +.border-bottom-red-soft { + border-bottom-color: #f1e0e3 !important; +} + +.border-bottom-orange-soft { + border-bottom-color: #f3e7e3 !important; +} + +.border-bottom-yellow-soft { + border-bottom-color: #f2eee3 !important; +} + +.border-bottom-green-soft { + border-bottom-color: #daefed !important; +} + +.border-bottom-teal-soft { + border-bottom-color: #daf0f2 !important; +} + +.border-bottom-cyan-soft { + border-bottom-color: #daf2f8 !important; +} + +.border-bottom-blue-soft { + border-bottom-color: #dae7fb !important; +} + +.border-bottom-indigo-soft { + border-bottom-color: #e3ddfa !important; +} + +.border-bottom-purple-soft { + border-bottom-color: #e4ddf7 !important; +} + +.border-bottom-pink-soft { + border-bottom-color: #f1ddec !important; +} + +.border-bottom-primary-soft { + border-bottom-color: #dae7fb !important; +} + +.border-bottom-secondary-soft { + border-bottom-color: #e4ddf7 !important; +} + +.border-bottom-success-soft { + border-bottom-color: #daefed !important; +} + +.border-bottom-info-soft { + border-bottom-color: #daf2f8 !important; +} + +.border-bottom-warning-soft { + border-bottom-color: #f2eee3 !important; +} + +.border-bottom-danger-soft { + border-bottom-color: #f1e0e3 !important; +} + +.rounded-xl { + border-radius: 1rem !important; +} + +.border-gray-100 { + border-color: #f2f6fc !important; +} + +.border-gray-200 { + border-color: #e0e5ec !important; +} + +.border-gray-300 { + border-color: #d4dae3 !important; +} + +.border-gray-400 { + border-color: #c5ccd6 !important; +} + +.border-gray-500 { + border-color: #a7aeb8 !important; +} + +.border-gray-600 { + border-color: #69707a !important; +} + +.border-gray-700 { + border-color: #4a515b !important; +} + +.border-gray-800 { + border-color: #363d47 !important; +} + +.border-gray-900 { + border-color: #212832 !important; +} + +.no-caret .dropdown-toggle::after { + display: none; +} + +.pointer { + cursor: pointer !important; +} + +.no-highlight { + -webkit-user-select: none !important; + -moz-user-select: none !important; + user-select: none !important; +} + +.lift { + box-shadow: 0 0.15rem 1.75rem 0 rgba(33, 40, 50, 0.15); + transition: transform 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.lift:hover { + transform: translateY(-0.3333333333rem); + box-shadow: 0 0.5rem 2rem 0 rgba(33, 40, 50, 0.25); +} +.lift:active { + transform: none; + box-shadow: 0 0.15rem 1.75rem 0 rgba(33, 40, 50, 0.15); +} + +.lift-sm { + box-shadow: 0 0.125rem 0.25rem 0 rgba(33, 40, 50, 0.2); +} +.lift-sm:hover { + transform: translateY(-0.1666666667rem); + box-shadow: 0 0.25rem 1rem 0 rgba(33, 40, 50, 0.25); +} +.lift-sm:active { + transform: none; + box-shadow: 0 0.125rem 0.25rem 0 rgba(33, 40, 50, 0.2); +} + +.card.lift { + text-decoration: none; + color: inherit; +} + +.o-visible { + overflow: visible !important; +} + +.o-hidden { + overflow: hidden !important; +} + +.shadow-right-sm { + box-shadow: 0.125rem 0 0.25rem 0 rgba(33, 40, 50, 0.15) !important; +} + +.shadow-right { + box-shadow: 0.15rem 0 1.75rem 0 rgba(33, 40, 50, 0.15) !important; +} + +.shadow-right-lg { + box-shadow: 1rem 0 3rem 0 rgba(33, 40, 50, 0.15) !important; +} + +.shadow-left-sm { + box-shadow: -0.125rem 0 0.25rem 0 rgba(33, 40, 50, 0.15) !important; +} + +.shadow-left { + box-shadow: -0.15rem 0 1.75rem 0 rgba(33, 40, 50, 0.15) !important; +} + +.shadow-left-lg { + box-shadow: -1rem 0 3rem 0 rgba(33, 40, 50, 0.15) !important; +} + +.content-skewed { + perspective: 1500px !important; + transform-style: preserve-3d !important; +} + +.content-skewed-right { + perspective-origin: right center !important; +} +.content-skewed-right .content-skewed-item { + transform: rotateY(30deg) rotateX(15deg) !important; + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; +} + +.content-skewed-left { + perspective-origin: left center !important; +} +.content-skewed-left .content-skewed-item { + transform: rotateY(-30deg) rotateX(15deg) !important; + -webkit-backface-visibility: hidden !important; + backface-visibility: hidden !important; +} + +.text-gray-100 { + color: #f2f6fc !important; +} + +.text-gray-200 { + color: #e0e5ec !important; +} + +.text-gray-300 { + color: #d4dae3 !important; +} + +.text-gray-400 { + color: #c5ccd6 !important; +} + +.text-gray-500 { + color: #a7aeb8 !important; +} + +.text-gray-600 { + color: #69707a !important; +} + +.text-gray-700 { + color: #4a515b !important; +} + +.text-gray-800 { + color: #363d47 !important; +} + +.text-gray-900 { + color: #212832 !important; +} + +.fw-100 { + font-weight: 100 !important; +} + +.fw-200 { + font-weight: 200 !important; +} + +.fw-300 { + font-weight: 300 !important; +} + +.fw-400 { + font-weight: 400 !important; +} + +.fw-500 { + font-weight: 500 !important; +} + +.fw-600 { + font-weight: 600 !important; +} + +.fw-700 { + font-weight: 700 !important; +} + +.fw-800 { + font-weight: 800 !important; +} + +.fw-900 { + font-weight: 900 !important; +} + +.text-white-75 { + color: rgba(255, 255, 255, 0.75) !important; +} + +.text-white-25 { + color: rgba(255, 255, 255, 0.25) !important; +} + +.text-black-75 { + color: rgba(0, 0, 0, 0.75) !important; +} + +.text-black-25 { + color: rgba(0, 0, 0, 0.25) !important; +} + +.text-xs { + font-size: 0.75rem !important; +} + +.text-sm { + font-size: 0.875rem !important; +} + +.text-lg { + font-size: 1.25rem !important; +} + +.text-xl { + font-size: 2.5rem !important; +} + +.text-uppercase-expanded { + font-weight: 700; + letter-spacing: 0.125em; + text-transform: uppercase; +} + +.text-arrow-icon { + line-height: 1; + display: inline-flex; + align-items: center; +} +.text-arrow-icon svg { + margin-left: 0.25rem; +} +.text-arrow-icon.small svg { + height: 0.875rem; + width: 0.875rem; +} + +.line-height-normal { + line-height: normal !important; +} + +.feather-sm { + height: 0.875rem !important; + width: 0.875rem !important; +} + +.feather-lg { + height: 1.25rem !important; + width: 1.25rem !important; +} + +.feather-xl { + height: 2.5rem !important; + width: 2.5rem !important; +} + +.z-1 { + z-index: 1 !important; + position: relative !important; +} + +.z-2 { + z-index: 2 !important; + position: relative !important; +} + +.alert-icon { + position: relative; + display: flex; + padding: 0; +} +.alert-icon button.btn-close { + position: absolute; + top: 1.25rem; + right: 1rem; +} +.alert-icon .alert-icon-aside { + display: flex; + align-items: center; + justify-content: center; + padding-top: 1.25rem; + padding-bottom: 1.25rem; + padding-left: 1rem; + font-size: 1.5rem; +} +.alert-icon .alert-icon-aside svg.feather, +.alert-icon .alert-icon-aside svg, +.alert-icon .alert-icon-aside i { + height: 1.5rem; + width: 1.5rem; +} +.alert-icon .alert-icon-content { + padding-top: 1.25rem; + padding-bottom: 1.25rem; + padding-left: 1rem; + padding-right: 1rem; +} + +.alert-primary.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #0061f2; + --bs-alert-border-color: #0061f2; +} +.alert-primary.alert-solid .alert-link { + color: #cccccc; +} + +.alert-secondary.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #6900c7; + --bs-alert-border-color: #6900c7; +} +.alert-secondary.alert-solid .alert-link { + color: #cccccc; +} + +.alert-success.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #00ac69; + --bs-alert-border-color: #00ac69; +} +.alert-success.alert-solid .alert-link { + color: #cccccc; +} + +.alert-info.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #00cfd5; + --bs-alert-border-color: #00cfd5; +} +.alert-info.alert-solid .alert-link { + color: #cccccc; +} + +.alert-warning.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #f4a100; + --bs-alert-border-color: #f4a100; +} +.alert-warning.alert-solid .alert-link { + color: #cccccc; +} + +.alert-danger.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #e81500; + --bs-alert-border-color: #e81500; +} +.alert-danger.alert-solid .alert-link { + color: #cccccc; +} + +.alert-light.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #f2f6fc; + --bs-alert-border-color: #f2f6fc; +} +.alert-light.alert-solid .alert-link { + color: black; +} + +.alert-dark.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #212832; + --bs-alert-border-color: #212832; +} +.alert-dark.alert-solid .alert-link { + color: #cccccc; +} + +.alert-black.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #000; + --bs-alert-border-color: #000; +} +.alert-black.alert-solid .alert-link { + color: #cccccc; +} + +.alert-white.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #fff; + --bs-alert-border-color: #fff; +} +.alert-white.alert-solid .alert-link { + color: black; +} + +.alert-red.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #e81500; + --bs-alert-border-color: #e81500; +} +.alert-red.alert-solid .alert-link { + color: #cccccc; +} + +.alert-orange.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #f76400; + --bs-alert-border-color: #f76400; +} +.alert-orange.alert-solid .alert-link { + color: #cccccc; +} + +.alert-yellow.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #f4a100; + --bs-alert-border-color: #f4a100; +} +.alert-yellow.alert-solid .alert-link { + color: #cccccc; +} + +.alert-green.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #00ac69; + --bs-alert-border-color: #00ac69; +} +.alert-green.alert-solid .alert-link { + color: #cccccc; +} + +.alert-teal.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #00ba94; + --bs-alert-border-color: #00ba94; +} +.alert-teal.alert-solid .alert-link { + color: #cccccc; +} + +.alert-cyan.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #00cfd5; + --bs-alert-border-color: #00cfd5; +} +.alert-cyan.alert-solid .alert-link { + color: #cccccc; +} + +.alert-blue.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #0061f2; + --bs-alert-border-color: #0061f2; +} +.alert-blue.alert-solid .alert-link { + color: #cccccc; +} + +.alert-indigo.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #5800e8; + --bs-alert-border-color: #5800e8; +} +.alert-indigo.alert-solid .alert-link { + color: #cccccc; +} + +.alert-purple.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #6900c7; + --bs-alert-border-color: #6900c7; +} +.alert-purple.alert-solid .alert-link { + color: #cccccc; +} + +.alert-pink.alert-solid { + --bs-alert-color: #fff; + --bs-alert-bg: #e30059; + --bs-alert-border-color: #e30059; +} +.alert-pink.alert-solid .alert-link { + color: #cccccc; +} + +.alert-red-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #f1e0e3; + --bs-alert-border-color: #f1e0e3; +} +.alert-red-soft.alert-solid .alert-link { + color: black; +} + +.alert-orange-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #f3e7e3; + --bs-alert-border-color: #f3e7e3; +} +.alert-orange-soft.alert-solid .alert-link { + color: black; +} + +.alert-yellow-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #f2eee3; + --bs-alert-border-color: #f2eee3; +} +.alert-yellow-soft.alert-solid .alert-link { + color: black; +} + +.alert-green-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #daefed; + --bs-alert-border-color: #daefed; +} +.alert-green-soft.alert-solid .alert-link { + color: black; +} + +.alert-teal-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #daf0f2; + --bs-alert-border-color: #daf0f2; +} +.alert-teal-soft.alert-solid .alert-link { + color: black; +} + +.alert-cyan-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #daf2f8; + --bs-alert-border-color: #daf2f8; +} +.alert-cyan-soft.alert-solid .alert-link { + color: black; +} + +.alert-blue-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #dae7fb; + --bs-alert-border-color: #dae7fb; +} +.alert-blue-soft.alert-solid .alert-link { + color: black; +} + +.alert-indigo-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #e3ddfa; + --bs-alert-border-color: #e3ddfa; +} +.alert-indigo-soft.alert-solid .alert-link { + color: black; +} + +.alert-purple-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #e4ddf7; + --bs-alert-border-color: #e4ddf7; +} +.alert-purple-soft.alert-solid .alert-link { + color: black; +} + +.alert-pink-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #f1ddec; + --bs-alert-border-color: #f1ddec; +} +.alert-pink-soft.alert-solid .alert-link { + color: black; +} + +.alert-primary-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #dae7fb; + --bs-alert-border-color: #dae7fb; +} +.alert-primary-soft.alert-solid .alert-link { + color: black; +} + +.alert-secondary-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #e4ddf7; + --bs-alert-border-color: #e4ddf7; +} +.alert-secondary-soft.alert-solid .alert-link { + color: black; +} + +.alert-success-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #daefed; + --bs-alert-border-color: #daefed; +} +.alert-success-soft.alert-solid .alert-link { + color: black; +} + +.alert-info-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #daf2f8; + --bs-alert-border-color: #daf2f8; +} +.alert-info-soft.alert-solid .alert-link { + color: black; +} + +.alert-warning-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #f2eee3; + --bs-alert-border-color: #f2eee3; +} +.alert-warning-soft.alert-solid .alert-link { + color: black; +} + +.alert-danger-soft.alert-solid { + --bs-alert-color: #000; + --bs-alert-bg: #f1e0e3; + --bs-alert-border-color: #f1e0e3; +} +.alert-danger-soft.alert-solid .alert-link { + color: black; +} + +.avatar { + display: inline-flex; + height: 2rem; + width: 2rem; + border-radius: 50%; + position: relative; + align-items: center; + justify-content: center; +} +.avatar .avatar-img { + border-radius: 100%; + -o-object-fit: cover; + object-fit: cover; + height: 2rem; + width: auto; +} + +.avatar-xs { + height: 1.25rem; + width: 1.25rem; +} +.avatar-xs .avatar-img { + height: 1rem; +} + +.avatar-sm { + height: 1.75rem; + width: 1.75rem; +} +.avatar-sm .avatar-img { + height: 1.5rem; +} + +.avatar-lg { + height: 2.5rem; + width: 2.5rem; +} +.avatar-lg .avatar-img { + height: 2.5rem; +} + +.avatar-xl { + height: 3rem; + width: 3rem; +} +.avatar-xl .avatar-img { + height: 3rem; +} + +.avatar-xxl { + height: 3.75rem; + width: 3.75rem; +} +.avatar-xxl .avatar-img { + height: 3.75rem; +} + +.avatar-busy::before, +.avatar-idle::before, +.avatar-offline::before, +.avatar-online::before { + content: ""; + position: absolute; + bottom: 5%; + right: 5%; + width: 20%; + height: 20%; + border-radius: 50%; + background-color: #d4dae3; + border: 0.0625rem solid #fff; +} + +.avatar-busy::before { + background-color: #e81500; +} + +.avatar-idle::before { + background-color: #f4a100; +} + +.avatar-offline::before { + background-color: #d4dae3; +} + +.avatar-online::before { + background-color: #00ac69; +} + +.btn { + display: inline-flex; + align-items: center; + justify-content: center; +} + +.btn-icon { + padding: 0; + justify-content: center; + overflow: hidden; + border-radius: 100%; + flex-shrink: 0; + height: calc((0.875rem * 1) + (0.875rem * 2) + (2px)) !important; + width: calc((0.875rem * 1) + (0.875rem * 2) + (2px)) !important; +} +.btn-icon .feather { + margin-top: 0 !important; +} +.btn-icon.btn-xl { + height: calc((1.125rem * 1) + (1.25rem * 2) + (2px)) !important; + width: calc((1.125rem * 1) + (1.25rem * 2) + (2px)) !important; + border-radius: 100%; +} +.btn-icon.btn-lg, .btn-group-lg > .btn-icon.btn { + height: calc((1rem * 1) + (1.125rem * 2) + (2px)) !important; + width: calc((1rem * 1) + (1.125rem * 2) + (2px)) !important; +} +.btn-icon.btn-sm, .btn-group-sm > .btn-icon.btn { + height: calc((0.75rem * 1) + (0.5rem * 2) + (2px)) !important; + width: calc((0.75rem * 1) + (0.5rem * 2) + (2px)) !important; +} +.btn-icon.btn-xs { + height: calc((0.7rem * 1) + (0.25rem * 2) + (2px)) !important; + width: calc((0.7rem * 1) + (0.25rem * 2) + (2px)) !important; + border-radius: 100%; +} +.btn-icon.btn-link { + text-decoration: none; +} + +.btn .feather { + margin-top: -1px; + height: 0.875rem; + width: 0.875rem; +} + +.btn-lg .feather, .btn-group-lg > .btn .feather { + height: 1rem; + width: 1rem; +} + +.btn-sm .feather, .btn-group-sm > .btn .feather { + height: 0.75rem; + width: 0.75rem; +} + +.btn-xs .feather { + height: 0.7rem; + width: 0.7rem; +} + +.btn-xl .feather { + height: 1.125rem; + width: 1.125rem; +} + +.btn-xs { + padding: 0.25rem 0.5rem; + font-size: 0.7rem; + border-radius: 0.35rem; + line-height: 1; +} + +.btn-xl { + padding: 1.25rem 1.5rem; + font-size: 1.125rem; + border-radius: 0.5rem; +} + +.btn-facebook { + --bs-btn-color: #fff; + --bs-btn-bg: #3b5998; + --bs-btn-border-color: #3b5998; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #324c81; + --bs-btn-hover-border-color: #2f477a; + --bs-btn-focus-shadow-rgb: 88, 114, 167; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #2f477a; + --bs-btn-active-border-color: #2c4372; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #3b5998; + --bs-btn-disabled-border-color: #3b5998; +} + +.btn-github { + --bs-btn-color: #fff; + --bs-btn-bg: #333333; + --bs-btn-border-color: #333333; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #2b2b2b; + --bs-btn-hover-border-color: #292929; + --bs-btn-focus-shadow-rgb: 82, 82, 82; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #292929; + --bs-btn-active-border-color: #262626; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #333333; + --bs-btn-disabled-border-color: #333333; +} + +.btn-google { + --bs-btn-color: #fff; + --bs-btn-bg: #ea4335; + --bs-btn-border-color: #ea4335; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #c7392d; + --bs-btn-hover-border-color: #bb362a; + --bs-btn-focus-shadow-rgb: 237, 95, 83; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #bb362a; + --bs-btn-active-border-color: #b03228; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #ea4335; + --bs-btn-disabled-border-color: #ea4335; +} + +.btn-twitter { + --bs-btn-color: #fff; + --bs-btn-bg: #1da1f2; + --bs-btn-border-color: #1da1f2; + --bs-btn-hover-color: #fff; + --bs-btn-hover-bg: #1989ce; + --bs-btn-hover-border-color: #1781c2; + --bs-btn-focus-shadow-rgb: 63, 175, 244; + --bs-btn-active-color: #fff; + --bs-btn-active-bg: #1781c2; + --bs-btn-active-border-color: #1679b6; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: #fff; + --bs-btn-disabled-bg: #1da1f2; + --bs-btn-disabled-border-color: #1da1f2; +} + +.btn-transparent-dark { + --bs-btn-color: rgba(33, 40, 50, 0.5); + --bs-btn-bg: transparent; + --bs-btn-border-color: transparent; + --bs-btn-hover-color: rgba(33, 40, 50, 0.5); + --bs-btn-hover-bg: rgba(33, 40, 50, 0.1); + --bs-btn-hover-border-color: transparent; + --bs-btn-focus-shadow-rgb: 11, 14, 17; + --bs-btn-active-color: rgba(33, 40, 50, 0.5); + --bs-btn-active-bg: rgba(33, 40, 50, 0.2); + --bs-btn-active-border-color: transparent; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: rgba(33, 40, 50, 0.35); + --bs-btn-disabled-bg: rgba(33, 40, 50, 0.1); + --bs-btn-disabled-border-color: transparent; + color: rgba(33, 40, 50, 0.5) !important; +} +.btn-transparent-dark:focus { + box-shadow: 0 0 0 0.25rem rgba(33, 40, 50, 0.25) !important; +} + +.btn-transparent-light { + --bs-btn-color: rgba(255, 255, 255, 0.5); + --bs-btn-bg: transparent; + --bs-btn-border-color: transparent; + --bs-btn-hover-color: rgba(255, 255, 255, 0.5); + --bs-btn-hover-bg: rgba(255, 255, 255, 0.1); + --bs-btn-hover-border-color: transparent; + --bs-btn-focus-shadow-rgb: 88, 88, 88; + --bs-btn-active-color: rgba(255, 255, 255, 0.5); + --bs-btn-active-bg: rgba(255, 255, 255, 0.2); + --bs-btn-active-border-color: transparent; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: rgba(255, 255, 255, 0.35); + --bs-btn-disabled-bg: rgba(255, 255, 255, 0.1); + --bs-btn-disabled-border-color: transparent; + color: rgba(255, 255, 255, 0.5) !important; +} +.btn-transparent-light:focus { + box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.25) !important; +} + +.btn-white-10 { + --bs-btn-color: rgba(255, 255, 255, 0.5); + --bs-btn-bg: rgba(255, 255, 255, 0.1); + --bs-btn-border-color: transparent; + --bs-btn-hover-color: rgba(255, 255, 255, 0.5); + --bs-btn-hover-bg: rgba(255, 255, 255, 0.15); + --bs-btn-hover-border-color: transparent; + --bs-btn-focus-shadow-rgb: 88, 88, 88; + --bs-btn-active-color: rgba(255, 255, 255, 0.5); + --bs-btn-active-bg: rgba(255, 255, 255, 0.2); + --bs-btn-active-border-color: transparent; + --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + --bs-btn-disabled-color: rgba(255, 255, 255, 0.35); + --bs-btn-disabled-bg: rgba(255, 255, 255, 0.1); + --bs-btn-disabled-border-color: transparent; + color: rgba(255, 255, 255, 0.5) !important; +} +.btn-white-10:focus { + box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.25) !important; +} + +.card { + box-shadow: 0 0.15rem 1.75rem 0 rgba(33, 40, 50, 0.15); +} +.card .card-header { + font-weight: 500; +} +.card:not([class*=bg-]) .card-header { + color: #0061f2; +} + +.card.bg-dark .card-header, +.card.bg-dark .card-footer { + border-color: rgba(255, 255, 255, 0.15); +} + +.card .card-header .card-header-tabs .nav-link.active { + background-color: #fff; + border-bottom-color: #fff; +} + +.card-header-actions .card-header { + height: 3.5625rem; + display: flex; + align-items: center; + justify-content: space-between; + padding-top: 0.5625rem; + padding-bottom: 0.5625rem; +} +.card-header-actions .card-header .dropdown-menu { + margin-top: 0; + top: 0.5625rem !important; +} + +.card-collapsable .card-header[data-bs-toggle=collapse], +.card-collapsable .card-header[data-toggle=collapse] { + display: flex; + text-decoration: none; + position: relative; + align-items: center; + justify-content: space-between; +} +.card-collapsable .card-header[data-bs-toggle=collapse] .card-collapsable-arrow, +.card-collapsable .card-header[data-toggle=collapse] .card-collapsable-arrow { + height: 0.9rem; + width: 0.9rem; + display: inline-flex; + font-size: 0.9rem; + transition: transform 0.1s ease-in-out; +} +.card-collapsable .card-header[data-bs-toggle=collapse] .card-collapsable-arrow svg, +.card-collapsable .card-header[data-bs-toggle=collapse] .card-collapsable-arrow i, +.card-collapsable .card-header[data-bs-toggle=collapse] .card-collapsable-arrow .feather, +.card-collapsable .card-header[data-toggle=collapse] .card-collapsable-arrow svg, +.card-collapsable .card-header[data-toggle=collapse] .card-collapsable-arrow i, +.card-collapsable .card-header[data-toggle=collapse] .card-collapsable-arrow .feather { + height: 0.9rem; + width: 0.9rem; +} +.card-collapsable .card-header[data-bs-toggle=collapse].collapsed, +.card-collapsable .card-header[data-toggle=collapse].collapsed { + border-radius: 0.35rem; +} +.card-collapsable .card-header[data-bs-toggle=collapse].collapsed .card-collapsable-arrow, +.card-collapsable .card-header[data-toggle=collapse].collapsed .card-collapsable-arrow { + transform: rotate(-90deg); +} + +.card-icon { + overflow: hidden; +} +.card-icon .card-icon-aside { + display: flex; + align-items: center; + justify-content: center; + font-size: 3rem; + padding: 2rem; +} +.card-icon .card-icon-aside i, +.card-icon .card-icon-aside svg, +.card-icon .card-icon-aside .feather { + height: 3rem; + width: 3rem; +} + +.card-link { + text-decoration: none !important; + color: inherit !important; +} +.card-link:hover { + color: inherit !important; +} + +.card-progress .progress { + height: 0.5rem; + background-color: rgba(33, 40, 50, 0.03); +} + +.card-scrollable .card-body { + max-height: 15rem; + overflow-y: auto; +} + +.card-waves .card-body, +.card-angles .card-body { + background-size: 100% auto; + background-repeat: no-repeat; + background-position: center bottom; +} + +.card-waves .card-body { + background-image: url("../assets/img/backgrounds/bg-waves.svg"); +} + +.card-angles .card-body { + background-image: url("../assets/img/backgrounds/bg-angles.svg"); +} + +.card-flag { + position: absolute; + font-size: 0.7rem; + padding: 0.3rem 0.5rem; + line-height: 1; +} + +.card-flag-dark { + background-color: rgba(33, 40, 50, 0.7); + color: #fff; +} + +.card-flag-light { + background-color: rgba(255, 255, 255, 0.7); + color: #69707a; +} + +.card-flag-lg { + font-size: 0.9rem; + padding: 0.5rem 0.65rem; +} + +.card-flag-top-right { + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + top: 0.5rem; + right: 0; +} + +.card-flag-top-left { + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; + top: 0.5rem; + left: 0; +} + +.card-flag-bottom-right { + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + bottom: 0.5rem; + right: 0; +} + +.card-flag-bottom-left { + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; + bottom: 0.5rem; + left: 0; +} + +.dropdown-menu { + font-size: 0.9rem; + border: none; + box-shadow: 0 0.15rem 1.75rem 0 rgba(33, 40, 50, 0.15); +} +.dropdown-menu .dropdown-header { + font-size: 0.75rem; + font-weight: 700; + display: flex; + align-items: center; +} +.dropdown-menu .dropdown-item { + display: flex; + align-items: center; +} +.dropdown-menu .dropdown-item .dropdown-item-icon { + margin-right: 0.5rem; + line-height: 1; +} +.dropdown-menu .dropdown-item .dropdown-item-icon svg { + height: 0.9em; + width: 0.9em; +} +.dropdown-menu .dropdown-item.active .dropdown-item-icon, .dropdown-menu .dropdown-item:active .dropdown-item-icon { + color: #fff; +} + +.dropdown .dropdown-toggle { + display: inline-flex; + align-items: center; +} +.dropdown .dropdown-toggle .dropdown-arrow { + margin-left: 0.4rem; + margin-right: 0; + transition: transform 0.1s ease-in-out; + font-size: 0.6em; +} +.dropdown .dropdown-toggle.show .dropdown-arrow { + transform: rotate(90deg); +} + +.feather { + height: 1rem; + width: 1rem; + vertical-align: top; +} + +.feather-sm { + height: 0.8rem; + width: 0.8rem; +} + +.icon-stack { + display: inline-flex; + justify-content: center; + align-items: center; + border-radius: 100%; + height: 2.5rem; + width: 2.5rem; + font-size: 1rem; + background-color: #f2f6fc; + flex-shrink: 0; +} +.icon-stack svg { + height: 1rem; + width: 1rem; +} + +.icon-stack-sm { + height: 2rem; + width: 2rem; +} + +.icon-stack-lg { + height: 4rem; + width: 4rem; + font-size: 1.5rem; +} +.icon-stack-lg svg { + height: 1.5rem; + width: 1.5rem; +} + +.icon-stack-xl { + height: 5rem; + width: 5rem; + font-size: 1.75rem; +} +.icon-stack-xl svg { + height: 1.75rem; + width: 1.75rem; +} + +.icon-list-social { + display: flex; +} +.icon-list-social .icon-list-social-link { + font-size: 1.25rem; + margin-right: 0.5rem; +} + +.badge-sm { + font-size: 0.75rem; +} + +.badge-md { + font-size: 1rem; +} + +.badge-lg { + font-size: 1.25rem; +} + +.timeline .timeline-item { + display: flex; + align-items: flex-start; +} +.timeline .timeline-item .timeline-item-marker { + display: inline-flex; + flex-direction: column; + align-items: center; + justify-content: center; + margin-bottom: 2rem; +} +.timeline .timeline-item .timeline-item-marker .timeline-item-marker-text { + font-size: 0.875rem; + width: 6rem; + color: #a7aeb8; + text-align: center; + margin-bottom: 0.5rem; + display: block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.timeline .timeline-item .timeline-item-marker .timeline-item-marker-indicator { + display: inline-flex; + align-items: center; + justify-content: center; + height: 3rem; + width: 3rem; + background-color: #f2f6fc; + border-radius: 100%; +} +.timeline .timeline-item .timeline-item-content { + padding-top: 0; + padding-bottom: 2rem; + padding-left: 1rem; + width: 100%; +} +.timeline .timeline-item:last-child .timeline-item-content { + padding-bottom: 0 !important; +} + +@media (min-width: 576px) { + .timeline .timeline-item .timeline-item-marker { + flex-direction: row; + transform: translateX(1.625rem); + margin-bottom: 0; + } + .timeline .timeline-item .timeline-item-marker .timeline-item-marker-text { + margin-right: 0.5rem; + margin-bottom: 0; + } + .timeline .timeline-item .timeline-item-content { + padding-top: 0.75rem; + padding-bottom: 3rem; + padding-left: 3rem; + border-left: solid 0.25rem #f2f6fc; + } + .timeline .timeline-item:last-child .timeline-item-content { + border-left-color: transparent; + } +} +.timeline.timeline-sm .timeline-item .timeline-item-marker { + transform: translateX(0.875rem); +} +.timeline.timeline-sm .timeline-item .timeline-item-marker .timeline-item-marker-text { + width: 3rem; + font-size: 0.7rem; +} +.timeline.timeline-sm .timeline-item .timeline-item-marker .timeline-item-marker-indicator { + height: 1.5rem; + width: 1.5rem; + font-size: 0.875rem; +} +.timeline.timeline-sm .timeline-item .timeline-item-marker .timeline-item-marker-indicator .feather { + height: 0.75rem; + width: 0.75rem; +} +.timeline.timeline-sm .timeline-item .timeline-item-content { + font-size: 0.875rem; + padding-top: 0.15rem; + padding-bottom: 1rem; + padding-left: 1.5rem; +} + +.timeline.timeline-xs .timeline-item .timeline-item-marker { + transform: translateX(0.5625rem); +} +.timeline.timeline-xs .timeline-item .timeline-item-marker .timeline-item-marker-text { + width: 3rem; + font-size: 0.7rem; +} +.timeline.timeline-xs .timeline-item .timeline-item-marker .timeline-item-marker-indicator { + height: 0.875rem; + width: 0.875rem; + font-size: 0.875rem; + border: 0.125rem solid #fff; + margin-top: -0.125rem; +} +.timeline.timeline-xs .timeline-item .timeline-item-content { + font-size: 0.875rem; + padding-top: 0; + padding-bottom: 1rem; + padding-left: 1.5rem; +} + +.step { + display: flex; + flex-wrap: nowrap; + width: 100%; +} +.step .step-item { + flex: 1 1 0; + position: relative; + text-align: center; +} +.step .step-item:not(:first-child)::before { + background-color: #69707a; + content: ""; + height: 0.125rem; + left: -50%; + position: absolute; + top: 0.4375rem; + width: 100%; + z-index: 0; +} +.step .step-item .step-item-link { + color: #69707a; + position: relative; + display: inline-block; + padding-top: 1.25rem; + padding-left: 1rem; + padding-right: 1rem; + text-decoration: none; + z-index: 1; +} +.step .step-item .step-item-link::before { + background-color: #69707a; + border: 0.125rem solid #fff; + border-radius: 100%; + content: ""; + display: block; + height: 1rem; + width: 1rem; + left: 50%; + position: absolute; + top: 0; + transform: translateX(-50%); + z-index: 1; +} +.step .step-item .step-item-link.disabled { + pointer-events: none; + cursor: default; +} +.step .step-item.active a::before { + background: #fff; + border: 0.125rem solid #69707a; +} +.step .step-item.active ~ .step-item .step-item-link { + color: #d4dae3; +} +.step .step-item.active ~ .step-item .step-item-link::before { + background: #d4dae3; +} +.step .step-item.active ~ .step-item::before { + background: #d4dae3; +} + +.step-lg .step-item:not(:first-child)::before { + height: 0.25rem; + top: 0.625rem; +} +.step-lg .step-item .step-item-link { + padding-top: 2rem; +} +.step-lg .step-item .step-item-link::before { + border-width: 0.25rem; + height: 1.5rem; + width: 1.5rem; +} +.step-lg .step-item.active a::before { + border-width: 0.25rem; +} + +.step-primary .step-item:not(:first-child)::before { + background-color: #0061f2; +} +.step-primary .step-item .step-item-link { + color: #0061f2; +} +.step-primary .step-item .step-item-link::before { + background-color: #0061f2; +} +.step-primary .step-item.active a::before { + border-color: #0061f2; +} + +.step-secondary .step-item:not(:first-child)::before { + background-color: #6900c7; +} +.step-secondary .step-item .step-item-link { + color: #6900c7; +} +.step-secondary .step-item .step-item-link::before { + background-color: #6900c7; +} +.step-secondary .step-item.active a::before { + border-color: #6900c7; +} + +.step-success .step-item:not(:first-child)::before { + background-color: #00ac69; +} +.step-success .step-item .step-item-link { + color: #00ac69; +} +.step-success .step-item .step-item-link::before { + background-color: #00ac69; +} +.step-success .step-item.active a::before { + border-color: #00ac69; +} + +.step-info .step-item:not(:first-child)::before { + background-color: #00cfd5; +} +.step-info .step-item .step-item-link { + color: #00cfd5; +} +.step-info .step-item .step-item-link::before { + background-color: #00cfd5; +} +.step-info .step-item.active a::before { + border-color: #00cfd5; +} + +.step-warning .step-item:not(:first-child)::before { + background-color: #f4a100; +} +.step-warning .step-item .step-item-link { + color: #f4a100; +} +.step-warning .step-item .step-item-link::before { + background-color: #f4a100; +} +.step-warning .step-item.active a::before { + border-color: #f4a100; +} + +.step-danger .step-item:not(:first-child)::before { + background-color: #e81500; +} +.step-danger .step-item .step-item-link { + color: #e81500; +} +.step-danger .step-item .step-item-link::before { + background-color: #e81500; +} +.step-danger .step-item.active a::before { + border-color: #e81500; +} + +.step-light .step-item:not(:first-child)::before { + background-color: #f2f6fc; +} +.step-light .step-item .step-item-link { + color: #f2f6fc; +} +.step-light .step-item .step-item-link::before { + background-color: #f2f6fc; +} +.step-light .step-item.active a::before { + border-color: #f2f6fc; +} + +.step-dark .step-item:not(:first-child)::before { + background-color: #212832; +} +.step-dark .step-item .step-item-link { + color: #212832; +} +.step-dark .step-item .step-item-link::before { + background-color: #212832; +} +.step-dark .step-item.active a::before { + border-color: #212832; +} + +.step-black .step-item:not(:first-child)::before { + background-color: #000; +} +.step-black .step-item .step-item-link { + color: #000; +} +.step-black .step-item .step-item-link::before { + background-color: #000; +} +.step-black .step-item.active a::before { + border-color: #000; +} + +.step-white .step-item:not(:first-child)::before { + background-color: #fff; +} +.step-white .step-item .step-item-link { + color: #fff; +} +.step-white .step-item .step-item-link::before { + background-color: #fff; +} +.step-white .step-item.active a::before { + border-color: #fff; +} + +.step-red .step-item:not(:first-child)::before { + background-color: #e81500; +} +.step-red .step-item .step-item-link { + color: #e81500; +} +.step-red .step-item .step-item-link::before { + background-color: #e81500; +} +.step-red .step-item.active a::before { + border-color: #e81500; +} + +.step-orange .step-item:not(:first-child)::before { + background-color: #f76400; +} +.step-orange .step-item .step-item-link { + color: #f76400; +} +.step-orange .step-item .step-item-link::before { + background-color: #f76400; +} +.step-orange .step-item.active a::before { + border-color: #f76400; +} + +.step-yellow .step-item:not(:first-child)::before { + background-color: #f4a100; +} +.step-yellow .step-item .step-item-link { + color: #f4a100; +} +.step-yellow .step-item .step-item-link::before { + background-color: #f4a100; +} +.step-yellow .step-item.active a::before { + border-color: #f4a100; +} + +.step-green .step-item:not(:first-child)::before { + background-color: #00ac69; +} +.step-green .step-item .step-item-link { + color: #00ac69; +} +.step-green .step-item .step-item-link::before { + background-color: #00ac69; +} +.step-green .step-item.active a::before { + border-color: #00ac69; +} + +.step-teal .step-item:not(:first-child)::before { + background-color: #00ba94; +} +.step-teal .step-item .step-item-link { + color: #00ba94; +} +.step-teal .step-item .step-item-link::before { + background-color: #00ba94; +} +.step-teal .step-item.active a::before { + border-color: #00ba94; +} + +.step-cyan .step-item:not(:first-child)::before { + background-color: #00cfd5; +} +.step-cyan .step-item .step-item-link { + color: #00cfd5; +} +.step-cyan .step-item .step-item-link::before { + background-color: #00cfd5; +} +.step-cyan .step-item.active a::before { + border-color: #00cfd5; +} + +.step-blue .step-item:not(:first-child)::before { + background-color: #0061f2; +} +.step-blue .step-item .step-item-link { + color: #0061f2; +} +.step-blue .step-item .step-item-link::before { + background-color: #0061f2; +} +.step-blue .step-item.active a::before { + border-color: #0061f2; +} + +.step-indigo .step-item:not(:first-child)::before { + background-color: #5800e8; +} +.step-indigo .step-item .step-item-link { + color: #5800e8; +} +.step-indigo .step-item .step-item-link::before { + background-color: #5800e8; +} +.step-indigo .step-item.active a::before { + border-color: #5800e8; +} + +.step-purple .step-item:not(:first-child)::before { + background-color: #6900c7; +} +.step-purple .step-item .step-item-link { + color: #6900c7; +} +.step-purple .step-item .step-item-link::before { + background-color: #6900c7; +} +.step-purple .step-item.active a::before { + border-color: #6900c7; +} + +.step-pink .step-item:not(:first-child)::before { + background-color: #e30059; +} +.step-pink .step-item .step-item-link { + color: #e30059; +} +.step-pink .step-item .step-item-link::before { + background-color: #e30059; +} +.step-pink .step-item.active a::before { + border-color: #e30059; +} + +.step-red-soft .step-item:not(:first-child)::before { + background-color: #f1e0e3; +} +.step-red-soft .step-item .step-item-link { + color: #f1e0e3; +} +.step-red-soft .step-item .step-item-link::before { + background-color: #f1e0e3; +} +.step-red-soft .step-item.active a::before { + border-color: #f1e0e3; +} + +.step-orange-soft .step-item:not(:first-child)::before { + background-color: #f3e7e3; +} +.step-orange-soft .step-item .step-item-link { + color: #f3e7e3; +} +.step-orange-soft .step-item .step-item-link::before { + background-color: #f3e7e3; +} +.step-orange-soft .step-item.active a::before { + border-color: #f3e7e3; +} + +.step-yellow-soft .step-item:not(:first-child)::before { + background-color: #f2eee3; +} +.step-yellow-soft .step-item .step-item-link { + color: #f2eee3; +} +.step-yellow-soft .step-item .step-item-link::before { + background-color: #f2eee3; +} +.step-yellow-soft .step-item.active a::before { + border-color: #f2eee3; +} + +.step-green-soft .step-item:not(:first-child)::before { + background-color: #daefed; +} +.step-green-soft .step-item .step-item-link { + color: #daefed; +} +.step-green-soft .step-item .step-item-link::before { + background-color: #daefed; +} +.step-green-soft .step-item.active a::before { + border-color: #daefed; +} + +.step-teal-soft .step-item:not(:first-child)::before { + background-color: #daf0f2; +} +.step-teal-soft .step-item .step-item-link { + color: #daf0f2; +} +.step-teal-soft .step-item .step-item-link::before { + background-color: #daf0f2; +} +.step-teal-soft .step-item.active a::before { + border-color: #daf0f2; +} + +.step-cyan-soft .step-item:not(:first-child)::before { + background-color: #daf2f8; +} +.step-cyan-soft .step-item .step-item-link { + color: #daf2f8; +} +.step-cyan-soft .step-item .step-item-link::before { + background-color: #daf2f8; +} +.step-cyan-soft .step-item.active a::before { + border-color: #daf2f8; +} + +.step-blue-soft .step-item:not(:first-child)::before { + background-color: #dae7fb; +} +.step-blue-soft .step-item .step-item-link { + color: #dae7fb; +} +.step-blue-soft .step-item .step-item-link::before { + background-color: #dae7fb; +} +.step-blue-soft .step-item.active a::before { + border-color: #dae7fb; +} + +.step-indigo-soft .step-item:not(:first-child)::before { + background-color: #e3ddfa; +} +.step-indigo-soft .step-item .step-item-link { + color: #e3ddfa; +} +.step-indigo-soft .step-item .step-item-link::before { + background-color: #e3ddfa; +} +.step-indigo-soft .step-item.active a::before { + border-color: #e3ddfa; +} + +.step-purple-soft .step-item:not(:first-child)::before { + background-color: #e4ddf7; +} +.step-purple-soft .step-item .step-item-link { + color: #e4ddf7; +} +.step-purple-soft .step-item .step-item-link::before { + background-color: #e4ddf7; +} +.step-purple-soft .step-item.active a::before { + border-color: #e4ddf7; +} + +.step-pink-soft .step-item:not(:first-child)::before { + background-color: #f1ddec; +} +.step-pink-soft .step-item .step-item-link { + color: #f1ddec; +} +.step-pink-soft .step-item .step-item-link::before { + background-color: #f1ddec; +} +.step-pink-soft .step-item.active a::before { + border-color: #f1ddec; +} + +.step-primary-soft .step-item:not(:first-child)::before { + background-color: #dae7fb; +} +.step-primary-soft .step-item .step-item-link { + color: #dae7fb; +} +.step-primary-soft .step-item .step-item-link::before { + background-color: #dae7fb; +} +.step-primary-soft .step-item.active a::before { + border-color: #dae7fb; +} + +.step-secondary-soft .step-item:not(:first-child)::before { + background-color: #e4ddf7; +} +.step-secondary-soft .step-item .step-item-link { + color: #e4ddf7; +} +.step-secondary-soft .step-item .step-item-link::before { + background-color: #e4ddf7; +} +.step-secondary-soft .step-item.active a::before { + border-color: #e4ddf7; +} + +.step-success-soft .step-item:not(:first-child)::before { + background-color: #daefed; +} +.step-success-soft .step-item .step-item-link { + color: #daefed; +} +.step-success-soft .step-item .step-item-link::before { + background-color: #daefed; +} +.step-success-soft .step-item.active a::before { + border-color: #daefed; +} + +.step-info-soft .step-item:not(:first-child)::before { + background-color: #daf2f8; +} +.step-info-soft .step-item .step-item-link { + color: #daf2f8; +} +.step-info-soft .step-item .step-item-link::before { + background-color: #daf2f8; +} +.step-info-soft .step-item.active a::before { + border-color: #daf2f8; +} + +.step-warning-soft .step-item:not(:first-child)::before { + background-color: #f2eee3; +} +.step-warning-soft .step-item .step-item-link { + color: #f2eee3; +} +.step-warning-soft .step-item .step-item-link::before { + background-color: #f2eee3; +} +.step-warning-soft .step-item.active a::before { + border-color: #f2eee3; +} + +.step-danger-soft .step-item:not(:first-child)::before { + background-color: #f1e0e3; +} +.step-danger-soft .step-item .step-item-link { + color: #f1e0e3; +} +.step-danger-soft .step-item .step-item-link::before { + background-color: #f1e0e3; +} +.step-danger-soft .step-item.active a::before { + border-color: #f1e0e3; +} + +.form-check.form-check-solid .form-check-input { + background-color: #eef2f8; + border-color: #eef2f8; +} +.form-check.form-check-solid .form-check-input:checked { + background-color: #0061f2; +} + +.form-control-solid { + background-color: #eef2f8; + border-color: #eef2f8; +} +.form-control-solid:focus { + background-color: #eef2f8; +} + +.input-group-joined { + border-color: #c5ccd6; + border-width: 1px; + border-style: solid; + border-radius: 0.4375rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} +.input-group-joined:focus-within { + border-color: transparent; + box-shadow: 0 0 0 0.25rem rgba(0, 97, 242, 0.25); +} +.input-group-joined .form-control, .input-group-joined .datatable-input { + border: none; +} +.input-group-joined .form-control:focus, .input-group-joined .datatable-input:focus { + box-shadow: none; + outline: none; +} +.input-group-joined .input-group-text, +.input-group-joined .input-group-text { + border: none; + background-color: #fff; +} + +.input-group-joined-xl .form-control, .input-group-joined-xl .datatable-input { + height: 4rem; + font-size: 1.25rem; +} + +.input-group-joined.input-group-solid { + border: 0; + background-color: #eef2f8; +} +.input-group-joined.input-group-solid .form-control, .input-group-joined.input-group-solid .datatable-input, +.input-group-joined.input-group-solid .input-group-text { + background-color: transparent; +} + +#layoutSidenav { + display: flex; +} +#layoutSidenav #layoutSidenav_nav { + flex-basis: 15rem; + flex-shrink: 0; + transition: transform 0.15s ease-in-out; + z-index: 1038; + transform: translateX(-15rem); +} +#layoutSidenav #layoutSidenav_content { + position: relative; + display: flex; + flex-direction: column; + justify-content: space-between; + min-width: 0; + flex-grow: 1; + min-height: calc(100vh - 3.625rem); + margin-left: -15rem; +} + +.sidenav-toggled #layoutSidenav #layoutSidenav_nav { + transform: translateX(0); +} +.sidenav-toggled #layoutSidenav #layoutSidenav_content:before { + content: ""; + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: #000; + z-index: 1037; + opacity: 0.5; + transition: opacity 0.3s ease-in-out; +} + +@media (min-width: 992px) { + #layoutSidenav #layoutSidenav_nav { + transform: translateX(0); + } + #layoutSidenav #layoutSidenav_content { + margin-left: 0; + transition: margin 0.15s ease-in-out; + } + .sidenav-toggled #layoutSidenav #layoutSidenav_nav { + transform: translateX(-15rem); + } + .sidenav-toggled #layoutSidenav #layoutSidenav_content { + margin-left: -15rem; + } + .sidenav-toggled #layoutSidenav #layoutSidenav_content:before { + display: none; + } +} +.nav-fixed .topnav { + z-index: 1039; +} +.nav-fixed #layoutSidenav #layoutSidenav_nav { + width: 15rem; + height: 100vh; + z-index: 1038; +} +.nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav { + padding-top: 3.625rem; +} +.nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav .sidenav-menu { + overflow-y: overlay; +} +.nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav .sidenav-menu::-webkit-scrollbar { + width: 0.75rem; +} +.nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav .sidenav-menu::-webkit-scrollbar-thumb { + border-radius: 10rem; + border-width: 0.2rem; + border-style: solid; + background-clip: padding-box; + background-color: rgba(33, 40, 50, 0.2); + border-color: transparent; +} +.nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav .sidenav-menu::-webkit-scrollbar-button { + width: 0; + height: 0; + display: none; +} +.nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav .sidenav-menu::-webkit-scrollbar-corner { + background-color: transparent; +} +.nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav .sidenav-menu::-webkit-scrollbar-track { + background: inherit; +} +@media (pointer: fine) and (hover: hover) { + .nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav .sidenav-menu { + overflow-y: hidden; + } + .nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav .sidenav-menu:hover { + overflow-y: overlay; + } +} +@media (pointer: coarse) and (hover: none) { + .nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav .sidenav-menu { + overflow-y: overlay; + } +} +@-moz-document url-prefix() { + .nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav .sidenav-menu { + overflow-y: auto; + } +} +.nav-fixed #layoutSidenav #layoutSidenav_nav .sidenav.sidenav-dark .sidenav-menu::-webkit-scrollbar-thumb { + background-color: rgba(255, 255, 255, 0.25); + border-color: rgba(0, 0, 0, 0); +} +.nav-fixed #layoutSidenav #layoutSidenav_content { + padding-left: 15rem; + top: 3.625rem; +} + +.layout-rtl #layoutSidenav #layoutSidenav_nav { + transform: translateX(15rem); +} +.layout-rtl #layoutSidenav #layoutSidenav_content { + margin-left: 0; + margin-right: -15rem; +} +.layout-rtl.sidenav-toggled #layoutSidenav #layoutSidenav_nav { + transform: translateX(0); +} +@media (min-width: 992px) { + .layout-rtl #layoutSidenav #layoutSidenav_nav { + transform: translateX(0); + } + .layout-rtl #layoutSidenav #layoutSidenav_content { + margin-right: 0; + transition: margin 0.15s ease-in-out; + } + .layout-rtl.sidenav-toggled #layoutSidenav #layoutSidenav_nav { + transform: translateX(15rem); + } + .layout-rtl.sidenav-toggled #layoutSidenav #layoutSidenav_content { + margin-right: -15rem; + } +} + +.layout-rtl.nav-fixed #layoutSidenav #layoutSidenav_nav { + left: auto; +} +.layout-rtl.nav-fixed #layoutSidenav #layoutSidenav_content { + padding-left: 0; + padding-right: 15rem; +} + +.dropdown-notifications { + position: static; +} +.dropdown-notifications .dropdown-menu { + padding-top: 0; + padding-bottom: 0; + width: calc(100% - 1.5rem); + right: 0.75rem; + max-height: calc(21rem - 1px); + overflow-x: hidden; + overflow-y: overlay; +} +.dropdown-notifications .dropdown-menu::-webkit-scrollbar { + width: 0.75rem; +} +.dropdown-notifications .dropdown-menu::-webkit-scrollbar-thumb { + border-radius: 10rem; + border-width: 0.2rem; + border-style: solid; + background-clip: padding-box; + background-color: rgba(33, 40, 50, 0.2); + border-color: transparent; +} +.dropdown-notifications .dropdown-menu::-webkit-scrollbar-button { + width: 0; + height: 0; + display: none; +} +.dropdown-notifications .dropdown-menu::-webkit-scrollbar-corner { + background-color: transparent; +} +.dropdown-notifications .dropdown-menu::-webkit-scrollbar-track { + background: inherit; +} +@media (pointer: fine) and (hover: hover) { + .dropdown-notifications .dropdown-menu { + overflow-y: hidden; + } + .dropdown-notifications .dropdown-menu:hover { + overflow-y: overlay; + } +} +@media (pointer: coarse) and (hover: none) { + .dropdown-notifications .dropdown-menu { + overflow-y: overlay; + } +} +@-moz-document url-prefix() { + .dropdown-notifications .dropdown-menu { + overflow-y: auto; + } +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-header { + background-color: #0061f2; + color: #fff !important; + padding-top: 1rem; + padding-bottom: 1rem; + line-height: 1; +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-header svg { + height: 0.7rem; + width: 0.7rem; + opacity: 0.7; +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-item { + padding-top: 1rem; + padding-bottom: 1rem; + border-bottom: 1px solid #e0e5ec; +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-item .dropdown-notifications-item-icon, +.dropdown-notifications .dropdown-menu .dropdown-notifications-item .dropdown-notifications-item-img { + height: 2.5rem; + width: 2.5rem; + border-radius: 100%; + margin-right: 1rem; + flex-shrink: 0; +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-item .dropdown-notifications-item-icon { + background-color: #0061f2; + display: flex; + align-items: center; + justify-content: center; +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-item .dropdown-notifications-item-icon svg { + text-align: center; + font-size: 0.85rem; + color: #fff; + height: 0.85rem; +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-item .dropdown-notifications-item-content .dropdown-notifications-item-content-details { + color: #a7aeb8; + font-size: 0.7rem; +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-item .dropdown-notifications-item-content .dropdown-notifications-item-content-text { + font-size: 0.9rem; + max-width: calc(100vw - 8.5rem); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-item .dropdown-notifications-item-content .dropdown-notifications-item-content-actions .btn-sm, .dropdown-notifications .dropdown-menu .dropdown-notifications-item .dropdown-notifications-item-content .dropdown-notifications-item-content-actions .btn-group-sm > .btn { + font-size: 0.7rem; + padding: 0.15rem 0.35rem; + cursor: pointer; +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-footer { + justify-content: center; + font-size: 0.8rem; + padding-top: 0.75rem; + padding-bottom: 0.75rem; + color: #a7aeb8; + cursor: pointer; +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-footer .dropdown-notifications-footer-icon { + height: 1em; + width: 1em; + margin-left: 0.25rem; +} +.dropdown-notifications .dropdown-menu .dropdown-notifications-footer:active { + color: #fff; +} +@media (min-width: 576px) { + .dropdown-notifications { + position: relative; + } + .dropdown-notifications .dropdown-menu { + width: auto; + min-width: 18.75rem; + right: 0; + } + .dropdown-notifications .dropdown-menu .dropdown-notifications-item .dropdown-notifications-item-content .dropdown-notifications-item-content-text { + max-width: 13rem; + } +} + +.dropdown-user .dropdown-menu { + min-width: 13rem; +} +.dropdown-user .dropdown-menu .dropdown-header { + text-transform: none; + letter-spacing: normal; +} +.dropdown-user .dropdown-menu .dropdown-header .dropdown-user-img { + height: 2.5rem; + width: 2.5rem; + margin-right: 1rem; + border-radius: 100%; +} +.dropdown-user .dropdown-menu .dropdown-header .dropdown-user-details { + font-weight: 400; +} +.dropdown-user .dropdown-menu .dropdown-header .dropdown-user-details .dropdown-user-details-name { + color: #212832; + font-weight: 500; + font-size: 0.9rem; + max-width: 10rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.dropdown-user .dropdown-menu .dropdown-header .dropdown-user-details .dropdown-user-details-email { + color: #69707a; + font-size: 0.75rem; + max-width: 10rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.dropdown-user .dropdown-menu .dropdown-item { + align-items: center; +} +.dropdown-user .dropdown-menu .dropdown-item .dropdown-item-icon { + color: #a7aeb8; +} +.dropdown-user .dropdown-menu .dropdown-item .dropdown-item-icon svg { + vertical-align: inherit; +} +.dropdown-user .dropdown-menu .dropdown-item:active .dropdown-item-icon { + color: #fff; +} + +.footer-admin { + height: 5rem; + display: flex; + align-items: center; +} +.footer-admin.footer-dark { + color: rgba(255, 255, 255, 0.6); +} +.footer-admin.footer-light { + color: #a7aeb8; +} + +.nav .nav-link .nav-link-icon, +.sidenav-menu .nav-link .nav-link-icon { + margin-right: 0.5rem; +} + +.nav-borders .nav-link { + color: #69707a; + border-bottom-width: 0.125rem; + border-bottom-style: solid; + border-bottom-color: transparent; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 0; + padding-right: 0; + margin-left: 1rem; + margin-right: 1rem; +} +.nav-borders .nav-link.active { + color: #0061f2; + border-bottom-color: #0061f2; +} +.nav-borders .nav-link.disabled { + color: #c5ccd6; +} +.nav-borders.flex-column .nav-link { + padding-top: 0; + padding-bottom: 0; + padding-right: 1rem; + padding-left: 1rem; + margin-top: 0.5rem; + margin-bottom: 0.5rem; + margin-right: 0; + margin-left: 0; + border-bottom: none; + border-right-width: 0.125rem; + border-right-style: solid; + border-right-color: transparent; +} +.nav-borders.flex-column .nav-link.active { + border-right-color: #0061f2; +} + +.navbar .dropdown-menu { + top: calc(100% + 0.5rem + 0.5rem) !important; + font-size: 0.9rem; +} +.navbar .dropdown-menu .dropdown-header { + color: #a7aeb8; +} +.navbar .form-control, .navbar .datatable-input { + font-size: 0.9rem; +} + +.topnav { + padding-left: 0; + height: 3.625rem; + z-index: 1039; + font-size: 0.9rem; +} +.topnav .navbar-brand { + width: 15rem; + margin: 0; + font-size: 1rem; + font-weight: bold; +} +.topnav .navbar-brand img { + height: 0.8rem; +} +@media (min-width: 992px) { + .topnav .navbar-brand { + width: 12rem; + } +} +.topnav.navbar-dark #sidebarToggle { + color: rgba(255, 255, 255, 0.5); +} +.topnav.navbar-dark .navbar-brand { + color: #fff; +} +.topnav.navbar-light #sidebarToggle { + color: #212832; +} +.topnav.navbar-light .navbar-brand { + color: #363d47; +} +.topnav .dropdown { + position: static; +} +.topnav .dropdown .dropdown-menu { + width: calc(100% - 1.5rem); + right: 0.75rem; + left: 0.75rem; +} +@media (min-width: 576px) { + .topnav .dropdown { + position: relative; + } + .topnav .dropdown .dropdown-menu { + width: auto; + min-width: 15rem; + right: 0; + left: auto; + } +} + +:target:before { + content: ""; + display: block; + height: 5.125rem; + margin: -5.125rem 0 0; +} + +.nav-sticky { + top: 5.125rem; + font-size: 0.9rem; +} +.nav-sticky .nav-link { + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} +.nav-sticky .nav-link.active { + font-weight: 600; +} + +.sidenav { + display: flex; + flex-direction: column; + height: 100%; + flex-wrap: nowrap; + font-size: 0.9rem; +} +.sidenav .sidenav-menu { + flex-grow: 1; +} +.sidenav .sidenav-menu .nav { + flex-direction: column; + flex-wrap: nowrap; +} +.sidenav .sidenav-menu .nav .sidenav-menu-heading { + padding: 1.75rem 1rem 0.75rem; + font-size: 0.7rem; + font-weight: bold; + text-transform: uppercase; + letter-spacing: 0.05em; +} +.sidenav .sidenav-menu .nav .nav-link { + display: flex; + align-items: center; + line-height: normal; + padding-top: 0.75rem; + padding-bottom: 0.75rem; + position: relative; +} +.sidenav .sidenav-menu .nav .nav-link .nav-link-icon { + font-size: 0.9rem; + padding-right: 0.5rem; + display: inline-flex; +} +.sidenav .sidenav-menu .nav .nav-link .nav-link-icon .feather { + width: 1rem; + height: 1rem; +} +.sidenav .sidenav-menu .nav .nav-link.active { + font-weight: 600; +} +.sidenav .sidenav-menu .nav .nav-link.active .nav-icon { + color: #0061f2; +} +.sidenav .sidenav-menu .nav .nav-link .sidenav-collapse-arrow { + display: inline-block; + margin-left: auto; + transition: transform 0.15s ease; +} +.sidenav .sidenav-menu .nav .nav-link.collapsed .sidenav-collapse-arrow { + transform: rotate(-90deg); +} +.sidenav .sidenav-menu .nav .nav-link .badge { + padding: 0.125rem 0.25rem; +} +.sidenav .sidenav-menu .nav .sidenav-menu-nested { + flex-direction: column; + margin-left: 1.4375rem; + border-left-style: solid; + border-left-width: thin; + padding-left: 0.5625rem; +} +.sidenav .sidenav-footer { + display: flex; + flex-shrink: 0; + align-items: center; + padding-left: 0.75rem; + padding-right: 0.75rem; + height: 5rem; +} +.sidenav .sidenav-footer .sidenav-footer-content { + font-size: 0.9rem; +} +.sidenav .sidenav-footer .sidenav-footer-content .sidenav-footer-subtitle { + font-size: 0.75rem; +} +.sidenav .sidenav-footer .sidenav-footer-content .sidenav-footer-title { + font-weight: 500; +} + +.sidenav-dark { + background-color: #272f3b; + color: rgba(255, 255, 255, 0.5); +} +.sidenav-dark .sidenav-menu .sidenav-menu-heading { + color: rgba(255, 255, 255, 0.25); +} +.sidenav-dark .sidenav-menu .nav-link { + color: rgba(255, 255, 255, 0.5); +} +.sidenav-dark .sidenav-menu .nav-link .nav-link-icon { + color: rgba(255, 255, 255, 0.25); +} +.sidenav-dark .sidenav-menu .nav-link .sidenav-collapse-arrow { + color: rgba(255, 255, 255, 0.25); +} +.sidenav-dark .sidenav-menu .nav-link:hover { + color: #fff; +} +.sidenav-dark .sidenav-menu .nav-link.active { + color: #fff; +} +.sidenav-dark .sidenav-menu .nav-link.active .nav-link-icon { + color: #fff; +} +.sidenav-dark .sidenav-menu-nested { + border-left-color: rgba(255, 255, 255, 0.15); +} +.sidenav-dark .sidenav-footer { + background-color: rgba(0, 0, 0, 0.25); +} + +.sidenav-light { + background-color: #fff; + color: #212832; +} +.sidenav-light .sidenav-menu .sidenav-menu-heading { + color: #a7aeb8; +} +.sidenav-light .sidenav-menu .nav-link { + color: #212832; +} +.sidenav-light .sidenav-menu .nav-link .nav-link-icon { + color: #a7aeb8; +} +.sidenav-light .sidenav-menu .nav-link .sidenav-collapse-arrow { + color: #a7aeb8; +} +.sidenav-light .sidenav-menu .nav-link:hover { + color: #0061f2; +} +.sidenav-light .sidenav-menu .nav-link.active { + color: #0061f2; +} +.sidenav-light .sidenav-menu .nav-link.active .nav-link-icon { + color: #0061f2; +} +.sidenav-light .sidenav-menu-nested { + border-left-color: #d4dae3; +} +.sidenav-light .sidenav-footer { + background-color: rgba(33, 40, 50, 0.05); +} +.sidenav-light .sidenav-footer .sidenav-footer-subtitle { + color: #69707a; +} + +.page-header .page-header-content { + padding-top: 3rem; + padding-bottom: 3rem; +} +.page-header .page-header-content .page-header-title { + line-height: normal; + font-size: 2.25rem; + font-weight: 500; + display: flex; + align-items: center; + margin-bottom: 0; +} +.page-header .page-header-content .page-header-title .page-header-icon { + margin-right: 0.5rem; + display: inline-flex; +} +.page-header .page-header-content .page-header-title .page-header-icon .feather { + height: 1.75rem; + width: 1.75rem; +} +.page-header .page-header-content .page-header-subtitle { + font-size: 1.15rem; + margin-top: 0.25rem; +} +.page-header .page-header-search .input-group-joined { + border-color: transparent; +} +.page-header .page-header-search .input-group-joined .form-control, .page-header .page-header-search .input-group-joined .datatable-input { + height: 4rem; + font-size: 1.25rem; +} +.page-header .page-header-search .input-group-joined:focus-within { + box-shadow: 0 0 0 0.25rem rgba(0, 97, 242, 0.25); + border-color: transparent; +} + +.page-header-compact .page-header-content { + padding: 0; +} +.page-header-compact .page-header-content .page-header-title { + font-size: 1rem; +} +.page-header-compact .page-header-content .page-header-title .page-header-icon .feather { + height: 1rem; + width: 1rem; +} + +.page-header.page-header-dark { + color: rgba(255, 255, 255, 0.5); +} +.page-header.page-header-dark .page-header-title { + color: #fff; +} +.page-header.page-header-dark .page-header-title .page-header-icon { + color: rgba(255, 255, 255, 0.5); +} +.page-header.page-header-dark .page-header-subtitle { + color: rgba(255, 255, 255, 0.5); +} +.page-header.page-header-dark .breadcrumb { + background-color: rgba(0, 0, 0, 0.15); + box-shadow: 0 0.15rem 1.75rem 0 rgba(33, 40, 50, 0.15); +} +.page-header.page-header-dark .breadcrumb .breadcrumb-item, +.page-header.page-header-dark .breadcrumb .breadcrumb-item + .breadcrumb-item::before { + color: rgba(255, 255, 255, 0.35); +} +.page-header.page-header-dark .breadcrumb .breadcrumb-item a { + color: rgba(255, 255, 255, 0.6); +} +.page-header.page-header-dark .page-header-search .input-group-joined:focus-within { + box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.5); + border-color: transparent; +} + +.page-header.page-header-light { + color: rgba(33, 40, 50, 0.5); +} +.page-header.page-header-light .page-header-title { + color: #212832; +} +.page-header.page-header-light .page-header-title .page-header-icon { + color: rgba(33, 40, 50, 0.5); +} +.page-header.page-header-light .page-header-subtitle { + color: rgba(33, 40, 50, 0.5); +} +.page-header.page-header-light .breadcrumb { + background-color: rgba(0, 0, 0, 0.05); +} +.page-header.page-header-light .breadcrumb .breadcrumb-item, +.page-header.page-header-light .breadcrumb .breadcrumb-item + .breadcrumb-item::before { + color: #69707a; +} +.page-header.page-header-light .breadcrumb .breadcrumb-item a { + color: #0061f2; +} + +.img-account-profile { + height: 10rem; +} + +.cc-color-visa { + color: #1a1f71; +} + +.cc-color-mastercard { + color: #cc0000; +} + +.cc-color-amex { + color: #002663; +} + +.table-billing-history { + font-size: 0.85rem; +} +.table-billing-history thead th { + border-top: none; +} +.table-billing-history th, +.table-billing-history td { + padding-top: 0.75rem; + padding-bottom: 0.75rem; + padding-left: 1.375rem; + padding-right: 1.375rem; +} + +.icons-org-create { + display: inline-flex; + align-items: center; + position: relative; +} +.icons-org-create .icon-users { + height: 4rem; + width: 4rem; +} +.icons-org-create .icon-users circle, +.icons-org-create .icon-users path:first-of-type { + color: #0061f2; +} +.icons-org-create .icon-users path { + color: rgba(0, 97, 242, 0.35); +} +.icons-org-create .icon-plus { + color: #0061f2; + position: absolute; + font-size: 1.5rem; + top: -0.5rem; + right: -0.75rem; +} + +.icons-org-join { + display: inline-flex; + position: relative; +} +.icons-org-join .icon-user { + height: 4rem; + width: 4rem; + color: #6900c7; +} +.icons-org-join .icon-arrow { + font-size: 2rem; + margin: 1rem 0.5rem 1rem 0; + color: #6900c7; +} +.icons-org-join .icon-users { + margin: 0.5rem 0; + height: 3rem; + width: 3rem; +} +.icons-org-join .icon-users circle, +.icons-org-join .icon-users path:first-of-type { + color: rgba(105, 0, 199, 0.5); +} +.icons-org-join .icon-users path { + color: rgba(105, 0, 199, 0.25); +} + +.org-or-divider { + display: flex; + position: relative; + width: 100%; + justify-content: center; + border-bottom: 1px solid #e0e5ec; +} +.org-or-divider .org-or { + height: 2rem; + width: 2rem; + position: absolute; + top: -1rem; + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto; + background-color: #fff; + border-radius: 100%; + border: 1px solid #e0e5ec; + font-size: 80%; + color: #6900c7; +} + +.invoice .invoice-brand-img { + height: 5rem; + width: 5rem; +} +.invoice .table tbody tr td, .invoice .datatable-table tbody tr td { + padding-top: 1.5rem; + padding-bottom: 1.5rem; +} + +@media (min-width: 992px) { + .pricing-detailed .pricing-detailed-behind { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } +} + +.pricing-columns .pricing-columns-price { + font-size: 2rem; + color: #212832; +} +.pricing-columns .pricing-columns-price span { + font-weight: normal; + font-size: 1rem; + color: #69707a; +} +.pricing-columns .list-group-flush .list-group-item { + display: flex; + align-items: center; +} + +.nav-wizard .nav-link { + display: flex; + align-items: center; + padding: 2rem; +} +.nav-wizard .nav-link .wizard-step-icon { + display: inline-flex; + align-items: center; + justify-content: center; + height: 2.5rem; + width: 2.5rem; + flex-shrink: 0; + margin-right: 1rem; + border-radius: 0.35rem; + background-color: #0061f2; + color: white; +} +.nav-wizard .nav-link .wizard-step-icon i, +.nav-wizard .nav-link .wizard-step-icon svg, +.nav-wizard .nav-link .wizard-step-icon .feather { + color: white; +} +.nav-wizard .nav-link .wizard-step-text { + line-height: 1; + text-align: left; +} +.nav-wizard .nav-link .wizard-step-text .wizard-step-text-name { + font-size: 1rem; + margin-bottom: 0.25rem; + color: #0061f2; +} +.nav-wizard .nav-link .wizard-step-text .wizard-step-text-details { + font-weight: 400; + font-size: 0.875rem; + color: #69707a; +} +.nav-wizard .nav-link.active .wizard-step-icon { + background-color: #fff; + color: #0061f2; +} +.nav-wizard .nav-link.active .wizard-step-icon i, +.nav-wizard .nav-link.active .wizard-step-icon svg, +.nav-wizard .nav-link.active .wizard-step-icon .feather { + color: #0061f2; +} +.nav-wizard .nav-link.active .wizard-step-text .wizard-step-text-name { + color: #fff; +} +.nav-wizard .nav-link.active .wizard-step-text .wizard-step-text-details { + color: rgba(255, 255, 255, 0.5); +} + +:root { + --litepicker-month-header-color: #4a515b; + --litepicker-button-prev-month-color: #69707a; + --litepicker-button-next-month-color: #69707a; + --litepicker-button-prev-month-color-hover: #212832; + --litepicker-button-next-month-color-hover: #212832; + --litepicker-month-weekday-color: #69707a; + --litepicker-month-week-number-color: #69707a; + --litepicker-day-width: 34px; + --litepicker-day-color: #363d47; + --litepicker-day-color-hover: #0061f2; + --litepicker-is-today-color: #69707a; + --litepicker-is-in-range-color: rgba(0, 97, 242, 0.15); + --litepicker-is-start-color: #fff; + --litepicker-is-start-color-bg: #0061f2; + --litepicker-is-end-color: #fff; + --litepicker-is-end-color-bg: #0061f2; + --litepicker-button-apply-color-bg: #0061f2; + --litepicker-button-reset-color-hover: #0061f2; + --litepicker-highlighted-day-color: #363d47; + --litepicker-highlighted-day-color-bg: rgba(0, 97, 242, 0.15); +} + +.show-week-numbers { + --litepicker-month-width: calc(var(--litepicker-day-width) * 8); +} + +.litepicker { + font-family: "Metropolis", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !important; + font-size: 0.875rem !important; +} +.litepicker .container__months { + box-shadow: none !important; + border-radius: 0.25rem !important; +} +@media (max-width: 709px) { + .litepicker .container__months.columns-2 { + width: calc(var(--litepicker-month-width) + 10px) !important; + } +} +.litepicker .container__months .month-item-header { + font-weight: normal !important; + padding-top: 0.5rem !important; + padding-bottom: 0.75rem !important; + color: var(--litepicker-month-header-color) !important; +} +.litepicker .container__months .month-item-header div > .month-item-name { + margin-right: 0.25rem !important; + font-weight: 500 !important; +} +.litepicker .container__months .month-item-header div > .month-item-year { + font-weight: 500 !important; +} +.litepicker .container__months .month-item-header .button-previous-month, +.litepicker .container__months .month-item-header .button-next-month { + transition: none !important; + cursor: pointer !important; +} +.litepicker .container__months .month-item-header .button-previous-month > svg, +.litepicker .container__months .month-item-header .button-previous-month > img, +.litepicker .container__months .month-item-header .button-next-month > svg, +.litepicker .container__months .month-item-header .button-next-month > img { + transform: scale(0.75); +} +.litepicker .container__months .month-item-header .button-previous-month { + color: var(--litepicker-button-prev-month-color) !important; +} +.litepicker .container__months .month-item-header .button-previous-month > svg, +.litepicker .container__months .month-item-header .button-previous-month > img { + fill: var(--litepicker-button-prev-month-color) !important; +} +.litepicker .container__months .month-item-header .button-previous-month:hover { + color: var(--litepicker-button-prev-month-color-hover) !important; +} +.litepicker .container__months .month-item-header .button-previous-month:hover > svg { + fill: var(--litepicker-button-prev-month-color-hover) !important; +} +.litepicker .container__months .month-item-header .button-next-month { + color: var(--litepicker-button-next-month-color) !important; +} +.litepicker .container__months .month-item-header .button-next-month > svg, +.litepicker .container__months .month-item-header .button-next-month > img { + fill: var(--litepicker-button-next-month-color) !important; +} +.litepicker .container__months .month-item-header .button-next-month:hover { + color: var(--litepicker-button-next-month-color-hover) !important; +} +.litepicker .container__months .month-item-header .button-next-month:hover > svg { + fill: var(--litepicker-button-next-month-color-hover) !important; +} +.litepicker .container__months .month-item-weekdays-row { + color: var(--litepicker-month-weekday-color) !important; +} +.litepicker .container__days > div, +.litepicker .container__days > a { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0 !important; + margin: 0; + width: var(--litepicker-day-width) !important; + height: var(--litepicker-day-width) !important; +} +.litepicker .container__days .day-item { + color: var(--litepicker-day-color) !important; + border-radius: 100% !important; + transition: none !important; + cursor: pointer !important; +} +.litepicker .container__days .day-item:hover { + color: var(--litepicker-day-color-hover) !important; + box-shadow: inset 0 0 0 1px var(--litepicker-day-color-hover) !important; +} +.litepicker .container__days .day-item.is-today { + box-shadow: inset 0 0 0 1px #69707a; + color: var(--litepicker-is-today-color) !important; +} +.litepicker .container__days .day-item.is-in-range { + position: relative; + background-color: transparent !important; +} +.litepicker .container__days .day-item.is-in-range:after { + content: ""; + display: block; + height: 100%; + width: 100%; + position: absolute; + background-color: var(--litepicker-is-in-range-color); +} +.litepicker .container__days .day-item.is-start-date { + color: var(--litepicker-is-start-color) !important; + background-color: var(--litepicker-is-start-color-bg) !important; + position: relative; +} +.litepicker .container__days .day-item.is-start-date:after { + content: ""; + display: block; + height: 100%; + width: 50%; + position: absolute; + left: auto; + right: 0; + background-color: var(--litepicker-is-in-range-color); +} +.litepicker .container__days .day-item.is-start-date.is-flipped:after { + right: auto; + left: 0; +} +.litepicker .container__days .day-item.is-end-date { + color: var(--litepicker-is-end-color) !important; + background-color: var(--litepicker-is-end-color-bg) !important; + position: relative; +} +.litepicker .container__days .day-item.is-end-date:after { + content: ""; + display: block; + height: 100%; + width: 50%; + position: absolute; + left: 0; + right: auto; + background-color: var(--litepicker-is-in-range-color); +} +.litepicker .container__days .day-item.is-end-date.is-flipped:after { + right: 0; + left: auto; +} +.litepicker .container__days .day-item.is-start-date.is-end-date:after { + display: none; +} +.litepicker .container__days .day-item.is-highlighted { + color: var(--litepicker-highlighted-day-color) !important; + background-color: var(--litepicker-highlighted-day-color-bg) !important; +} +.litepicker[data-plugins=ranges] .container__main { + margin-top: 0.25rem; + box-shadow: 0 0.15rem 1.75rem 0 rgba(33, 40, 50, 0.15); + overflow: hidden; + border-radius: 0.35rem; +} +.litepicker[data-plugins=ranges] .container__main .container__predefined-ranges { + box-shadow: none !important; + border-radius: 0.35rem !important; + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important; + padding-top: 0.5rem; + border-right: 1px solid #e0e5ec; +} +.litepicker[data-plugins=ranges] .container__main .container__predefined-ranges button { + cursor: pointer !important; +} +.litepicker[data-plugins=ranges] .container__main .container__months { + border-top-left-radius: 0 !important; + border-bottom-left-radius: 0 !important; +} + +.chart-area { + position: relative; + height: 10rem; + width: 100%; +} +@media (min-width: 768px) { + .chart-area { + height: 15rem; + } +} + +.chart-bar { + position: relative; + height: 10rem; + width: 100%; +} +@media (min-width: 768px) { + .chart-bar { + height: 15rem; + } +} + +.chart-pie { + position: relative; + height: 15rem; + width: 100%; +} +@media (min-width: 768px) { + .chart-pie { + height: 15rem; + } +} + +.datatable-wrapper .datatable-container { + font-size: 0.875rem; +} + +.datatable-wrapper.no-header .datatable-container { + border-top: none; +} + +.datatable-wrapper.no-footer .datatable-container { + border-bottom: none; +} + +.datatable-top { + padding: 0 0 1rem; +} + +.datatable-bottom { + padding: 0; +} + +.datatable-top > nav:first-child, +.datatable-top > div:first-child, +.datatable-bottom > nav:first-child, +.datatable-bottom > div:first-child { + float: left; +} + +.datatable-top > nav:last-child, +.datatable-top > div:last-child, +.datatable-bottom > nav:last-child, +.datatable-bottom > div:last-child { + float: right; +} + +.datatable-selector { + width: auto; + display: inline-block; + padding-left: 1.125rem; + padding-right: 2.125rem; + margin-right: 0.25rem; +} + +.datatable-info { + margin: 7px 0; +} + +/* PAGER */ +.datatable-pagination a:hover { + background-color: #e0e5ec; +} + +.datatable-pagination .datatable-active a, +.datatable-pagination .datatable-active a:focus, +.datatable-pagination .datatable-active a:hover { + color: #fff; + background-color: #0061f2; +} + +.datatable-pagination li.datatable-hidden { + visibility: visible; +} + +.datatable-pagination .ellipsis a, +.datatable-pagination .disabled a, +.datatable-pagination .disabled a:focus, +.datatable-pagination .disabled a:hover { + cursor: not-allowed; +} + +.datatable-pagination .disabled a, +.datatable-pagination .disabled a:focus, +.datatable-pagination .disabled a:hover { + cursor: not-allowed; + opacity: 0.4; +} + +.datatable-pagination .pager a { + font-weight: bold; +} + +/* TABLE */ +.datatable-table { + border-collapse: collapse; +} + +.datatable-table > tbody > tr > td, +.datatable-table > tbody > tr > th, +.datatable-table > tfoot > tr > td, +.datatable-table > tfoot > tr > th, +.datatable-table > thead > tr > td, +.datatable-table > thead > tr > th { + vertical-align: middle; + padding: 0.75rem 0.75rem; +} + +.datatable-table > thead > tr > th { + vertical-align: bottom; + text-align: left; + border-bottom: none; +} + +.datatable-table > tfoot > tr > th { + vertical-align: bottom; + text-align: left; +} + +.datatable-table th { + vertical-align: bottom; + text-align: left; +} + +.datatable-table th a { + text-decoration: none; + color: inherit; +} + +.datatable-sorter { + display: inline-block; + height: 100%; + position: relative; + width: 100%; + padding-right: 1rem; +} + +.datatable-sorter::before, +.datatable-sorter::after { + content: ""; + height: 0; + width: 0; + position: absolute; + right: 4px; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + opacity: 0.2; +} + +.datatable-sorter::before { + bottom: 4px; +} + +.datatable-sorter::after { + top: 0px; +} + +.asc .datatable-sorter::after, +.desc .datatable-sorter::before { + opacity: 0.6; +} + +.datatables-empty { + text-align: center; +} + +.datatable-top::after, +.datatable-bottom::after { + clear: both; + content: " "; + display: table; +} + +.btn-datatable { + height: 20px !important; + width: 20px !important; + font-size: 0.75rem; + border-radius: 0.35rem !important; +} + +.sbp-dropdown-example .dropdown-menu { + display: inline-block; + position: relative; + float: none; + max-width: 15rem; +} + +.sbp-preview { + border-radius: 0.35rem; + border: 0.25rem solid #e0e5ec; + border-style: solid; +} +.sbp-preview .sbp-preview-content { + padding: 1.5rem; + border-bottom: 1px solid #e0e5ec; + position: relative; +} +.sbp-preview .sbp-preview-code { + background-color: #f2f6fc; + padding: 1.5rem; + border-bottom: 1px solid #e0e5ec; +} +.sbp-preview .sbp-preview-code .nav-tabs { + border-bottom-color: transparent; + font-size: 0.75rem; + font-weight: 500; +} +.sbp-preview .sbp-preview-code .nav-tabs .nav-item .nav-link { + border-bottom: 0; + display: inline-flex; + align-items: center; +} +.sbp-preview .sbp-preview-code .nav-tabs .nav-item .nav-link.active { + border-color: transparent; + background-color: #2f2f2f; + color: white; +} +.sbp-preview .sbp-preview-code .nav-tabs .nav-item .nav-link .img-pug { + height: 1em; + padding: 1px 0; +} +.sbp-preview .sbp-preview-text { + background-color: #f2f6fc; + font-size: 0.875rem; + padding: 1.5rem; +} + +code[class*=language-], +pre[class*=language-] { + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + color: #eee; + background: #2f2f2f; + font-family: "SFMono-Regular", "Consolas", "Liberation Mono", "Menlo", monospace; + font-size: 0.875rem; + line-height: 1.5em; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + hyphens: none; +} + +code[class*=language-]::-moz-selection, +pre[class*=language-]::-moz-selection, +code[class*=language-] ::-moz-selection, +pre[class*=language-] ::-moz-selection { + background: #363636; +} + +code[class*=language-]::-moz-selection, pre[class*=language-]::-moz-selection, code[class*=language-] ::-moz-selection, pre[class*=language-] ::-moz-selection { + background: #363636; +} + +code[class*=language-]::selection, +pre[class*=language-]::selection, +code[class*=language-] ::selection, +pre[class*=language-] ::selection { + background: #363636; +} + +:not(pre) > code[class*=language-] { + white-space: normal; + border-radius: 0.2em; + padding: 0.1em; +} + +pre[class*=language-] { + overflow: auto; + position: relative; + margin: 0; + padding: 1rem; + max-height: 35rem; +} + +.language-css > code, +.language-sass > code, +.language-scss > code { + color: #fd9170; +} + +[class*=language-] .namespace { + opacity: 0.7; +} + +.token.atrule { + color: #c792ea; +} + +.token.attr-name { + color: #ffcb6b; +} + +.token.attr-value { + color: #a5e844; +} + +.token.attribute { + color: #a5e844; +} + +.token.boolean { + color: #c792ea; +} + +.token.builtin { + color: #ffcb6b; +} + +.token.cdata { + color: #80cbc4; +} + +.token.char { + color: #80cbc4; +} + +.token.class { + color: #ffcb6b; +} + +.token.class-name { + color: #f2ff00; +} + +.token.comment { + color: #616161; +} + +.token.constant { + color: #c792ea; +} + +.token.deleted { + color: #ff6666; +} + +.token.doctype { + color: #616161; +} + +.token.entity { + color: #ff6666; +} + +.token.function { + color: #c792ea; +} + +.token.hexcode { + color: #f2ff00; +} + +.token.id { + color: #c792ea; + font-weight: bold; +} + +.token.important { + color: #c792ea; + font-weight: bold; +} + +.token.inserted { + color: #80cbc4; +} + +.token.keyword { + color: #c792ea; +} + +.token.number { + color: #fd9170; +} + +.token.operator { + color: #89ddff; +} + +.token.prolog { + color: #616161; +} + +.token.property { + color: #80cbc4; +} + +.token.pseudo-class { + color: #a5e844; +} + +.token.pseudo-element { + color: #a5e844; +} + +.token.punctuation { + color: #89ddff; +} + +.token.regex { + color: #f2ff00; +} + +.token.selector { + color: #ff6666; +} + +.token.string { + color: #a5e844; +} + +.token.symbol { + color: #c792ea; +} + +.token.tag { + color: #ff6666; +} + +.token.unit { + color: #fd9170; +} + +.token.url { + color: #ff6666; +} + +.token.variable { + color: #ff6666; +} \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..e69de29 diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..ee8f07e --- /dev/null +++ b/public/index.php @@ -0,0 +1,20 @@ +handleRequest(Request::capture()); diff --git a/public/js/custom.js b/public/js/custom.js new file mode 100644 index 0000000..dc5cea4 --- /dev/null +++ b/public/js/custom.js @@ -0,0 +1,38 @@ +$(document).ready(function() { + $('.rmv-custom-alert-container').on( "click", function() { + $('.custom-alert-container').remove(); + }); + + $('input.datepicker, input[type="date"]').each(function () { + const input = $(this); + const value = input.val() || input.attr('value') || ''; + const isoDate = /^(\d{4})-(\d{2})-(\d{2})/.exec(value); + + input.attr('type', 'text').addClass('datepicker'); + + if (isoDate) { + input.val(`${isoDate[3]}/${isoDate[2]}/${isoDate[1]}`); + } else { + input.val(value); + } + + if (typeof $.fn.datepicker !== 'undefined') { + input.datepicker({ + dateFormat: 'dd/mm/yy', + changeMonth: true, + changeYear: true + }); + } + }); + + $('form').on('submit', function () { + $(this).find('input.datepicker').each(function () { + const input = $(this); + const date = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(input.val()); + + if (date) { + input.val(`${date[3]}-${date[2]}-${date[1]}`); + } + }); + }); +}); diff --git a/public/js/datatables/datatables-simple-demo.js b/public/js/datatables/datatables-simple-demo.js new file mode 100644 index 0000000..c02639b --- /dev/null +++ b/public/js/datatables/datatables-simple-demo.js @@ -0,0 +1,9 @@ +window.addEventListener('DOMContentLoaded', event => { + // Simple-DataTables + // https://github.com/fiduswriter/Simple-DataTables/wiki + + const datatablesSimple = document.getElementById('datatablesSimple'); + if (datatablesSimple) { + new simpleDatatables.DataTable(datatablesSimple); + } +}); diff --git a/public/js/litepicker.js b/public/js/litepicker.js new file mode 100644 index 0000000..412e5cc --- /dev/null +++ b/public/js/litepicker.js @@ -0,0 +1,56 @@ +// Litepicker +// +// The date pickers in Material Admin Pro +// are powered by the Litepicker plugin. +// Litepicker is a lightweight, no dependencies +// date picker that allows for date ranges +// and other options. For more usage details +// visit the Litepicker docs. +// +// Litepicker Documentation +// https://wakirin.github.io/Litepicker + +window.addEventListener('DOMContentLoaded', event => { + + const litepickerSingleDate = document.getElementById('litepickerSingleDate'); + if (litepickerSingleDate) { + new Litepicker({ + element: litepickerSingleDate, + format: 'MMM DD, YYYY' + }); + } + + const litepickerDateRange = document.getElementById('litepickerDateRange'); + if (litepickerDateRange) { + new Litepicker({ + element: litepickerDateRange, + singleMode: false, + format: 'MMM DD, YYYY' + }); + } + + const litepickerDateRange2Months = document.getElementById('litepickerDateRange2Months'); + if (litepickerDateRange2Months) { + new Litepicker({ + element: litepickerDateRange2Months, + singleMode: false, + numberOfMonths: 2, + numberOfColumns: 2, + format: 'MMM DD, YYYY' + }); + } + + const litepickerRangePlugin = document.getElementById('litepickerRangePlugin'); + if (litepickerRangePlugin) { + new Litepicker({ + element: litepickerRangePlugin, + startDate: new Date(), + endDate: new Date(), + singleMode: false, + numberOfMonths: 2, + numberOfColumns: 2, + format: 'MMM DD, YYYY', + plugins: ['ranges'] + }); + } +}); diff --git a/public/js/markdown.js b/public/js/markdown.js new file mode 100644 index 0000000..7c0ecc5 --- /dev/null +++ b/public/js/markdown.js @@ -0,0 +1,4 @@ +var easyMDE = new EasyMDE({ + element: document.getElementById('postEditor'), + toolbar: ['bold', 'italic', 'heading', '|', 'quote', 'unordered-list', 'ordered-list', '|', 'link', 'image', '|', 'preview', 'guide'] +}); diff --git a/public/js/scripts.js b/public/js/scripts.js new file mode 100644 index 0000000..4edc8ad --- /dev/null +++ b/public/js/scripts.js @@ -0,0 +1,78 @@ +/*! + * Start Bootstrap - SB Admin Pro v2.0.5 (https://shop.startbootstrap.com/product/sb-admin-pro) + * Copyright 2013-2023 Start Bootstrap + * Licensed under SEE_LICENSE (https://github.com/StartBootstrap/sb-admin-pro/blob/master/LICENSE) + */ + +window.onload = function () { + // Activate feather + feather.replace(); + + // Enable tooltips globally + var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); + var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { + return new bootstrap.Tooltip(tooltipTriggerEl); + }); + + // Enable popovers globally + var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]')); + var popoverList = popoverTriggerList.map(function (popoverTriggerEl) { + return new bootstrap.Popover(popoverTriggerEl); + }); + + // Toggle the side navigation + const sidebarToggle = document.body.querySelector('#sidebarToggle'); + + if (sidebarToggle) { + // Uncomment Below to persist sidebar toggle between refreshes + // if (localStorage.getItem('sb|sidebar-toggle') === 'true') { + // document.body.classList.toggle('sidenav-toggled'); + // } + sidebarToggle.addEventListener('click', event => { + event.preventDefault(); + document.body.classList.toggle('sidenav-toggled'); + localStorage.setItem('sb|sidebar-toggle', document.body.classList.contains('sidenav-toggled')); + }); + } + + // Close side navigation when width < LG + const sidenavContent = document.body.querySelector('#layoutSidenav_content'); + if (sidenavContent) { + sidenavContent.addEventListener('click', event => { + const BOOTSTRAP_LG_WIDTH = 992; + if (window.innerWidth >= 992) { + return; + } + if (document.body.classList.contains("sidenav-toggled")) { + document.body.classList.toggle("sidenav-toggled"); + } + }); + } + + // Add active state to sidbar nav links + let activatedPath = window.location.pathname.match(/([\w-]+\.html)/, '$1'); + + if (activatedPath) { + activatedPath = activatedPath[0]; + } else { + activatedPath = 'index.html'; + } + + const targetAnchors = document.body.querySelectorAll('[href="' + activatedPath + '"].nav-link'); + + targetAnchors.forEach(targetAnchor => { + let parentNode = targetAnchor.parentNode; + while (parentNode !== null && parentNode !== document.documentElement) { + if (parentNode.classList.contains('collapse')) { + parentNode.classList.add('show'); + const parentNavLink = document.body.querySelector( + '[data-bs-target="#' + parentNode.id + '"]' + ); + parentNavLink.classList.remove('collapsed'); + parentNavLink.classList.add('active'); + } + parentNode = parentNode.parentNode; + } + targetAnchor.classList.add('active'); + }); +}; diff --git a/public/js/toasts.js b/public/js/toasts.js new file mode 100644 index 0000000..79d3dbe --- /dev/null +++ b/public/js/toasts.js @@ -0,0 +1,26 @@ +// For more details see: https://getbootstrap.com/docs/5.0/components/toasts/#usage + +window.addEventListener('DOMContentLoaded', event => { + + const toastBasicEl = document.getElementById('toastBasic'); + const toastNoAutohideEl = document.getElementById('toastNoAutohide'); + + const toastBasic = new bootstrap.Toast(toastBasicEl); + const toastNoAutohide = new bootstrap.Toast(toastNoAutohideEl); + + const toastBasicTrigger = document.getElementById('toastBasicTrigger'); + if (toastBasicTrigger) { + toastBasicTrigger.addEventListener('click', event => { + console.log('asd'); + toastBasic.show(); + }); + } + + const toastNoAutohideTrigger = document.getElementById('toastNoAutohideTrigger'); + if (toastNoAutohideTrigger) { + toastNoAutohideTrigger.addEventListener('click', event => { + toastNoAutohide.show(); + }); + } + +}) diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..eb05362 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/resources/css/analytal_index.css b/resources/css/analytal_index.css new file mode 100644 index 0000000..000123d --- /dev/null +++ b/resources/css/analytal_index.css @@ -0,0 +1,79 @@ +:root { + --primary-gradient: linear-gradient(135deg, #4361ee 0%, #3a0ca3 100%); + --surface-color: #ffffff; + --text-main: #2b3445; + --text-muted: #7d879c; + } + + body { background-color: #f6f9fc; color: var(--text-main); font-family: 'Inter', sans-serif; } + + /* Cards KPI - Refinamento de Elevação */ + .stat-card { + border: none; + border-radius: 20px; + background: var(--surface-color); + box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.02); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + border: 1px solid rgba(0,0,0,0.03); + } + + .stat-card:hover { + transform: translateY(-5px); + box-shadow: 0px 12px 24px rgba(67, 97, 238, 0.12); + } + + /* Ícones com Gradientes */ + .icon-box { + width: 52px; + height: 52px; + border-radius: 14px; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.3rem; + transition: transform 0.2s; + } + + .bg-blue-soft { background: linear-gradient(135deg, #e7f0ff 0%, #d0e1ff 100%); color: #4361ee; } + .bg-green-soft { background: linear-gradient(135deg, #e6f9f7 0%, #c4f2ed 100%); color: #2ec4b6; } + .bg-dark-soft { background: linear-gradient(135deg, #f1f3f5 0%, #e9ecef 100%); color: #495057; } + + /* Filtros Modernizados */ + .filter-section { + border-radius: 20px; + background: rgba(255, 255, 255, 0.8); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.5) !important; + } + + .input-group-text { + background-color: transparent; + border-right: none; + color: var(--text-muted); + font-weight: 500; + } + + .form-control { + border-radius: 10px; + padding: 0.6rem 1rem; + border: 1px solid #e3e9ef; + } + + .form-control:focus { + box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1); + border-color: #4361ee; + } + + /* Botão Primário Estilo SaaS */ + .btn-primary { + background: var(--primary-gradient); + border: none; + font-weight: 600; + padding: 0.6rem 1.5rem; + border-radius: 12px; + box-shadow: 0 4px 14px 0 rgba(67, 97, 238, 0.3); + } + + /* Gráficos */ + .chart-container { min-height: 350px; } + .card-title { font-size: 1.1rem; letter-spacing: -0.02em; } diff --git a/resources/css/app.css b/resources/css/app.css new file mode 100644 index 0000000..2243c60 --- /dev/null +++ b/resources/css/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; +@source '../../storage/framework/views/*.php'; +@source "../**/*.blade.php"; +@source "../**/*.js"; +@source "../**/*.vue"; + +@theme { + --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol', 'Noto Color Emoji'; +} diff --git a/resources/js/app.js b/resources/js/app.js new file mode 100644 index 0000000..e59d6a0 --- /dev/null +++ b/resources/js/app.js @@ -0,0 +1 @@ +import './bootstrap'; diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js new file mode 100644 index 0000000..46f7a33 --- /dev/null +++ b/resources/js/bootstrap.js @@ -0,0 +1,34 @@ +import 'bootstrap'; + +/** + * We'll load the axios HTTP library which allows us to easily issue requests + * to our Laravel back-end. This library automatically handles sending the + * CSRF token as a header based on the value of the "XSRF" token cookie. + */ + +import axios from 'axios'; +window.axios = axios; + +window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; + +/** + * Echo exposes an expressive API for subscribing to channels and listening + * for events that are broadcast by Laravel. Echo and event broadcasting + * allows your team to easily build robust real-time web applications. + */ + +// import Echo from 'laravel-echo'; + +// import Pusher from 'pusher-js'; +// window.Pusher = Pusher; + +// window.Echo = new Echo({ +// broadcaster: 'pusher', +// key: import.meta.env.VITE_PUSHER_APP_KEY, +// cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1', +// wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`, +// wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80, +// wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443, +// forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https', +// enabledTransports: ['ws', 'wss'], +// }); diff --git a/resources/lang/pt/attributes.php b/resources/lang/pt/attributes.php new file mode 100644 index 0000000..411c42e --- /dev/null +++ b/resources/lang/pt/attributes.php @@ -0,0 +1,46 @@ + 'nome', + 'tax_number' => 'NIF', + 'email' => 'e-mail', + 'phone' => 'telefone', + 'address' => 'morada', + 'contact_info' => 'informações de contacto', + 'notes' => 'notas', + 'client_type_id' => 'tipo de cliente', + 'seller_id' => 'vendedor', + 'locality' => 'localidade', + 'client_id' => 'cliente', + 'contract_value' => 'valor do contrato', + 'commission_value' => 'valor da comissão', + 'profit_value' => 'lucro', + 'supply_type' => 'tipo de fornecimento', + 'supply_address' => 'endereço de fornecimento', + 'annual_consumption' => 'consumo anual', + 'code' => 'código', + 'contract_type_id' => 'tipo de contrato', + 'validity' => 'validade', + 'contract_end_date' => 'data de fim do contrato', + 'contract_date' => 'data do contrato', + 'activation_date' => 'data de ativação', + 'status_id' => 'estado do contrato', + 'commission_rate' => 'percentagem da comissão', + 'power_tier_id' => 'escalão de potência', + 'payment_method_id' => 'método de pagamento', + 'delivery_method' => 'método de envio', + 'delivery_email' => 'e-mail de envio', + 'previous_supplier_id' => 'fornecedor anterior', + 'new_supplier_id' => 'novo fornecedor', + 'typology_id' => 'tipologia', + 'cui_tier_id' => 'escalão CUI', + 'paid' => 'pago', + 'chargeback' => 'chargeback', + 'chargeback_value' => 'valor do chargeback', + 'chargeback_date' => 'data de chargeback', + 'next_due_date' => 'próxima renovação', + 'renewal_type' => 'tipo de renovação', + 'lead_status_id' => 'estado do lead', + 'contact_date' => 'data de contacto', + 'contract_type' => 'tipo de contrato', +]; diff --git a/resources/lang/pt/validation.php b/resources/lang/pt/validation.php new file mode 100644 index 0000000..0e6a31d --- /dev/null +++ b/resources/lang/pt/validation.php @@ -0,0 +1,350 @@ + 'O campo :attribute deve ser aceite.', + 'accepted_if' => 'O campo :attribute deve ser aceite quando :other é :value.', + 'active_url' => 'O campo :attribute não é uma URL válida.', + 'after' => 'O campo :attribute deve ser uma data posterior a :date.', + 'after_or_equal' => 'O campo :attribute deve ser uma data posterior ou igual a :date.', + 'alpha' => 'O campo :attribute deve conter apenas letras.', + 'alpha_dash' => 'O campo :attribute pode conter apenas letras, números, traços e underscores.', + 'alpha_num' => 'O campo :attribute deve conter apenas letras e números.', + 'array' => 'O campo :attribute deve ser uma lista.', + 'before' => 'O campo :attribute deve ser uma data anterior a :date.', + 'before_or_equal' => 'O campo :attribute deve ser uma data anterior ou igual a :date.', + 'between' => [ + 'array' => 'O campo :attribute deve ter entre :min e :max itens.', + 'file' => 'O campo :attribute deve ter entre :min e :max kilobytes.', + 'numeric' => 'O campo :attribute deve estar entre :min e :max.', + 'string' => 'O campo :attribute deve ter entre :min e :max caracteres.', + ], + 'boolean' => 'O campo :attribute deve ser verdadeiro ou falso.', + 'confirmed' => 'A confirmação de :attribute não corresponde.', + 'current_password' => 'A palavra-passe atual está incorreta.', + 'date' => 'O campo :attribute deve ser uma data válida.', + 'date_equals' => 'O campo :attribute deve ser uma data igual a :date.', + 'date_format' => 'O campo :attribute deve estar no formato :format.', + 'declined' => 'O campo :attribute deve ser recusado.', + 'declined_if' => 'O campo :attribute deve ser recusado quando :other for :value.', + 'different' => 'O campo :attribute e :other devem ser diferentes.', + 'digits' => 'O campo :attribute deve ter :digits dígitos.', + 'digits_between' => 'O campo :attribute deve ter entre :min e :max dígitos.', + 'email' => 'O campo :attribute deve conter um e-mail válido.', + 'ends_with' => 'O campo :attribute deve terminar com: :values.', + 'exists' => 'O :attribute selecionado não é válido.', + 'file' => 'O campo :attribute deve ser um ficheiro.', + 'filled' => 'O campo :attribute é obrigatório.', + 'gt' => [ + 'array' => 'O campo :attribute deve ter mais de :value itens.', + 'file' => 'O campo :attribute deve ser maior do que :value kilobytes.', + 'numeric' => 'O campo :attribute deve ser maior do que :value.', + 'string' => 'O campo :attribute deve ter mais de :value caracteres.', + ], + 'gte' => [ + 'array' => 'O campo :attribute deve ter :value itens ou mais.', + 'file' => 'O campo :attribute deve ter :value kilobytes ou mais.', + 'numeric' => 'O campo :attribute deve ser maior ou igual a :value.', + 'string' => 'O campo :attribute deve ter :value caracteres ou mais.', + ], + 'image' => 'O campo :attribute deve ser uma imagem.', + 'in' => 'O campo :attribute selecionado não é válido.', + 'in_array' => 'O campo :attribute não existe em :other.', + 'integer' => 'O campo :attribute deve ser um número inteiro.', + 'ip' => 'O campo :attribute deve ser um endereço IP válido.', + 'ipv4' => 'O campo :attribute deve ser um endereço IPv4 válido.', + 'ipv6' => 'O campo :attribute deve ser um endereço IPv6 válido.', + 'json' => 'O campo :attribute deve conter JSON válido.', + 'lt' => [ + 'array' => 'O campo :attribute deve ter menos de :value itens.', + 'file' => 'O campo :attribute deve ser inferior a :value kilobytes.', + 'numeric' => 'O campo :attribute deve ser inferior a :value.', + 'string' => 'O campo :attribute deve ter menos de :value caracteres.', + ], + 'lte' => [ + 'array' => 'O campo :attribute deve ter :value itens ou menos.', + 'file' => 'O campo :attribute deve ter :value kilobytes ou menos.', + 'numeric' => 'O campo :attribute deve ser menor ou igual a :value.', + 'string' => 'O campo :attribute deve ter :value caracteres ou menos.', + ], + 'max' => [ + 'array' => 'O campo :attribute não pode ter mais de :max itens.', + 'file' => 'O campo :attribute não pode ter mais de :max kilobytes.', + 'numeric' => 'O campo :attribute não pode ser superior a :max.', + 'string' => 'O campo :attribute não pode ter mais de :max caracteres.', + ], + 'mimes' => 'O campo :attribute deve ser um ficheiro do tipo: :values.', + 'mimetypes' => 'O campo :attribute deve ser um ficheiro do tipo: :values.', + 'min' => [ + 'array' => 'O campo :attribute deve ter pelo menos :min itens.', + 'file' => 'O campo :attribute deve ter pelo menos :min kilobytes.', + 'numeric' => 'O campo :attribute deve ser pelo menos :min.', + 'string' => 'O campo :attribute deve ter pelo menos :min caracteres.', + ], + 'multiple_of' => 'O campo :attribute deve ser múltiplo de :value.', + 'not_in' => 'O campo :attribute selecionado não é válido.', + 'not_regex' => 'O formato do campo :attribute não é válido.', + 'numeric' => 'O campo :attribute deve ser um número.', + 'password' => 'A palavra-passe está incorreta.', + 'present' => 'O campo :attribute deve estar presente.', + 'prohibited' => 'O campo :attribute é proibido.', + 'prohibited_if' => 'O campo :attribute é proibido quando :other é :value.', + 'prohibited_unless' => 'O campo :attribute é proibido, a menos que :other esteja em :values.', + 'prohibits' => 'O campo :attribute proíbe :other de estar presente.', + 'regex' => 'O formato do campo :attribute não é válido.', + 'required' => 'O campo :attribute é obrigatório.', + 'required_array_keys' => 'O campo :attribute deve incluir entradas para: :values.', + 'required_if' => 'O campo :attribute é obrigatório quando :other é :value.', + 'required_unless' => 'O campo :attribute é obrigatório, a menos que :other esteja em :values.', + 'required_with' => 'O campo :attribute é obrigatório quando :values está presente.', + 'required_with_all' => 'O campo :attribute é obrigatório quando :values estão presentes.', + 'required_without' => 'O campo :attribute é obrigatório quando :values não está presente.', + 'required_without_all' => 'O campo :attribute é obrigatório quando nenhum dos :values está presente.', + 'same' => 'O campo :attribute e :other devem coincidir.', + 'size' => [ + 'array' => 'O campo :attribute deve conter :size itens.', + 'file' => 'O campo :attribute deve ter :size kilobytes.', + 'numeric' => 'O campo :attribute deve ser :size.', + 'string' => 'O campo :attribute deve ter :size caracteres.', + ], + 'starts_with' => 'O campo :attribute deve começar com: :values.', + 'string' => 'O campo :attribute deve ser texto.', + 'timezone' => 'O campo :attribute deve ser uma zona válida.', + 'unique' => 'Este valor para :attribute já existe.', + 'uploaded' => 'O campo :attribute não foi carregado com sucesso.', + 'url' => 'O campo :attribute deve ser uma URL válida.', + 'uuid' => 'O campo :attribute deve ser um UUID válido.', + + 'custom' => [ + 'name' => [ + 'required' => 'O nome é obrigatório.', + 'string' => 'O nome deve ser texto.', + 'max' => 'O nome não pode ter mais de 255 caracteres.', + ], + 'tax_number' => [ + 'required' => 'O NIF é obrigatório.', + 'digits' => 'O NIF deve ter 9 dígitos.', + 'unique' => 'Já existe um cliente com este NIF.', + ], + 'email' => [ + 'required' => 'O e-mail é obrigatório.', + 'email' => 'O e-mail deve ser válido.', + 'max' => 'O e-mail não pode ter mais de 255 caracteres.', + ], + 'phone' => [ + 'required' => 'O telefone é obrigatório.', + 'string' => 'O telefone deve ser texto.', + 'max' => 'O telefone não pode ter mais de 20 caracteres.', + ], + 'address' => [ + 'required' => 'A morada é obrigatória.', + 'string' => 'A morada deve ser texto.', + 'max' => 'A morada não pode ter mais de 255 caracteres.', + ], + 'contact_info' => [ + 'string' => 'As informações de contacto devem ser texto.', + 'max' => 'As informações de contacto não podem exceder 255 caracteres.', + ], + 'notes' => [ + 'string' => 'As notas devem ser texto.', + 'max' => 'As notas não podem exceder 500 caracteres.', + ], + 'client_type_id' => [ + 'required' => 'O tipo de cliente é obrigatório.', + 'exists' => 'O tipo de cliente selecionado não é válido.', + ], + 'seller_id' => [ + 'required' => 'O vendedor é obrigatório.', + 'exists' => 'O vendedor selecionado não é válido.', + ], + 'locality' => [ + 'string' => 'A localidade deve ser texto.', + 'max' => 'A localidade não pode ter mais de 255 caracteres.', + ], + 'client_id' => [ + 'required' => 'O cliente é obrigatório.', + 'exists' => 'O cliente selecionado não é válido.', + ], + 'contract_value' => [ + 'numeric' => 'O valor do contrato deve ser um número.', + 'min' => 'O valor do contrato não pode ser negativo.', + ], + 'commission_value' => [ + 'numeric' => 'O valor da comissão deve ser um número.', + ], + 'profit_value' => [ + 'numeric' => 'O lucro deve ser um número.', + ], + 'supply_type' => [ + 'required' => 'O tipo de fornecimento é obrigatório.', + 'in' => 'O tipo de fornecimento deve ser CPE ou cui.', + ], + 'annual_consumption' => [ + 'numeric' => 'O consumo anual deve ser numérico.', + 'min' => 'O consumo anual não pode ser negativo.', + ], + 'contract_type_id' => [ + 'required' => 'O tipo de contrato é obrigatório.', + 'exists' => 'O tipo de contrato selecionado não é válido.', + ], + 'validity' => [ + 'date' => 'A validade deve ser uma data válida.', + 'date_format' => 'A validade deve estar no formato DD/MM/AAAA.', + ], + 'contract_end_date' => [ + 'date' => 'A data de fim do contrato deve ser válida.', + 'after_or_equal' => 'A data de fim de contrato deve ser igual ou posterior à data de contacto.', + 'date_format' => 'A data de fim de contrato deve estar no formato DD/MM/AAAA.', + ], + 'contract_date' => [ + 'date' => 'A data do contrato deve ser válida.', + 'date_format' => 'A data do contrato deve estar no formato DD/MM/AAAA.', + ], + 'activation_date' => [ + 'date' => 'A data de ativação deve ser válida.', + 'date_format' => 'A data de ativação deve estar no formato DD/MM/AAAA.', + ], + 'status_id' => [ + 'required' => 'O estado do contrato é obrigatório.', + 'exists' => 'O estado do contrato selecionado não é válido.', + ], + 'commission_rate' => [ + 'numeric' => 'A percentagem da comissão deve ser um número.', + 'between' => 'A percentagem da comissão deve estar entre 0 e 100.', + ], + 'power_tier_id' => [ + 'exists' => 'O escalão de potência selecionado não é válido.', + ], + 'payment_method_id' => [ + 'required' => 'O método de pagamento é obrigatório.', + 'exists' => 'O método de pagamento selecionado não é válido.', + ], + 'delivery_method' => [ + 'required' => 'O método de envio é obrigatório.', + 'in' => 'O método de envio deve ser "correio" ou "email".', + ], + 'delivery_email' => [ + 'email' => 'O e-mail de envio deve ser válido.', + 'max' => 'O e-mail de envio não pode exceder 255 caracteres.', + ], + 'previous_supplier_id' => [ + 'exists' => 'O fornecedor anterior selecionado não é válido.', + ], + 'new_supplier_id' => [ + 'exists' => 'O novo fornecedor selecionado não é válido.', + 'required_if' => 'O novo fornecedor é obrigatório quando a alteração está ativa.', + ], + 'paid' => [ + 'required' => 'O campo "Pago" é obrigatório.', + 'boolean' => 'O campo "Pago" deve ser verdadeiro ou falso.', + ], + 'chargeback' => [ + 'boolean' => 'O campo "Chargeback" deve ser verdadeiro ou falso.', + ], + 'chargeback_value' => [ + 'required_if' => 'O valor do chargeback é obrigatório.', + 'numeric' => 'O valor do chargeback deve ser numérico.', + 'max' => 'O valor do chargeback deve ser negativo.', + ], + 'chargeback_date' => [ + 'required_if' => 'A data de chargeback é obrigatória.', + 'date' => 'A data de chargeback deve ser uma data válida.', + 'date_format' => 'A data de chargeback deve estar no formato DD/MM/AAAA.', + ], + 'installments_due_date' => [ + 'required_with' => 'A data da parcela é obrigatória quando o valor está preenchido.', + 'date' => 'A data da parcela deve ser uma data válida.', + 'date_format' => 'A data da parcela deve estar no formato DD/MM/AAAA.', + ], + 'installments_amount' => [ + 'required_with' => 'O valor da parcela é obrigatório quando a data está preenchida.', + 'numeric' => 'O valor da parcela deve ser numérico.', + 'min' => 'O valor da parcela não pode ser negativo.', + ], + 'lead_status_id' => [ + 'exists' => 'O estado do lead selecionado não é válido.', + ], + 'contact_date' => [ + 'date' => 'A data de contacto deve ser válida.', + 'date_format' => 'A data de contacto deve estar no formato DD/MM/AAAA.', + ], + 'contract_type' => [ + 'in' => 'O tipo de contrato deve ser CPE ou CUI.', + ], + 'next_due_date' => [ + 'required' => 'A próxima renovação é obrigatória.', + 'date_format' => 'A próxima renovação deve estar no formato DD/MM/AAAA.', + ], + 'renewal_type' => [ + 'required' => 'O tipo de renovação é obrigatório.', + 'exists' => 'O tipo de renovação selecionado não é válido.', + ], + 'amount_paid' => [ + 'required' => 'O valor do contrato é obrigatório.', + 'numeric' => 'O valor do contrato deve ser um número.', + ], + 'cui_tier_id' => [ + 'exists' => 'O escalão CUI selecionado não é válido.', + ], + 'commission_value' => [ + 'numeric' => 'A comissão deve ser um número.', + ], + 'typology_id' => [ + 'exists' => 'A tipologia selecionada não é válida.', + ], + 'code' => [ + 'required' => 'O código é obrigatório.', + 'string' => 'O código deve ser texto.', + 'max' => 'O código não pode ter mais de 255 caracteres.', + ], + 'supply_address' => [ + 'string' => 'O endereço de fornecimento deve ser texto.', + 'max' => 'O endereço de fornecimento não pode exceder 255 caracteres.', + ], + ], + + 'attributes' => [ + 'name' => 'nome', + 'tax_number' => 'NIF', + 'email' => 'e-mail', + 'phone' => 'telefone', + 'address' => 'morada', + 'contact_info' => 'informações de contacto', + 'notes' => 'notas', + 'client_type_id' => 'tipo de cliente', + 'seller_id' => 'vendedor', + 'locality' => 'localidade', + 'client_id' => 'cliente', + 'contract_value' => 'valor do contrato', + 'commission_value' => 'valor da comissão', + 'profit_value' => 'lucro', + 'supply_type' => 'tipo de fornecimento', + 'supply_address' => 'endereço de fornecimento', + 'annual_consumption' => 'consumo anual', + 'code' => 'código', + 'contract_type_id' => 'tipo de contrato', + 'validity' => 'validade', + 'contract_end_date' => 'data de fim do contrato', + 'contract_date' => 'data do contrato', + 'activation_date' => 'data de ativação', + 'status_id' => 'estado do contrato', + 'commission_rate' => 'percentagem da comissão', + 'power_tier_id' => 'escalão de potência', + 'payment_method_id' => 'método de pagamento', + 'delivery_method' => 'método de envio', + 'delivery_email' => 'e-mail de envio', + 'previous_supplier_id' => 'fornecedor anterior', + 'new_supplier_id' => 'novo fornecedor', + 'typology_id' => 'tipologia', + 'cui_tier_id' => 'escalão CUI', + 'paid' => 'pago', + 'chargeback' => 'chargeback', + 'chargeback_value' => 'valor do chargeback', + 'chargeback_date' => 'data de chargeback', + 'next_due_date' => 'próxima renovação', + 'annual_consumption' => 'consumo anual', + 'renewal_type' => 'tipo de renovação', + 'lead_status_id' => 'estado do lead', + 'contact_date' => 'data de contacto', + 'contract_type' => 'tipo de contrato', + ], +]; diff --git a/resources/sass/_variables.scss b/resources/sass/_variables.scss new file mode 100644 index 0000000..172daaa --- /dev/null +++ b/resources/sass/_variables.scss @@ -0,0 +1,7 @@ +// Body +$body-bg: #f8fafc; + +// Typography +$font-family-sans-serif: 'Nunito', sans-serif; +$font-size-base: 0.9rem; +$line-height-base: 1.6; diff --git a/resources/sass/app.scss b/resources/sass/app.scss new file mode 100644 index 0000000..1026a0b --- /dev/null +++ b/resources/sass/app.scss @@ -0,0 +1,8 @@ +// Fonts +@import url('https://fonts.bunny.net/css?family=Nunito'); + +// Variables +@import 'variables'; + +// Bootstrap +@import 'bootstrap/scss/bootstrap'; diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php new file mode 100644 index 0000000..570f3e5 --- /dev/null +++ b/resources/views/auth/login.blade.php @@ -0,0 +1,87 @@ + + + + @include('layouts.base.head') + + +
+
+
+
+
+
+ + @if(session('error')) +
+ {{ session('error') }} +
+ @endif + +
+
+

Login

+
+
+ +
+ @csrf + +
+ + + @error('email') +
{{ $message }}
+ @enderror +
+ +
+ + + @error('password') +
{{ $message }}
+ @enderror +
+ +
+
+ + +
+
+ +
+ Forgot Password? + +
+
+
+
+
+
+
+
+
+ + Developed by + + Package IT + + +
+
+
+ @include('layouts.base.bottom') + + diff --git a/resources/views/auth/passwords/confirm.blade.php b/resources/views/auth/passwords/confirm.blade.php new file mode 100644 index 0000000..f8c8e61 --- /dev/null +++ b/resources/views/auth/passwords/confirm.blade.php @@ -0,0 +1,49 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Confirm Password') }}
+ +
+ {{ __('Please confirm your password before continuing.') }} + +
+ @csrf + +
+ + +
+ + + @error('password') + + {{ $message }} + + @enderror +
+
+ +
+
+ + + @if (Route::has('password.request')) + + {{ __('Forgot Your Password?') }} + + @endif +
+
+
+
+
+
+
+
+@endsection diff --git a/resources/views/auth/passwords/email.blade.php b/resources/views/auth/passwords/email.blade.php new file mode 100644 index 0000000..d801e4a --- /dev/null +++ b/resources/views/auth/passwords/email.blade.php @@ -0,0 +1,55 @@ + + + + + Pedir reset de password + + + + + +
+
+
+
+
+
Esqueci-me da password
+
+
+ @if (session('status')) +
+ {{ session('status') }} +
+ @endif + + @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + +
+ @csrf + +
+ + +
+ + +
+
+
+

© {{ date('Y') }} Voltcerto

+
+
+
+ + diff --git a/resources/views/auth/passwords/reset.blade.php b/resources/views/auth/passwords/reset.blade.php new file mode 100644 index 0000000..4dcbcc4 --- /dev/null +++ b/resources/views/auth/passwords/reset.blade.php @@ -0,0 +1,60 @@ + + + + + Alterar Password + + + + + +
+
+
+
+
+
Alterar Palavra-passe
+
+
+ @if (session('status')) +
{{ session('status') }}
+ @endif + + @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + +
+ @csrf + + + + +
+ + +
+ +
+ + +
+ + +
+
+
+

© {{ date('Y') }} Voltcerto

+
+
+
+ + diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php new file mode 100644 index 0000000..9da1ec2 --- /dev/null +++ b/resources/views/auth/register.blade.php @@ -0,0 +1,47 @@ +@extends('layouts.app') + +@section('content') +
+

Registar Novo Utilizador

+ +
+ @csrf + +
+ + +
+ +
+ + +
+ +
+
+ @forelse ($roles as $role) +
+ + +
+ @empty +

Nenhuma role disponível.

+ @endforelse +
+ +
+ + +
+ +

A palavra-passe será gerada automaticamente e enviada por e-mail apenas se o login estiver permitido.

+ + + Cancelar +
+
+@endsection diff --git a/resources/views/auth/verify.blade.php b/resources/views/auth/verify.blade.php new file mode 100644 index 0000000..9f8c1bc --- /dev/null +++ b/resources/views/auth/verify.blade.php @@ -0,0 +1,28 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
{{ __('Verify Your Email Address') }}
+ +
+ @if (session('resent')) + + @endif + + {{ __('Before proceeding, please check your email for a verification link.') }} + {{ __('If you did not receive the email') }}, +
+ @csrf + . +
+
+
+
+
+
+@endsection diff --git a/resources/views/components/pin-modal.blade.php b/resources/views/components/pin-modal.blade.php new file mode 100644 index 0000000..daa6f93 --- /dev/null +++ b/resources/views/components/pin-modal.blade.php @@ -0,0 +1,30 @@ + + diff --git a/resources/views/emails/new_user_welcome.blade.php b/resources/views/emails/new_user_welcome.blade.php new file mode 100644 index 0000000..494281b --- /dev/null +++ b/resources/views/emails/new_user_welcome.blade.php @@ -0,0 +1,14 @@ + + + + + Conta criada + + +

Olá, {{ $user->name }} 👋

+

A sua conta foi criada com sucesso na plataforma.

+

Email: {{ $user->email }}

+

Palavra-passe temporária: {{ $password }}

+

Recomenda-se que altere a sua palavra-passe após iniciar sessão.

+ + diff --git a/resources/views/emails/test-status.blade.php b/resources/views/emails/test-status.blade.php new file mode 100644 index 0000000..78c1079 --- /dev/null +++ b/resources/views/emails/test-status.blade.php @@ -0,0 +1,42 @@ + + + + Status do Envio de E-mail + + + +

Status do Envio de E-mail

+ +
    +
  • Destinatário: {{ $emailData['to'] }}
  • +
  • Assunto: {{ $emailData['subject'] }}
  • +
  • Corpo do E-mail: {{ $emailData['body'] }}
  • +
  • Data/Hora do Envio: {{ \Carbon\Carbon::parse($emailData['sent_at'])->format('d/m/Y H:i') }}
  • +
  • Tempo de Execução: {{ $emailData['execution_time'] }} segundos
  • +
  • Status: {{ $emailData['status'] }}
  • + @if($emailData['error']) +
  • Erro: {{ $emailData['error'] }}
  • + @endif +
+ +

Configuração do Sistema de Envio

+
    + @foreach($emailData['mail_config'] as $key => $value) +
  • {{ ucfirst($key) }}: {{ $value }}
  • + @endforeach +
+ +

Informações do Sistema

+
    +
  • Laravel: {{ $emailData['laravel_info']['laravel_version'] }}
  • +
  • PHP: {{ $emailData['laravel_info']['php_version'] }}
  • +
  • Ambiente: {{ $emailData['laravel_info']['env'] }}
  • +
  • Classe Mailer: {{ $emailData['laravel_info']['mailer_class'] }}
  • +
+ + diff --git a/resources/views/errors/503.blade.php b/resources/views/errors/503.blade.php new file mode 100644 index 0000000..455d891 --- /dev/null +++ b/resources/views/errors/503.blade.php @@ -0,0 +1,120 @@ + + + + + Manutenção em curso + + + + + +
+
+
⚡
+
🔥
+
+ + Manutenção programada + +

Estamos a melhorar o serviço

+ +

+ Temporariamente indisponível para manutenção. +

+ +
+ © {{ date('Y') }} — Luís Medon +
+
+ + diff --git a/resources/views/home.blade.php b/resources/views/home.blade.php new file mode 100644 index 0000000..4284e51 --- /dev/null +++ b/resources/views/home.blade.php @@ -0,0 +1,89 @@ +@extends('layouts.app') + +@section('content') +
+
+

+ Visão Geral do Sistema +

+
+ +
+
+
+
+ + {{-- Clients By Type --}} + +
+
+
+
+ + @can('view_contract_summary') +
+ @include('web.dashboard.partials.contractsTable', [ + 'contracts' => $upcomingRenewals, + 'title' => 'Próximas Renovações', + 'emptyMessage' => 'Não existem renovações agendadas para este mês.', + 'redirect' => '#' + ]) +
+ +
+ @include('web.dashboard.partials.contractsTable', [ + 'contracts' => $pendingContracts, + 'title' => 'Contratos por Ativar', + 'emptyMessage' => 'Não existem contratos por ativar.', + 'redirect' => route('contract.list', ['status' => 3]) + ]) +
+ +
+ @include('web.dashboard.partials.contractsTable', [ + 'contracts' => $activeContracts, + 'title' => 'Contratos Ativos', + 'emptyMessage' => 'Não existem contratos ativos.', + 'redirect' => route('contract.list', ['status' => 1]) + ]) +
+ @endcan +
+ + + + +@endsection diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..fb6d78d --- /dev/null +++ b/resources/views/layouts/app.blade.php @@ -0,0 +1,60 @@ + + + + + @include('layouts.base.head') + + + + + @include('layouts.base.topnav') + +
+
+ @include('layouts.base.sidenav') +
+ +
+ + @if ($errors->any()) +
+ +
+ @endif + + @if (session('success')) +
+ +
+ @endif + +
+ @yield('content') +
+
+ @include('layouts.base.footer') +
+
+
+ + @include('components.pin-modal') + + + @include('layouts.base.bottom') + + + diff --git a/resources/views/layouts/base/bottom.blade.php b/resources/views/layouts/base/bottom.blade.php new file mode 100644 index 0000000..c4c5016 --- /dev/null +++ b/resources/views/layouts/base/bottom.blade.php @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/views/layouts/base/footer.blade.php b/resources/views/layouts/base/footer.blade.php new file mode 100644 index 0000000..631976d --- /dev/null +++ b/resources/views/layouts/base/footer.blade.php @@ -0,0 +1,12 @@ +
+
+
{{ config('app.name') }} 2025 - {{ date('Y') }}
+
+ · + Dev + @if (isset($elapsed)) + Render time: {{ $elapsed }}ms + @endif +
+
+
diff --git a/resources/views/layouts/base/head.blade.php b/resources/views/layouts/base/head.blade.php new file mode 100644 index 0000000..2ec55ff --- /dev/null +++ b/resources/views/layouts/base/head.blade.php @@ -0,0 +1,27 @@ + + + + + + +{{ config('app.name') }} + + + + + + + + + + + + + + + + + + + + diff --git a/resources/views/layouts/base/sidenav.blade.php b/resources/views/layouts/base/sidenav.blade.php new file mode 100644 index 0000000..dc1011e --- /dev/null +++ b/resources/views/layouts/base/sidenav.blade.php @@ -0,0 +1,122 @@ + diff --git a/resources/views/layouts/base/topnav.blade.php b/resources/views/layouts/base/topnav.blade.php new file mode 100644 index 0000000..508b4ce --- /dev/null +++ b/resources/views/layouts/base/topnav.blade.php @@ -0,0 +1,69 @@ + + + diff --git a/resources/views/web/admin/access/index.blade.php b/resources/views/web/admin/access/index.blade.php new file mode 100644 index 0000000..8691d5e --- /dev/null +++ b/resources/views/web/admin/access/index.blade.php @@ -0,0 +1,93 @@ +@extends('layouts.app') + +@section('content') +
+
+

Criar Nova Permissão

+
+ @csrf +
+ + +
+
+ + +
+
+ +
+
+
+ +

Gestão de Acessos

+ +
+

1. Roles por Utilizador

+ @foreach ($users as $user) +
+
{{ $user->name }} ({{ $user->email }})
+
+ @foreach ($roles as $role) +
+ hasRole($role->name) ? 'checked' : '' }}> + +
+ @endforeach +
+
+ @endforeach +
+ +
+

2. Permissões por Role

+ @foreach ($roles as $role) +
+
{{ $role->description ?? $role->name }}
+
+ @foreach ($permissions as $permission) +
+ hasPermissionTo($permission->name) ? 'checked' : '' }}> + +
+ @endforeach +
+
+ @endforeach +
+
+ + +@endsection diff --git a/resources/views/web/admin/access/roles_permissions.blade.php b/resources/views/web/admin/access/roles_permissions.blade.php new file mode 100644 index 0000000..130d562 --- /dev/null +++ b/resources/views/web/admin/access/roles_permissions.blade.php @@ -0,0 +1,34 @@ +@extends('layouts.app') + +@section('content') +
+

Permissões por Role

+ @foreach ($roles as $role) +
+
+ {{ $role->description ?? $role->name }} +
+
+
+ @csrf +
+ @foreach ($permissions as $permission) +
+
+ hasPermissionTo($permission->name) ? 'checked' : '' }}> + +
+
+ @endforeach +
+ +
+
+
+ @endforeach +
+@endsection diff --git a/resources/views/web/admin/access/users.blade.php b/resources/views/web/admin/access/users.blade.php new file mode 100644 index 0000000..da2deb0 --- /dev/null +++ b/resources/views/web/admin/access/users.blade.php @@ -0,0 +1,38 @@ +@extends('layouts.app') + +@section('content') +
+

Roles por Utilizador

+ @foreach ($users as $user) +
+
+ {{ $user->name }} ({{ $user->email }}) +
+
+
+ @csrf +
+ @foreach ($roles as $role) + @if ($role->name === 'admin' && !Auth::user()->hasRole('admin')) + @continue + @endif + +
+
+ hasRole($role->name) ? 'checked' : '' }}> + +
+
+ @endforeach +
+ +
+
+
+ @endforeach +
+@endsection diff --git a/resources/views/web/admin/system.blade.php b/resources/views/web/admin/system.blade.php new file mode 100644 index 0000000..23edfce --- /dev/null +++ b/resources/views/web/admin/system.blade.php @@ -0,0 +1,27 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
Informação Geral do Sistema
+
    +
  • PHP: {{ $php_version }}
  • +
  • PHP SAPI: {{ $php_sapi }}
  • +
  • Laravel: {{ $laravel_version }}
  • +
  • Ambiente: {{ $environment }}
  • +
  • Debug Mode: {{ $debug_mode ? 'On' : 'Off' }}
  • +
  • Base de Dados: {{ $database_driver }}
  • +
  • Versão MySQL: {{ $database_version ?? 'N/A' }}
  • +
  • Redis: {{ $redis_version }}
  • +
  • Redis DB: {{ $redis_database }}
  • +
  • Cache Driver: {{ $cache_driver }}
  • +
  • Queue Driver: {{ $queue_driver }}
  • +
  • Session Driver: {{ $session_driver }}
  • +
  • Memory Limit: {{ $memory_limit }}
  • +
  • Sistema: {{ $system }}
  • +
+
+
+
+@endsection diff --git a/resources/views/web/admin/user/add_edit.blade.php b/resources/views/web/admin/user/add_edit.blade.php new file mode 100644 index 0000000..5b2fc36 --- /dev/null +++ b/resources/views/web/admin/user/add_edit.blade.php @@ -0,0 +1,64 @@ +@extends('layouts.app') + +@section('content') +
+

{{ isset($user) ? 'Editar Utilizador' : 'Registar Novo Utilizador' }}

+ +
+ @csrf + @if(isset($user)) + @method('PUT') + @endif + +
+ + +
+ +
+ + +
+ +
+
+ @forelse ($roles as $role) +
+ roles->pluck('name')->contains($role->name) ? 'checked' : '' }}> + +
+ @empty +

Nenhuma role disponível.

+ @endforelse +
+ +
+ can_login ?? true) ? 'checked' : '' }}> + +
+ + @if (!isset($user)) +

A palavra-passe será gerada automaticamente e enviada por e-mail apenas se o login estiver permitido.

+ @endif + + + Cancelar +
+ + @if (isset($user)) +
+ @csrf + +
+ @endif +
+@endsection diff --git a/resources/views/web/admin/user/index.blade.php b/resources/views/web/admin/user/index.blade.php new file mode 100644 index 0000000..df70ce9 --- /dev/null +++ b/resources/views/web/admin/user/index.blade.php @@ -0,0 +1,60 @@ +{{-- resources/views/web/admin/user/index.blade.php --}} +@extends('layouts.app') + +@section('content') +
+
+

Lista de Utilizadores

+ Novo Utilizador +
+ +
+
+
+ + + + + + + + + + + + @forelse ($users as $user) + + + + + + + + @empty + + + + @endforelse + +
NomeEmailLoginFunçõesAções
{{ $user->name }}{{ $user->email }} + @if ($user->can_login) + Sim + @else + Não + @endif + + @foreach ($user->roles as $role) + {{ $role->name }} + @endforeach + +
+ + + +
+
Nenhum utilizador encontrado.
+
+
+
+
+@endsection diff --git a/resources/views/web/analytical/index.blade.php b/resources/views/web/analytical/index.blade.php new file mode 100644 index 0000000..509f7c9 --- /dev/null +++ b/resources/views/web/analytical/index.blade.php @@ -0,0 +1,249 @@ +@extends('layouts.app') + +@section('content') + +
+
+
+

Painel Analítico

+

Desempenho de contratos e métricas de vendas.

+
+ +
+ +
+
+
+
+ +
+ De + + + Até + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ Limpar +
+
+
+
+ +
+
+
+
+
+
+ Clientes +

{{ $stats['total_clients'] }}

+
+
+
+
+
+
+
+
+
+ Contratos +

{{ $stats['contagem'] }}

+
+
+
+
+ @can('view_contract_summary') +
+
+
+
+
+ Vendas Totais +

{{ number_format($stats['total_vendas'], 0, ',', '.') }}€

+
+
+
+
+
+
+ Comissões +

{{ number_format($stats['total_comissao'], 0, ',', '.') }}€

+
+
+
+
+ Lucro +

{{ number_format($stats['total_lucro'], 0, ',', '.') }}€

+
+
+
+
+
+ @endcan +
+ + @can('view_contract_summary') +
+
+
+
+
Tendência de Crescimento
+ Mensal +
+
+ +
+
+
+
+
+
Mix por Tipo de Cliente
+
+ +
+
+
+
+ @endcan +
+ +@can('view_contract_summary') + + +@endcan +@endsection diff --git a/resources/views/web/clients/create/add.blade.php b/resources/views/web/clients/create/add.blade.php new file mode 100644 index 0000000..3a2e7ec --- /dev/null +++ b/resources/views/web/clients/create/add.blade.php @@ -0,0 +1,24 @@ +@extends('layouts.app') +@section('content') +
+
+
+
+
+

Escolha o Tipo de Cliente

+
+
+

Selecione o tipo de cliente para prosseguir.

+
+ @foreach ($clientTypes as $type) + + {{ $type->description }} + + @endforeach +
+
+
+
+
+
+@stop diff --git a/resources/views/web/clients/create/form.blade.php b/resources/views/web/clients/create/form.blade.php new file mode 100644 index 0000000..b531aac --- /dev/null +++ b/resources/views/web/clients/create/form.blade.php @@ -0,0 +1,90 @@ +@extends('layouts.app') +@section('content') +
+
+
+
+
+ Criar Cliente - {{ ucfirst($type->description) }} +
+
+
+ @csrf + +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ + + + +
+
+
+
+
+
+ + +@stop diff --git a/resources/views/web/clients/detail.blade.php b/resources/views/web/clients/detail.blade.php new file mode 100644 index 0000000..54fcdba --- /dev/null +++ b/resources/views/web/clients/detail.blade.php @@ -0,0 +1,56 @@ +@extends('layouts.app') +@section('content') +
+ +
+
+
+ +
+
+
+ @csrf +
+ + +
+ @include('web.clients.detail.info') +
+ + +
+ @include('web.clients.detail.contract') +
+ +
+
+ +
+
+
+
+
+
+@endsection diff --git a/resources/views/web/clients/detail/contract.blade.php b/resources/views/web/clients/detail/contract.blade.php new file mode 100644 index 0000000..a08970b --- /dev/null +++ b/resources/views/web/clients/detail/contract.blade.php @@ -0,0 +1,36 @@ +
+ +
+ + + + Adicionar Contrato + +
+ +
+ @foreach($contractsByStatus as $statusName => $contracts) +
+ @include('web.clients.detail.listContracts', ['contracts' => $contracts]) +
+ @endforeach +
+
diff --git a/resources/views/web/clients/detail/info.blade.php b/resources/views/web/clients/detail/info.blade.php new file mode 100644 index 0000000..fb2b7d3 --- /dev/null +++ b/resources/views/web/clients/detail/info.blade.php @@ -0,0 +1,71 @@ +
+
+ Cliente {{ $client->clientType->description }} +
+ +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+
diff --git a/resources/views/web/clients/detail/listContracts.blade.php b/resources/views/web/clients/detail/listContracts.blade.php new file mode 100644 index 0000000..3bc1c68 --- /dev/null +++ b/resources/views/web/clients/detail/listContracts.blade.php @@ -0,0 +1,73 @@ + + +
+ @foreach($contracts as $contract) +
+
+ +
+
    +
  • + 🔌 Fornecimento
    + {{ strtoupper($contract->supply_type) }} +
  • + +
  • + + @if ($contract->supply_type === 'cpe') + ⚡ Escalão de Potência + @elseif ($contract->supply_type === 'cui') + 🏢 Tipo de Instalação + @else + 📐 Informação Técnica + @endif +
    + + @if ($contract->supply_type === 'cpe') + {{ $contract->powerTier->name ?? 'N/A' }} + @elseif ($contract->supply_type === 'cui') + {{ $contract->cuiTier->name ?? 'N/A' }} + @else + N/A + @endif + +
  • + + @can('view_contract_summary') +
  • + 💶 Valor Contratual
    + {{ number_format($contract->contract_value, 2, ',', '.') }}€ +
  • + +
  • + 📈 Lucro
    + {{ number_format($contract->profit_value, 2, ',', '.') }}€ +
  • + +
  • + ↩️ Chargeback
    + {{ $contract->chargeback_value !== null ? number_format($contract->chargeback_value, 2, ',', '.') . '€' : '—' }} +
  • + @endcan + +
  • + 📅 Data do Contrato
    + {{ $contract->contract_date ? \Carbon\Carbon::parse($contract->contract_date)->format('d/m/Y') : '—' }} +
  • + +
  • + ⏳ Renovação
    + {{ $contract->validity ? \Carbon\Carbon::parse($contract->validity)->format('d/m/Y') : '—' }} +
  • +
+
+
+
+ @endforeach +
diff --git a/resources/views/web/clients/detail/payment.blade.php b/resources/views/web/clients/detail/payment.blade.php new file mode 100644 index 0000000..2d17a1f --- /dev/null +++ b/resources/views/web/clients/detail/payment.blade.php @@ -0,0 +1,24 @@ +
+
+ Métodos de Pagamento Disponiveis + {{-- --}} +
+
+ @foreach ($paymentMethods as $payMethod ) +
+
+ {!! $payMethod->icon !!} +
+
{{ $payMethod->description }}
+
+
+
+ id === $client->payment_type_id) + checked + @endif> +
+
+ @endforeach +
+
diff --git a/resources/views/web/clients/detail/statistics.blade.php b/resources/views/web/clients/detail/statistics.blade.php new file mode 100644 index 0000000..365e5d9 --- /dev/null +++ b/resources/views/web/clients/detail/statistics.blade.php @@ -0,0 +1,110 @@ +
+
+
+
+
+
Número de Contratos
+
152
+
+
+
+
+
+
+
Contratos Ativos
+
97
+
+
+
+
+
+
+
Pagamentos em atraso
+
+ 245.00€ +
+
+
+
+
+
+
+
Total de Pagamentos Realizados
+
+ 3,560.00€ +
+
+
+
+
+ +
+
+
+
+
Contratos com Pagamento em Falta
+
13
+
+
+
+
+ + +
+
+
+
Contratos por Status
+
+ +
+
+
+
+
+
Distribuição de Pagamentos
+
+ +
+
+
+
+
+ + + + + diff --git a/resources/views/web/clients/filtersList.blade.php b/resources/views/web/clients/filtersList.blade.php new file mode 100644 index 0000000..0abd001 --- /dev/null +++ b/resources/views/web/clients/filtersList.blade.php @@ -0,0 +1,62 @@ +
+
+
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ + + @if(!empty($clientTypes)) +
+ +
+ + +
+
+ @endif + +
+ + + Limpar + +
+
+
diff --git a/resources/views/web/clients/list.blade.php b/resources/views/web/clients/list.blade.php new file mode 100644 index 0000000..3260620 --- /dev/null +++ b/resources/views/web/clients/list.blade.php @@ -0,0 +1,130 @@ +@extends('layouts.app') +@section('content') +
+
+
+
+ Lista de Clientes + Adicionar Cliente +
+
+ + + +
+
+ @include('web.clients.filtersList') +
+
+ +
+ + + + + + + + + + + + @forelse($clients as $client) + + + + + + + + + + + + @empty + + + + @endforelse + +
NomeMoradaNIFEmailAções
+ + {{ Str::limit($client->name, 25) }} + + + {{ Str::limit($client->address, 30) ?? '—' }} + + + {{ $client->tax_number ?? '—' }} + + + + {{ $client->email ?? '—' }} + + +
+ + + + + +
+
+ Nenhum cliente encontrado. +
+
+ +
+ {{ $clients->links() }} +
+
+
+
+
+ + +@stop diff --git a/resources/views/web/contract/add_edit.blade.php b/resources/views/web/contract/add_edit.blade.php new file mode 100644 index 0000000..4542681 --- /dev/null +++ b/resources/views/web/contract/add_edit.blade.php @@ -0,0 +1,639 @@ +@extends('layouts.app') + +@section('content') +
+
+ + {{-- Botões de ação no topo --}} + @if(isset($contract)) + + @endif + +
+
+
+

+ + {{ isset($contract) ? 'Editar Contrato' : 'Criar Novo Contrato' }} +

+
+ +
+
+ @csrf + @if(isset($contract)) + @method('PUT') + @endif + + {{-- Cliente --}} +
+
+ + Selecionar Cliente +
+
+ + + + Digite pelo menos 2 caracteres para pesquisar. +
+
+ + {{-- Financeira --}} + @can('view_contract_summary') +
+
+ + Informação Financeira +
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+ + paid ?? false) ? 'checked' : '' }}> + +
+
+ + chargeback ?? false) ? 'checked' : '' }}> + +
+
+ +
+ + {{-- Parcelamento --}} +
+
+ installments->count() > 0 ? 'checked' : '') }}> + +
+ + +
+
+
+ @endcan + + {{-- Informações Gerais --}} +
+
+ + Informações Gerais +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
+
+ + {{-- Características Técnicas --}} +
+
+ + Características Técnicas +
+
+
+ {{-- CPE AREA --}} +
+ + +
+ {{-- CUI AREA --}} +
+ + +
+ +
+ + +
+
+
+
+ + + {{-- Método de Pagamento --}} +
+
+ + Método de Pagamento +
+
+
+
+ + + @error('payment_method_id') +
{{ $message }}
+ @enderror +
+ +
+ + +
+
+ +
+
+ + +
+
+
+
+ + + {{-- Datas do Contrato --}} +
+
+ + Datas do Contrato +
+
+
+ {{-- Data de Contrato --}} +
+ +
+ + +
+
+ + {{-- Data de Ativação --}} +
+ +
+ + +
+
+ + {{-- Data de Renovação --}} +
+ +
+ + +
+
+ + {{-- Data de Renovação --}} +
+ +
+ + +
+
+
+
+
+ + {{-- Outras Informações --}} +
+
+ + Outras Informações +
+
+
+
+ + +
+ +
+ + +
+ +
+ + +
+
+
+
+ + {{-- Notas --}} +
+
+ + Notas +
+
+ +
+
+ + {{-- Botões --}} +
+ + Cancelar + + +
+
+
+
+
+
+
+ +@endsection diff --git a/resources/views/web/contract/detail.blade.php b/resources/views/web/contract/detail.blade.php new file mode 100644 index 0000000..f576bd6 --- /dev/null +++ b/resources/views/web/contract/detail.blade.php @@ -0,0 +1,136 @@ +@extends('layouts.app') + +@section('content') + + +
+ + +
+
+ + @can('view_contract_summary') +
+
+

Resumo Financeiro (Gerência)

+
+
+
+
+
Lucro
+

{{ number_format($profit, 2, ',', '.') }} €

+
+
+
+
+
+
+
Total Recebido
+

{{ number_format($totalReceived, 2, ',', '.') }} €

+
+
+
+
+
+
+
Total Pendente
+

{{ number_format($totalPending, 2, ',', '.') }} €

+
+
+
+
+
+
+ @endcan + + +
+
Informações do Contrato
+
+
+ @can('view_contract_summary') +

PVP: {{ number_format($contract->pvp, 2, ',', '.') }} €

+

NET: {{ number_format($contract->net, 2, ',', '.') }} €

+ @endcan +

Potência: {{ $contract->power }} kW

+

Consumo Anual: {{ $contract->annual_consumption }} kW

+

Escalão: {{ $contract->tier }}

+
+
+

Tipo de Contrato: {{ $contract->contractType->description }}

+

Validade: {{ $contract->validity ? \Carbon\Carbon::parse($contract->validity)->format('d/m/Y') : '—' }}

+

Fim de Contrato: {{ $contract->contract_end_date ? \Carbon\Carbon::parse($contract->contract_end_date)->format('d/m/Y') : '—' }}

+

Data de Ativação: {{ $contract->activation_date ? \Carbon\Carbon::parse($contract->activation_date)->format('d/m/Y') : '—' }}

+

Fornecedor Anterior: {{ $contract->previous_supplier }}

+

Status: {{ $contract->status->description }}

+
+
+

Notas: {{ $contract->notes }}

+
+
+
+
+ + @can('view_contract_summary') +
+ +
+
Histórico de Pagamentos
+
+ @if($contract->payments->count()) +
+ + + + + + + + + + + + @foreach($contract->payments as $payment) + + + + + + + + @endforeach + +
DataValorPeríodo ReferênciaStatusObservações
{{ $payment->payment_date ? \Carbon\Carbon::parse($payment->payment_date)->format('d/m/Y') : '—' }}{{ number_format($payment->amount, 2, ',', '.') }} €{{ $payment->reference_period }}{{ ucfirst($payment->status) }}{{ $payment->notes }}
+
+ @else +

Nenhum pagamento registado.

+ @endif +
+
+
+ @endcan +
+
+@endsection diff --git a/resources/views/web/contract/history.blade.php b/resources/views/web/contract/history.blade.php new file mode 100644 index 0000000..e458f72 --- /dev/null +++ b/resources/views/web/contract/history.blade.php @@ -0,0 +1,198 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+

+ + Histórico de Renovação - Contrato #{{ $contract->code }} +

+ +
+ +
+ + @can('view_contract_summary') +
+
+
+
Renovações
+
{{ $totals->renewals_count }}
+
+
+
+
+
Total de parcelas
+
{{ $totals->total_installments }}
+
+
+
+
+
Parcelas pagas
+
{{ $totals->paid_installments }}
+
+
+
+
+
Valor contratos
+
{{ number_format($totals->contract_value, 2, ',', '.') }} €
+
+
+
+
+
Comissões
+
{{ number_format($totals->commission_value, 2, ',', '.') }} €
+
+
+
+
+
Lucro
+
{{ number_format($totals->profit_value, 2, ',', '.') }} €
+
+
+
+ @endcan + + @if($histories->isEmpty()) +
+ Nenhuma renovação registrada para este contrato. +
+ @else +
+ + + + + + + + + + + + + + @can('view_contract_summary') + + + + @endcan + + + @role('admin') + + @endrole + + + + @foreach($histories as $history) + + + + + + + + @can('view_contract_summary') + + @endcan + + + + @can('view_contract_summary') + + + + @endcan + + + @role('admin') + @can('view_contract_summary') + + @endcan + @endrole + + @endforeach + + @can('view_contract_summary') + + + + + + + + + @role('admin') + + @endrole + + + @endcan +
Fornecedor AnteriorFornecedor AtualData do ContratoData de AtivaçãoData de RenovaçãoConsumoParcelamentoFixo/IndexadoGO/FIRenovaçãoValor Contrato (€)Comissão (€)Lucro (€)VendedorAçõesSnapshot
{{ $history->previousSupplier->name ?? '-' }}{{ $history->currentSupplier->name ?? '-' }}{{ $history->contract_date ? \Carbon\Carbon::parse($history->contract_date)->format('d/m/Y') : '-' }}{{ $history->activation_date ? \Carbon\Carbon::parse($history->activation_date)->format('d/m/Y') : '-' }}{{ $history->renewal_date ? \Carbon\Carbon::parse($history->renewal_date)->format('d/m/Y') : ($history->validity ? $history->validity->format('d/m/Y') : '-') }}{{ $history->annual_consumption !== null ? number_format($history->annual_consumption, 2, ',', '.') : '-' }} + @if ( intval($history->total_installments) === 0) + - + @else + {{ $history->paid_installments }} / {{ $history->total_installments }} + @endif + {{ $history->contractType->description ?? '-' }}{{ $history->go_ki !== null ? number_format($history->go_ki, 2, ',', '.') : '-' }}{{ $history->renewal_type ?? '-' }}{{ number_format($history->contract_value, 2, ',', '.') }}{{ number_format($history->commission_value, 2, ',', '.') }}{{ number_format($history->profit_value, 2, ',', '.') }}{{ $history->seller->name ?? '-' }} + + + +
+ @csrf + @method('DELETE') + +
+
+ + + +
Totais{{ number_format($totals->contract_value, 2, ',', '.') }} €{{ number_format($totals->commission_value, 2, ',', '.') }} €{{ number_format($totals->profit_value, 2, ',', '.') }} €
+ + +
+ {{ $histories->links('pagination::bootstrap-5') }} +
+
+ + @endif +
+
+
+
+@endsection diff --git a/resources/views/web/contract/history_create.blade.php b/resources/views/web/contract/history_create.blade.php new file mode 100644 index 0000000..a3f2118 --- /dev/null +++ b/resources/views/web/contract/history_create.blade.php @@ -0,0 +1,133 @@ +@extends('layouts.app') + +@section('content') +
+
+
+

Criar registo do histórico

+ + Voltar + +
+
+
+ @csrf +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ @can('view_contract_summary') +
+ + +
+
+ + +
+
+ + +
+
+ +
+ + + +
+
+
+ + +
+
+ + +
+ @endcan +
+ + +
+
+
+ +
+
+
+
+
+@endsection diff --git a/resources/views/web/contract/history_edit.blade.php b/resources/views/web/contract/history_edit.blade.php new file mode 100644 index 0000000..5fe5414 --- /dev/null +++ b/resources/views/web/contract/history_edit.blade.php @@ -0,0 +1,88 @@ +@extends('layouts.app') + +@section('content') +
+
+
+

Editar registo do histórico

+ + Voltar + +
+
+
+ @csrf + @method('PUT') +
+
+ + +
+
+ + +
+
+ + +
+ @can('view_contract_summary') +
+ + +
+
+ + +
+
+ + +
+
+ +
+ + chargeback ?? false) ? 'checked' : '' }}> + +
+
+
+ + +
+
+ + +
+ @endcan +
+ + +
+
+
+ +
+
+
+
+
+@endsection diff --git a/resources/views/web/contract/list.blade.php b/resources/views/web/contract/list.blade.php new file mode 100644 index 0000000..a8f07ab --- /dev/null +++ b/resources/views/web/contract/list.blade.php @@ -0,0 +1,393 @@ +@extends('layouts.app') +@section('content') +
+
+
+
+

+ Gestão de Pontos de Entrega +

+ +
+ +
+
+ + @if (auth()->user()?->hasRole('administracao')) + + @endif +
+ +
+
+ @include('web.contract.listFilters') +
+
+ + @can('view_contract_summary') + + + + @endcan + +

Desloque horizontalmente para consultar todas as colunas.

+
+ + + + + + + + + @can('view_contract_summary') + + + + @endcan + + + + + + + + + + + @can('view_contract_summary') + + @endcan + + @if (auth()->user()?->hasRole('administracao')) + + + @endif + + + + @forelse($contracts as $contract) + + {{-- Client Name --}} + + {{-- Client Type --}} + + + {{-- Seller --}} + + + @can('view_contract_summary') + {{-- PVP --}} + + {{-- Comission --}} + + {{-- Profit --}} + + @endcan + + + + + + + + + + + + + + + + + + @can('view_contract_summary') + + @endcan + + + + @if (auth()->user()?->hasRole('administracao')) + + + @endif + + @empty + + + + @endforelse + +
NomeTipoVendedorPVPComissãoLucroCódigoTipo FornecimentoFornecedorPotência / EscalãoConsumoTipoAtivaçãoRenovaçãoFim de ContratoPagoEstadoAções + +
+ + {{ Str::limit($contract->client->name, 25) }} + + + {{ $contract->client->clientType->description }} + {{ $contract->seller->name ?? '—' }}{{ number_format($contract->contract_value, 2, ',', '.') }}{{ number_format($contract->commission_value, 2, ',', '.') }} + {{ number_format($contract->profit_value, 2, ',', '.') }} + {{ $contract->code }} + @if ($contract->supply_type === 'cpe') + CPE + @elseif ($contract->supply_type === 'cui') + CUI + @else + — + @endif + + {{ $contract->newSupplier->name }} + + @if ($contract->supply_type === 'cpe') + {{ $contract->powerTier->name ?? '—' }} + @elseif ($contract->supply_type === 'cui') + {{ $contract->cuiTier->name ?? '—' }} + @else + — + @endif + + @if ($contract->annual_consumption) + {{ number_format($contract->annual_consumption) }} kWh + @else + — + @endif + + {{ $contract->contractType->description ?? '—' }} + {{ $contract->activation_date ? $contract->activation_date->format('d/m/Y') : '—' }}{{ $contract->validity ? $contract->validity->format('d/m/Y') : '—' }}{{ $contract->contract_end_date ? $contract->contract_end_date->format('d/m/Y') : '—' }} + @if ($contract->paid) + Pago + @else + Não Pago + @endif + + + {{ $contract->status->description ?? '—' }} + + +
+ + + + + + + + + + + + + + + + + +
+
+ +
Nenhum contrato encontrado.
+
+ +
+ {{ $contracts->links() }} +
+
+
+
+
+ + +@stop diff --git a/resources/views/web/contract/listFilters.blade.php b/resources/views/web/contract/listFilters.blade.php new file mode 100644 index 0000000..182867f --- /dev/null +++ b/resources/views/web/contract/listFilters.blade.php @@ -0,0 +1,189 @@ +
+
+
+
Pesquisa de contratos
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+
+
Período
+
+ +
+ +
+ De + + Até + +
+
+ +
+ +
+ De + + Até + +
+
+ +
+ +
+ De + + Até + +
+
+ +
+
+
Responsáveis e apresentação
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + +
+
+ +
+ +
+ + + +
+
+ +
+ + + Limpar + +
+
+
diff --git a/resources/views/web/contract/renew.blade.php b/resources/views/web/contract/renew.blade.php new file mode 100644 index 0000000..f484cf5 --- /dev/null +++ b/resources/views/web/contract/renew.blade.php @@ -0,0 +1,299 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+

+ + Renovar Contrato {{ strtoupper($contract->supply_type) }} +

+
+ +
+ {{-- Informação Atual --}} +
+
+ + Informação Atual +
+
+

Código: {{ $contract->code }}

+

Fornecedor Atual: {{ $contract->newSupplier->name ?? '-' }}

+

Status: {{ $contract->status->description }}

+ @can('view_contract_summary') +

Valor do Contrato: {{ $contract->contract_value }}

+ @endcan +

Data Renovação Atual: {{ $contract->validity ? \Carbon\Carbon::parse($contract->validity)->format('d/m/Y') : '-' }}

+ +
+ + +
+ +
+ + +
+
+
+ + {{-- Formulário de Renovação --}} +
+ @csrf + + {{-- Fornecedor --}} +
+
+ + Fornecedor +
+
+ + +
+
+ + + + {{-- Dados do Contrato --}} +
+
+ + Dados do Contrato +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ +
+ + +
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+ + {{-- Financeira --}} + @can('view_contract_summary') +
+
+ + Dados Financeiros da Renovação +
+
+
+ + + + Valor Atual: {{ number_format($contract->contract_value, 2, ',', '.') }} € + + +
+ +
+ + +
+ +
+ +
+ 0.00 € + 0% +
+
+
+
+ @endcan + + {{-- Ações --}} +
+ + Cancelar + + +
+
+
+
+
+
+ + + + + +@endsection diff --git a/resources/views/web/dashboard/partials/contractsTable.blade.php b/resources/views/web/dashboard/partials/contractsTable.blade.php new file mode 100644 index 0000000..511f767 --- /dev/null +++ b/resources/views/web/dashboard/partials/contractsTable.blade.php @@ -0,0 +1,151 @@ +
+ + +
+ @if($contracts->isNotEmpty()) +
+ + + + + + + + + + + + + + + + + @can('view_contract_summary') + + @endcan + + + + + @can('view_contract_summary') + + + + @endcan + + + + + @foreach($contracts as $contract) + + + + + + + + + + + + + + + + + + + + + + + + + @can('view_contract_summary') + + @endcan + + + + + + + + + + @can('view_contract_summary') + + + + @endcan + + @endforeach + +
FornecedorGestorTipo ClienteLUZ / GASPotênciaCódigo ContratoClienteTipologiaTipo ContratoConsumo AnualData InícioData FimData RenovaçãoParcelamentoEstadoIdade ClienteNotasAUTOValorComissãoLucro
+ {{ $contract->newSupplier->name ?? '-' }} + {{ $contract->seller->name ?? '—' }}{{ $contract->client->clientType->description ?? '-' }} + @if($contract->supply_type === 'cpe') + CPE + @elseif($contract->supply_type === 'cui') + CUI + @else - @endif + {{ $contract->powerTier->name ?? '-' }} + + {{ $contract->code }} + + + + {{ $contract->client->name }} + + {{ $contract->typology->description ?? '-' }}{{ $contract->contractType->description ?? '-' }}{{ $contract->annual_consumption ?? '-' }}{{ $contract->contract_date ? \Carbon\Carbon::parse($contract->contract_date)->format('d/m/Y') : '-' }} + @if($contract->contract_date && $contract->validity) + {{ \Carbon\Carbon::parse($contract->contract_date)->addMonths($contract->validity)->format('d/m/Y') }} + @else - @endif + {{ $contract->validity ? \Carbon\Carbon::parse($contract->validity)->format('d/m/Y') : '-' }} + @if($contract->installments->isNotEmpty()) + @php + $total = $contract->installments->count(); + $pagas = $contract->installments->where('paid', 1)->count(); + $pendente = $contract->installments->where('paid', 0)->sum('amount'); + @endphp + + {{ $pagas }}/{{ $total }} + + @if($pendente > 0) +
{{ number_format($pendente, 2, ',', '.') }}€
+ @endif + @else + N/A + @endif +
+ + {{ ucfirst($contract->status->description ?? '-') }} + + + @if($contract->client && $contract->client->created_at) + @php $diff = \Carbon\Carbon::parse($contract->client->created_at)->diff(now()); @endphp + @if ($diff->y > 0) {{ $diff->y }} {{ Str::plural('ano', $diff->y) }} + @elseif ($diff->m > 0) {{ $diff->m }} {{ Str::plural('mês', $diff->m) }} + @else {{ $diff->d }} {{ Str::plural('dia', $diff->d) }} @endif + @else - @endif + + + {{ $contract->notes ?? '-' }} + + {{ isset($contract->auto) ? ($contract->auto ? 'Sim' : 'Não') : '-' }}{{ number_format($contract->contract_value, 2, ',', '.') }}€{{ number_format($contract->commission_value, 2, ',', '.') }}€ + {{ number_format($contract->profit_value, 2, ',', '.') }}€ +
+
+ @else +
+ +

{{ $emptyMessage ?? 'Nenhum contrato encontrado para este período.' }}

+
+ @endif +
+
diff --git a/resources/views/web/lead/add_edit.blade.php b/resources/views/web/lead/add_edit.blade.php new file mode 100644 index 0000000..149f33c --- /dev/null +++ b/resources/views/web/lead/add_edit.blade.php @@ -0,0 +1,115 @@ +@extends('layouts.app') +@section('content') +
+
+
+
+ {{ isset($lead) ? 'Editar Lead' : 'Adicionar Lead' }} +
+
+
+ @csrf + @if(isset($lead)) + @method('PUT') + @endif + + {{-- Nome e Email --}} +
+
+ + +
+
+ + +
+
+ + {{-- Telefone e Estado do Lead --}} +
+
+ + +
+
+ + +
+
+ + {{-- Morada --}} +
+ + +
+ + {{-- Datas de contacto e fim de contrato --}} +
+
+ + +
+
+ + +
+
+ + + {{-- Tipo de contrato --}} +
+ + +
+ + {{-- Código do ponto de entrega --}} +
+ + +
+ + + {{-- Informações de contato adicionais --}} +
+ + +
+ + {{-- Notas --}} +
+ + +
+ + {{-- Botões --}} +
+ Cancelar + +
+
+
+
+
+
+@endsection diff --git a/resources/views/web/lead/list.blade.php b/resources/views/web/lead/list.blade.php new file mode 100644 index 0000000..dafd68d --- /dev/null +++ b/resources/views/web/lead/list.blade.php @@ -0,0 +1,156 @@ +@extends('layouts.app') +@section('content') +
+
+
+
+

+ Gestão de Leads +

+ +
+ +
+ {{-- + +
+
+
+
--}} + +
+ + + + + + + + + + + + + + + + @forelse ($leads as $lead) + + + + + + + + + + + + @empty + + + + @endforelse + +
NomePonto de EntregaEstadoData de ContactoData fim de ContratoEmailTelefoneMorada Ações
{{ $lead->name }}{{ $lead->leadDetail?->delivery_point_code ?? '-' }}{{ $lead->leadStatus->name ?? 'Sem etapa' }}{{ $lead->leadDetail?->contact_date ? \Carbon\Carbon::parse($lead->leadDetail->contact_date)->format('d/m/Y') : '-' }}{{ $lead->leadDetail?->contract_end_date ? \Carbon\Carbon::parse($lead->leadDetail->contract_end_date)->format('d/m/Y') : '-' }}{{ $lead->email ?? '-' }}{{ $lead->phone ?? '-' }}{{ $lead->address ?? '-' }} +
+ + + + + +
+
Nenhum lead encontrado.
+
+ + +
+ {{ $leads->links() }} +
+
+
+
+
+ + +@stop diff --git a/resources/views/web/lead/show.blade.php b/resources/views/web/lead/show.blade.php new file mode 100644 index 0000000..e465f9a --- /dev/null +++ b/resources/views/web/lead/show.blade.php @@ -0,0 +1,21 @@ +@extends('layouts.app') + +@section('content') +
+

Detalhes do Lead

+ +
+
+

ID: {{ $lead->id }}

+

Nome: {{ $lead->name }}

+

Email: {{ $lead->email ?? '-' }}

+

Telefone: {{ $lead->phone ?? '-' }}

+

Estado: {{ $lead->leadStatus->name ?? 'Sem etapa' }}

+

Notas: {{ $lead->notes ?? '-' }}

+

Informações de Contato: {{ $lead->contact_info ?? '-' }}

+
+
+ + Voltar +
+@endsection diff --git a/resources/views/web/resources/contract_status/add_edit.blade.php b/resources/views/web/resources/contract_status/add_edit.blade.php new file mode 100644 index 0000000..002cb93 --- /dev/null +++ b/resources/views/web/resources/contract_status/add_edit.blade.php @@ -0,0 +1,65 @@ +@extends('layouts.app') + +@section('content') +
+
+
+

{{ isset($contractStatus) ? 'Editar Estado de Contrato' : 'Novo Estado de Contrato' }}

+ +
+
+
+ @csrf + @if(isset($contractStatus)) + @method('PUT') + @endif + +
+ + + @error('code') +
{{ $message }}
+ @enderror +
+ +
+ + + @error('description') +
{{ $message }}
+ @enderror +
+ +
+ + +
+ + + +
+ Cancelar + +
+
+
+
+
+
+
+@endsection diff --git a/resources/views/web/resources/contract_status/index.blade.php b/resources/views/web/resources/contract_status/index.blade.php new file mode 100644 index 0000000..978c56e --- /dev/null +++ b/resources/views/web/resources/contract_status/index.blade.php @@ -0,0 +1,58 @@ +@extends('layouts.app') + +@section('content') +
+
+

Estados de Contrato

+ Novo Estado +
+ + @if(session('success')) +
{{ session('success') }}
+ @endif + +
+
+
+ + + + + + + + + + + @forelse ($statuses as $contractStatus) + + + + + + + @empty + + + + @endforelse + +
IDCódigoDescriçãoAções
{{ $contractStatus->id }}{{ $contractStatus->code }}{{ $contractStatus->description }} +
+ + + +
+ @csrf + @method('DELETE') + +
+
+
Nenhum estado encontrado.
+
+
+
+
+@endsection diff --git a/resources/views/web/resources/contract_types/add_edit.blade.php b/resources/views/web/resources/contract_types/add_edit.blade.php new file mode 100644 index 0000000..73aad08 --- /dev/null +++ b/resources/views/web/resources/contract_types/add_edit.blade.php @@ -0,0 +1,42 @@ +@extends('layouts.app') + +@section('content') +
+
+
+

{{ isset($contract_type) ? 'Editar Tipo de Contrato' : 'Novo Tipo de Contrato' }}

+ +
+
+
+ @csrf + @if(isset($contract_type)) + @method('PUT') + @endif + +
+ + + @error('description') +
{{ $message }}
+ @enderror +
+ +
+ Cancelar + +
+
+
+
+
+
+
+@endsection diff --git a/resources/views/web/resources/contract_types/index.blade.php b/resources/views/web/resources/contract_types/index.blade.php new file mode 100644 index 0000000..613df87 --- /dev/null +++ b/resources/views/web/resources/contract_types/index.blade.php @@ -0,0 +1,60 @@ +@extends('layouts.app') + +@section('content') +
+
+

Tipos de Contrato

+ Novo Tipo +
+ +
+
+
+ + + + + + + + + + + @forelse ($types as $type) + + + + + + + @empty + + + + @endforelse + +
IDDescriçãoEstadoAções
{{ $type->id }}{{ $type->description }} + @if ($type->status === 'A') + ● + @else + ● + @endif + +
+ + + +
+ @csrf + @method('DELETE') + +
+
+
Nenhum tipo encontrado.
+
+
+
+
+@endsection diff --git a/resources/views/web/resources/cui_tiers/add_edit.blade.php b/resources/views/web/resources/cui_tiers/add_edit.blade.php new file mode 100644 index 0000000..b9eb5a5 --- /dev/null +++ b/resources/views/web/resources/cui_tiers/add_edit.blade.php @@ -0,0 +1,28 @@ +@extends('layouts.app') + +@section('content') +
+

{{ isset($cuiTier) ? 'Editar Escalão cui' : 'Novo Escalão cui' }}

+ +
+ @csrf + @if (isset($cuiTier)) + @method('PUT') + @endif + +
+ + + @error('name') +
{{ $message }}
+ @enderror +
+ + Cancelar + +
+
+@endsection diff --git a/resources/views/web/resources/cui_tiers/index.blade.php b/resources/views/web/resources/cui_tiers/index.blade.php new file mode 100644 index 0000000..4455c95 --- /dev/null +++ b/resources/views/web/resources/cui_tiers/index.blade.php @@ -0,0 +1,60 @@ +@extends('layouts.app') + +@section('content') +
+
+

Escalões cui

+ Novo Escalão +
+ +
+
+
+ + + + + + + + + + + @forelse ($cuiTiers as $tier) + + + + + + + @empty + + + + @endforelse + +
IDNomeEstadoAções
{{ $tier->id }}{{ $tier->name }} + @if ($tier->status === 'A') + ● + @else + ● + @endif + +
+ + + +
+ @csrf + @method('DELETE') + +
+
+
Nenhum escalão encontrado.
+
+
+
+
+@endsection diff --git a/resources/views/web/resources/payment_methods/add_edit.blade.php b/resources/views/web/resources/payment_methods/add_edit.blade.php new file mode 100644 index 0000000..e9c388c --- /dev/null +++ b/resources/views/web/resources/payment_methods/add_edit.blade.php @@ -0,0 +1,59 @@ +@extends('layouts.app') + +@section('content') +
+
+
+

{{ isset($payment_method) ? 'Editar Método de Pagamento' : 'Novo Método de Pagamento' }}

+ +
+
+
+ @csrf + @if(isset($payment_method)) + @method('PUT') + @endif + +
+ + + @error('name') +
{{ $message }}
+ @enderror +
+ +
+ + + @error('icon') +
{{ $message }}
+ @enderror + Consulta os ícones disponíveis em fontawesome.com/icons +
+ +
+ Cancelar + +
+
+
+
+
+
+
+@endsection diff --git a/resources/views/web/resources/payment_methods/index.blade.php b/resources/views/web/resources/payment_methods/index.blade.php new file mode 100644 index 0000000..3e71e90 --- /dev/null +++ b/resources/views/web/resources/payment_methods/index.blade.php @@ -0,0 +1,62 @@ +@extends('layouts.app') + +@section('content') +
+
+

Métodos de Pagamento

+ Novo Método +
+ +
+
+
+ + + + + + + + + + + + @forelse ($methods as $method) + + + + + + + + @empty + + + + @endforelse + +
IDNomeÍconeEstadoAções
{{ $method->id }}{{ $method->name }} {{ $method->icon }} + @if ($method->status === 'A') + ● + @else + ● + @endif + +
+ + + +
+ @csrf + @method('DELETE') + +
+
+
Nenhum método encontrado.
+
+
+
+
+@endsection diff --git a/resources/views/web/resources/power_tiers/add_edit.blade.php b/resources/views/web/resources/power_tiers/add_edit.blade.php new file mode 100644 index 0000000..05e5a5a --- /dev/null +++ b/resources/views/web/resources/power_tiers/add_edit.blade.php @@ -0,0 +1,42 @@ +@extends('layouts.app') + +@section('content') +
+
+
+

{{ isset($power_tier) ? 'Editar Potência' : 'Nova Potência' }}

+ +
+
+
+ @csrf + @if(isset($power_tier)) + @method('PUT') + @endif + +
+ + + @error('name') +
{{ $message }}
+ @enderror +
+ +
+ Cancelar + +
+
+
+
+
+
+
+@endsection diff --git a/resources/views/web/resources/power_tiers/index.blade.php b/resources/views/web/resources/power_tiers/index.blade.php new file mode 100644 index 0000000..8f696e0 --- /dev/null +++ b/resources/views/web/resources/power_tiers/index.blade.php @@ -0,0 +1,60 @@ +@extends('layouts.app') + +@section('content') +
+
+

Potências

+ Nova Potência +
+ +
+
+
+ + + + + + + + + + + @forelse ($tiers as $tier) + + + + + + + @empty + + + + @endforelse + +
IDNomeEstadoAções
{{ $tier->id }}{{ $tier->name }} + @if ($tier->status === 'A') + ● + @else + ● + @endif + +
+ + + +
+ @csrf + @method('DELETE') + +
+
+
Nenhuma potência encontrada.
+
+
+
+
+@endsection diff --git a/resources/views/web/resources/suppliers/add_edit.blade.php b/resources/views/web/resources/suppliers/add_edit.blade.php new file mode 100644 index 0000000..f412901 --- /dev/null +++ b/resources/views/web/resources/suppliers/add_edit.blade.php @@ -0,0 +1,42 @@ +@extends('layouts.app') + +@section('content') +
+

{{ isset($supplier) ? 'Editar Fornecedor' : 'Novo Fornecedor' }}

+ + @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + +
+ @csrf + @if (isset($supplier)) + @method('PUT') + @endif + +
+ + +
+ +
+ + +
+ + + + Cancelar +
+
+@endsection diff --git a/resources/views/web/resources/suppliers/index.blade.php b/resources/views/web/resources/suppliers/index.blade.php new file mode 100644 index 0000000..6b419d0 --- /dev/null +++ b/resources/views/web/resources/suppliers/index.blade.php @@ -0,0 +1,68 @@ +@extends('layouts.app') + +@section('content') +
+
+

Fornecedores

+ Novo Fornecedor +
+ +
+
+
+ + + + + + + + + + + + @forelse ($suppliers as $supplier) + + + + + + + + @empty + + + + @endforelse + +
IDNomeCorEstadoAções
{{ $supplier->id }}{{ $supplier->name }} + @if ($supplier->color) +     + @else + — + @endif + + @if ($supplier->status === 'A') + ● + @else + ● + @endif + +
+ + + +
+ @csrf + @method('DELETE') + +
+
+
Nenhum fornecedor encontrado.
+
+
+
+
+@endsection diff --git a/resources/views/web/resources/typology/add_edit.blade.php b/resources/views/web/resources/typology/add_edit.blade.php new file mode 100644 index 0000000..eb4559c --- /dev/null +++ b/resources/views/web/resources/typology/add_edit.blade.php @@ -0,0 +1,45 @@ +@extends('layouts.app') + +@section('content') +
+
+
+

{{ isset($typology) ? 'Editar Tipologia' : 'Nova Tipologia' }}

+ +
+
+
+ @csrf + @if(isset($typology)) + @method('PUT') + @endif + +
+ + + @error('description') +
{{ $message }}
+ @enderror +
+ +
+ Cancelar + +
+
+
+
+ +
+
+
+@endsection diff --git a/resources/views/web/resources/typology/index.blade.php b/resources/views/web/resources/typology/index.blade.php new file mode 100644 index 0000000..4be50da --- /dev/null +++ b/resources/views/web/resources/typology/index.blade.php @@ -0,0 +1,60 @@ +@extends('layouts.app') + +@section('content') +
+
+

Tipologias

+ Nova Tipologia +
+ +
+
+
+ + + + + + + + + + + @forelse ($typologies as $typology) + + + + + + + @empty + + + + @endforelse + +
IDDescriçãoEstadoAções
{{ $typology->id }}{{ $typology->description }} + @if ($typology->status === 'A') + ● + @else + ● + @endif + +
+ + + +
+ @csrf + @method('DELETE') + +
+
+
Nenhuma tipologia encontrada.
+
+
+
+
+@endsection diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php new file mode 100644 index 0000000..eb1dcae --- /dev/null +++ b/resources/views/welcome.blade.php @@ -0,0 +1,163 @@ + + + + + + + Laravel + + + + + + + + + + + + diff --git a/routes/api.php b/routes/api.php new file mode 100644 index 0000000..323fa8e --- /dev/null +++ b/routes/api.php @@ -0,0 +1,75 @@ +middleware('throttle:10,1'); +Route::post('password/email', [AuthController::class, 'sendResetLink'])->middleware('throttle:5,1'); +Route::post('password/reset', [AuthController::class, 'resetPassword'])->middleware('throttle:5,1'); + +Route::middleware(['auth:sanctum', \App\Http\Middleware\EnsureApiUser::class])->group(function () { + Route::post('logout', [AuthController::class, 'logout']); + Route::post('refresh', [AuthController::class, 'refresh']); + Route::get('check-token', [AuthController::class, 'checkToken']); + Route::get('me', [AuthController::class, 'user']); + Route::get('dashboard', [DashboardController::class, 'index']); + Route::get('analytics', [DashboardController::class, 'analytics'])->middleware('role:administracao'); + + Route::post('user/pin', [UserController::class, 'savePin']); + Route::post('user/check-pin', [UserController::class, 'checkPin'])->middleware('throttle:10,1'); + + Route::prefix('clients')->group(function () { + Route::get('options', [ClientController::class, 'options']); + Route::get('search/name', [ClientController::class, 'searchName']); + Route::post('search/id', [ClientController::class, 'searchID']); + Route::get('{id}/detail', [ClientController::class, 'detail'])->whereNumber('id'); + }); + Route::apiResource('clients', ClientController::class)->parameters(['clients' => 'id'])->whereNumber('id'); + + Route::prefix('contracts')->group(function () { + Route::get('options', [ContractController::class, 'options']); + Route::get('export', [ContractController::class, 'export'])->middleware('can:view_contract_summary'); + Route::delete('bulk', [ContractController::class, 'bulkDestroy']); + Route::get('{id}/edit', [ContractController::class, 'edit'])->whereNumber('id'); + Route::get('{id}/renew', [ContractController::class, 'renewalOptions'])->whereNumber('id'); + Route::post('{id}/renew', [ContractController::class, 'renew'])->whereNumber('id'); + Route::get('{id}/history', [ContractController::class, 'history'])->whereNumber('id'); + Route::get('{id}/history/{historyId}', [ContractController::class, 'showHistory'])->whereNumber(['id', 'historyId']); + Route::put('{id}/history/{historyId}', [ContractController::class, 'updateHistory'])->whereNumber(['id', 'historyId']); + Route::delete('{id}/history/{historyId}', [ContractController::class, 'destroyHistory'])->whereNumber(['id', 'historyId']); + }); + Route::apiResource('contracts', ContractController::class)->parameters(['contracts' => 'id'])->whereNumber('id'); + + Route::get('leads/options', [LeadController::class, 'options']); + Route::put('leads/{id}/convert', [LeadController::class, 'convert'])->whereNumber('id'); + Route::apiResource('leads', LeadController::class)->parameters(['leads' => 'id'])->whereNumber('id'); + + Route::middleware('role:admin')->group(function () { + Route::get('users/options', [UserController::class, 'options']); + Route::post('users/{user}/password-reset', [UserController::class, 'sendPasswordResetLink'])->whereNumber('user'); + Route::apiResource('users', UserController::class)->whereNumber('user'); + + Route::prefix('admin')->group(function () { + Route::get('info', [AdminController::class, 'info']); + Route::get('phpinfo', [AdminController::class, 'phpInfo']); + Route::post('runMigrations', [AdminController::class, 'runMigrations']); + Route::post('testEmail', [AdminController::class, 'testEmail'])->middleware('throttle:5,1'); + Route::get('access/roles-permissions', [AccessController::class, 'roles']); + Route::post('access/roles/{role}/permissions', [AccessController::class, 'updatePermissions'])->whereNumber('role'); + Route::get('access/users', [AccessController::class, 'users']); + Route::post('access/users/{user}/roles', [AccessController::class, 'updateRoles'])->whereNumber('user'); + }); + }); + + Route::middleware('can:manage_resources')->prefix('resources')->group(function () { + $resources = 'power_tiers|contract_types|payment_methods|typologies|cui_tiers|suppliers|contract-statuses'; + Route::get('{resource}', [ResourceController::class, 'index'])->where('resource', $resources); + Route::post('{resource}', [ResourceController::class, 'store'])->where('resource', $resources); + Route::get('{resource}/{id}', [ResourceController::class, 'show'])->where('resource', $resources)->whereNumber('id'); + Route::put('{resource}/{id}', [ResourceController::class, 'update'])->where('resource', $resources)->whereNumber('id'); + Route::delete('{resource}/{id}', [ResourceController::class, 'destroy'])->where('resource', $resources)->whereNumber('id'); + }); +}); \ No newline at end of file diff --git a/routes/console.php b/routes/console.php new file mode 100644 index 0000000..57843b8 --- /dev/null +++ b/routes/console.php @@ -0,0 +1,11 @@ +comment(Inspiring::quote()); +})->purpose('Display an inspiring quote'); diff --git a/routes/web.php b/routes/web.php new file mode 100644 index 0000000..80f1394 --- /dev/null +++ b/routes/web.php @@ -0,0 +1,151 @@ +group(function () { + // API login + Route::get('login', [ApiLoginController::class, 'showLoginForm'])->name('login'); + Route::post('login', [ApiLoginController::class, 'login'])->middleware('throttle:10,1')->name('login.post'); + Route::post('logout', [ApiLoginController::class, 'logout'])->name('logout'); + + // Password reset + Route::get('password/reset', [ForgotPasswordController::class, 'showLinkRequestForm'])->name('password.request'); + Route::post('password/email', [ForgotPasswordController::class, 'sendResetLinkEmail'])->middleware('throttle:5,1')->name('password.email'); + Route::get('password/reset/{token}', [ResetPasswordController::class, 'showResetForm'])->name('password.reset'); + Route::post('password/reset', [ResetPasswordController::class, 'reset'])->middleware('throttle:5,1')->name('password.update'); +}); + +/** + * ---------------------------------------------------------- + * Private routes (only for authenticated API users) + * ---------------------------------------------------------- + */ +Route::middleware(['web', 'auth.session'])->group(function () { + + // Home/Dashboard + Route::get('/', [HomeController::class, 'index'])->name('home'); + + // Users (PIN management) + Route::prefix('user')->name('user.')->group(function () { + Route::post('pin', [UserController::class, 'savePin'])->name('pin.save'); + Route::post('check-pin', [UserController::class, 'checkPin'])->middleware('throttle:10,1')->name('checkPin'); + }); + + // Contracts + Route::prefix('contract')->name('contract.')->group(function () { + Route::get('list', [ContractController::class, 'index'])->name('list'); + Route::get('add', [ContractController::class, 'create'])->name('add'); + Route::post('store', [ContractController::class, 'store'])->name('store'); + Route::get('{id}/edit', [ContractController::class, 'edit'])->name('edit'); + Route::put('{id}/update', [ContractController::class, 'update'])->name('update'); + Route::get('{id}/renew', [ContractController::class, 'renewForm'])->name('renew.form'); + Route::post('{id}/renew', [ContractController::class, 'renew'])->name('renew'); + Route::get('{id}/history', [ContractController::class, 'history'])->name('history'); + Route::get('{id}/history/create', [ContractController::class, 'createHistory'])->name('history.create'); + Route::post('{id}/history', [ContractController::class, 'storeHistory'])->name('history.store'); + Route::get('{id}/history/{historyId}/edit', [ContractController::class, 'editHistory'])->name('history.edit'); + Route::put('{id}/history/{historyId}', [ContractController::class, 'updateHistory'])->name('history.update'); + Route::delete('{id}/history/{historyId}', [ContractController::class, 'destroyHistory'])->name('history.destroy'); + Route::get('/contracts/export', [ContractController::class, 'export'])->middleware('can:view_contract_summary')->name('export'); + Route::delete('bulk', [ContractController::class, 'bulkDestroy'])->name('bulk.destroy'); + Route::delete('{id}', [ContractController::class, 'destroy'])->name('destroy'); + }); + + // Leads + Route::prefix('lead')->name('lead.')->group(function () { + Route::get('/', [LeadController::class, 'list'])->name('list'); + Route::get('/create', [LeadController::class, 'create'])->name('create'); + Route::post('/', [LeadController::class, 'store'])->name('store'); + Route::get('/{id}', [LeadController::class, 'show'])->name('show'); + Route::get('/{id}/edit', [LeadController::class, 'edit'])->name('edit'); + Route::put('/{id}', [LeadController::class, 'update'])->name('update'); + Route::put('/{id}/convert', [LeadController::class, 'convert'])->name('convert'); + Route::delete('/{id}', [LeadController::class, 'destroy'])->name('destroy'); + }); + + // Clients + Route::prefix('client')->name('client.')->group(function () { + Route::get('list', [ClientController::class, 'list'])->name('list'); + Route::get('add', [ClientController::class, 'add'])->name('add'); + Route::get('create/{type}', [ClientController::class, 'add2step'])->name('create'); + Route::post('store', [ClientController::class, 'store'])->name('store'); + Route::get('detail/{id}', [ClientController::class, 'detail'])->name('detail'); + Route::post('detail/{id}', [ClientController::class, 'update'])->name('update'); + Route::delete('/{id}', [ClientController::class, 'destroy'])->name('destroy'); + }); + + // Admin - Roles & Permissions + Route::middleware('role:admin')->prefix('admin/access')->name('admin.access.')->group(function () { + Route::get('/roles-permissions', [RolePermissionController::class, 'index'])->name('roles-permissions'); + Route::post('/roles/{role}/permissions', [RolePermissionController::class, 'updatePermissions'])->name('roles.update-permissions'); + Route::get('/users', [UserAccessController::class, 'index'])->name('users'); + Route::post('/users/{user}/roles', [UserAccessController::class, 'updateRoles'])->name('users.update-roles'); + }); + + // Analytical + Route::middleware('role:administracao')->prefix('Analytical')->name('Analytical.')->group(function () { + Route::get('/', [AnalyticalController::class, 'index'])->name('index'); + }); + + // User management + Route::middleware('role:admin')->prefix('users')->name('users.')->group(function () { + Route::get('/', [UserController::class, 'index'])->name('index'); + Route::get('/create', [UserController::class, 'create'])->name('create'); + Route::post('/', [UserController::class, 'store'])->name('store'); + Route::post('/{user}/password-reset', [UserController::class, 'sendPasswordResetLink'])->name('password-reset'); + Route::get('/{user}/edit', [UserController::class, 'edit'])->name('edit'); + Route::put('/{user}', [UserController::class, 'update'])->name('update'); + Route::delete('/{user}', [UserController::class, 'destroy'])->name('destroy'); + }); + + // Admin-only routes + Route::middleware('role:admin')->prefix('admin')->name('admin.')->group(function () { + Route::get('info', [AdminController::class, 'main'])->name('info'); + Route::get('phpinfo', [AdminController::class, 'phpInfo'])->name('phpinfo'); + }); + + // AJAX utility routes + Route::prefix('utils.ajax')->name('utils.ajax.')->group(function () { + Route::get('clients/search/name', [ClientController::class, 'searchName'])->name('clients.search.name'); + Route::post('clients/search/id', [ClientController::class, 'searchID'])->name('clients.search.id'); + }); + + // Resource management + Route::middleware('can:manage_resources')->group(function () { + Route::resource('power_tiers', PowerTierController::class); + Route::resource('contract_types', ContractTypeController::class); + Route::resource('payment_methods', PaymentMethodController::class); + Route::resource('typologies', TypologyController::class); + Route::resource('cui_tiers', CuiTierController::class); + Route::resource('suppliers', SupplierController::class); + Route::resource('contract-statuses', ContractStatusController::class); + }); +}); diff --git a/storage/app/.gitignore b/storage/app/.gitignore new file mode 100644 index 0000000..fedb287 --- /dev/null +++ b/storage/app/.gitignore @@ -0,0 +1,4 @@ +* +!private/ +!public/ +!.gitignore diff --git a/storage/app/private/.gitignore b/storage/app/private/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/app/private/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/app/public/.gitignore b/storage/app/public/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/app/public/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/.gitignore b/storage/framework/.gitignore new file mode 100644 index 0000000..05c4471 --- /dev/null +++ b/storage/framework/.gitignore @@ -0,0 +1,9 @@ +compiled.php +config.php +down +events.scanned.php +maintenance.php +routes.php +routes.scanned.php +schedule-* +services.json diff --git a/storage/framework/cache/.gitignore b/storage/framework/cache/.gitignore new file mode 100644 index 0000000..01e4a6c --- /dev/null +++ b/storage/framework/cache/.gitignore @@ -0,0 +1,3 @@ +* +!data/ +!.gitignore diff --git a/storage/framework/cache/data/.gitignore b/storage/framework/cache/data/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/cache/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/sessions/.gitignore b/storage/framework/sessions/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/sessions/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/testing/.gitignore b/storage/framework/testing/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/testing/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/framework/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/storage/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/tests/Api/ApiEndpointsTest.php b/tests/Api/ApiEndpointsTest.php new file mode 100644 index 0000000..e99eef6 --- /dev/null +++ b/tests/Api/ApiEndpointsTest.php @@ -0,0 +1,222 @@ +get('/api/' . $endpoint)->assertUnauthorized()->assertJsonStructure(['message']); + } + } + + public function test_login_validation_and_invalid_credentials_return_json_errors(): void + { + $this->post('/api/login', [])->assertUnprocessable()->assertJsonValidationErrors(['email', 'password']); + $this->postJson('/api/login', ['email' => 'user@example.com', 'password' => 'wrong'])->assertUnauthorized(); + } + + public function test_login_refresh_check_and_logout_use_real_bearer_tokens(): void + { + Http::preventStrayRequests(); + $login = $this->postJson('/api/login', ['email' => 'user@example.com', 'password' => 'secret123']); + $login->assertOk()->assertJsonPath('user.id', 1); + $token = $login->json('token'); + $this->withToken($token)->getJson('/api/check-token')->assertOk()->assertJsonPath('valid', true); + $this->withToken($token)->postJson('/api/refresh')->assertOk()->assertJsonStructure(['expires_at']); + $this->withToken($token)->postJson('/api/logout')->assertOk()->assertJsonPath('revoked', true); + $this->assertDatabaseCount('personal_access_tokens', 0); + $this->app['auth']->forgetGuards(); + $this->withToken($token)->getJson('/api/check-token')->assertUnauthorized(); + } + + public function test_expired_tokens_and_disabled_users_cannot_login(): void + { + $user = User::findOrFail(1); + $token = $user->createToken('expired', ['*'], now()->subMinute()); + $this->withToken($token->plainTextToken)->getJson('/api/check-token')->assertUnauthorized(); + $user->update(['can_login' => false]); + $this->postJson('/api/login', ['email' => 'user@example.com', 'password' => 'secret123'])->assertUnauthorized(); + $validToken = $user->createToken('disabled', ['*'], now()->addMinutes(20)); + $this->app['auth']->forgetGuards(); + $this->withToken($validToken->plainTextToken)->getJson('/api/check-token')->assertUnauthorized(); + } + + public function test_client_crud_uses_shared_service_and_returns_ids(): void + { + $this->authenticate(); + $created = $this->postJson('/api/clients', $this->clientData())->assertCreated(); + $id = $created->json('client.id'); + $this->assertNotNull($id); + $this->getJson('/api/clients?name=Client')->assertOk()->assertJsonPath('clients.0.id', $id); + $this->getJson('/api/clients?per_page=1')->assertOk()->assertJsonPath('clients.data.0.id', $id)->assertJsonPath('clients.per_page', 1); + $this->getJson('/api/clients/' . $id)->assertOk()->assertJsonPath('id', $id); + $this->putJson('/api/clients/' . $id, array_replace($this->clientData(), ['name' => 'Changed'])) + ->assertOk()->assertJsonPath('client.name', 'Changed'); + $this->deleteJson('/api/clients/' . $id)->assertOk(); + $this->assertDatabaseHas('clients', ['id' => $id, 'status' => 'I']); + $this->getJson('/api/clients')->assertJsonCount(0, 'clients'); + } + + public function test_client_validation_and_missing_record_return_422_and_404(): void + { + $this->authenticate(); + $this->postJson('/api/clients', [])->assertUnprocessable()->assertJsonValidationErrors(['name', 'tax_number']); + $this->getJson('/api/clients/999')->assertNotFound()->assertJsonStructure(['message']); + } + + public function test_lead_conversion_uses_the_business_service(): void + { + $this->authenticate(); + $lead = Clients::create(array_replace($this->clientData(), ['type' => 'lead'])); + $this->putJson('/api/leads/' . $lead->id . '/convert')->assertOk()->assertJsonPath('client.type', 'client'); + $this->assertDatabaseHas('clients', ['id' => $lead->id, 'type' => 'client', 'lead_status_id' => null]); + } + + public function test_financial_values_and_snapshots_are_removed_without_permission(): void + { + $this->authenticate(); + $this->mock(ContractService::class, function ($service) { + $service->shouldReceive('show')->once()->with('1')->andReturn([ + 'contract' => ['id' => 1, 'contract_value' => 100, 'histories' => [['contract_snapshot' => '{"profit_value":100}', 'profit_margin' => 25]]], + 'totalReceived' => 100, + ]); + }); + $response = $this->getJson('/api/contracts/1')->assertOk()->assertJsonPath('contract.id', 1); + $this->assertArrayNotHasKey('contract_value', $response->json('contract')); + $this->assertArrayNotHasKey('contract_snapshot', $response->json('contract.histories.0')); + $this->assertArrayNotHasKey('profit_margin', $response->json('contract.histories.0')); + $this->assertArrayNotHasKey('totalReceived', $response->json()); + $this->getJson('/api/contracts/export')->assertForbidden(); + } + + public function test_financial_values_are_preserved_with_permission(): void + { + $this->authenticate(financial: true); + $this->mock(ContractService::class, function ($service) { + $service->shouldReceive('show')->once()->with('1')->andReturn(['contract' => ['contract_value' => 100]]); + }); + $this->getJson('/api/contracts/1')->assertOk()->assertJsonPath('contract.contract_value', 100); + } + + public function test_analytics_hides_financial_totals_and_series_without_summary_permission(): void + { + $this->authenticate(admin: true); + $this->mock(AnalyticalService::class, function ($service) { + $service->shouldReceive('index')->once()->andReturn([ + 'stats' => ['contagem' => 2, 'total_clients' => 1, 'total_vendas' => 100, 'total_lucro' => 80, 'total_comissao' => 20], + 'vendasMensais' => [['mes' => '2026-10', 'total' => 100]], + 'vendasPorTipo' => [['tipo' => 'Particular', 'total' => 100]], + ]); + }); + $response = $this->getJson('/api/analytics')->assertOk()->assertJsonPath('stats.contagem', 2); + foreach (['total_vendas', 'total_lucro', 'total_comissao'] as $field) { + $this->assertArrayNotHasKey($field, $response->json('stats')); + } + $this->assertArrayNotHasKey('vendasMensais', $response->json()); + $this->assertArrayNotHasKey('vendasPorTipo', $response->json()); + } + + public function test_administration_and_resources_require_permissions(): void + { + $this->authenticate(); + $this->getJson('/api/users')->assertForbidden(); + $this->postJson('/api/admin/runMigrations')->assertForbidden(); + $this->postJson('/api/admin/testEmail', ['email' => 'test@example.com'])->assertForbidden(); + $this->getJson('/api/resources/power_tiers')->assertForbidden(); + } + + public function test_resource_crud_invalidates_the_actual_lookup_cache(): void + { + $this->authenticate(resources: true); + cache()->put('power_tiers', ['stale'], 60); + $response = $this->postJson('/api/resources/power_tiers', ['name' => '3.45'])->assertCreated(); + $id = $response->json('data.id'); + $this->assertNull(cache()->get('power_tiers')); + $this->putJson('/api/resources/power_tiers/' . $id, ['name' => '6.9'])->assertOk()->assertJsonPath('data.name', '6.9'); + $this->deleteJson('/api/resources/power_tiers/' . $id)->assertOk(); + $this->assertDatabaseHas('power_tiers', ['id' => $id, 'status' => 'I']); + $this->getJson('/api/resources/unknown')->assertNotFound(); + } + + public function test_pin_hash_is_never_serialized(): void + { + $user = User::findOrFail(1); + $user->update(['pin' => Hash::make('1234')]); + $this->assertArrayNotHasKey('pin', $user->toArray()); + $this->assertArrayNotHasKey('password', $user->toArray()); + } + + public function test_password_reset_revokes_existing_tokens(): void + { + Notification::fake(); + $user = User::findOrFail(1); + $user->createToken('old'); + $this->postJson('/api/password/email', ['email' => $user->email])->assertOk(); + Notification::assertSentTo($user, \Illuminate\Auth\Notifications\ResetPassword::class); + $token = Password::createToken($user); + $this->postJson('/api/password/reset', [ + 'email' => $user->email, 'token' => $token, 'password' => 'new-secret', 'password_confirmation' => 'new-secret', + ])->assertOk(); + $this->assertTrue(Hash::check('new-secret', $user->fresh()->password)); + $this->assertDatabaseCount('personal_access_tokens', 0); + } + + public function test_updates_without_financial_permission_preserve_values_and_installments(): void + { + $user = $this->authenticate(); + $contract = \App\Models\Contract::create([ + 'client_id' => 1, 'contract_value' => 100, 'commission_value' => 10, 'profit_value' => 85, + 'chargeback' => true, 'chargeback_value' => 5, 'chargeback_date' => '2026-09-01', + ]); + $contract->installments()->create(['installment_number' => 1, 'due_date' => '2026-10-01', 'amount' => 100]); + $request = Mockery::mock(\App\Http\Requests\ContractRequest::class)->makePartial(); + $request->shouldReceive('validated')->andReturn(['notes' => 'Updated', 'contract_value' => 999, 'chargeback_value' => 999]); + $request->setUserResolver(fn () => $user); + app(ContractService::class)->update($request, (string) $contract->id); + $this->assertDatabaseHas('contracts', ['id' => $contract->id, 'contract_value' => 100, 'chargeback_value' => 5, 'notes' => 'Updated']); + $this->assertDatabaseCount('contract_installments', 1); + } + + public function test_real_admin_role_grants_access_to_system_information(): void + { + $role = \Spatie\Permission\Models\Role::create(['name' => 'admin', 'guard_name' => 'web']); + $user = User::findOrFail(1); + $user->assignRole($role); + Sanctum::actingAs($user); + $this->getJson('/api/admin/info')->assertOk()->assertJsonPath('database_driver', 'sqlite'); + $this->getJson('/api/admin/access/roles-permissions')->assertOk()->assertJsonPath('roles.0.name', 'admin'); + $this->getJson('/api/admin/access/users')->assertOk()->assertJsonPath('users.0.id', 1); + } + + public function test_all_api_routes_reference_existing_actions_and_protect_private_operations(): void + { + $public = ['api/login', 'api/password/email', 'api/password/reset']; + foreach (app('router')->getRoutes() as $route) { + if (!str_starts_with($route->uri(), 'api/')) { + continue; + } + [$controller, $method] = explode('@', $route->getAction('controller')); + $this->assertTrue(method_exists($controller, $method), $route->uri()); + if (!in_array($route->uri(), $public, true)) { + $this->assertContains('auth:sanctum', $route->gatherMiddleware(), $route->uri()); + } + } + } +} diff --git a/tests/Browser/BrowserAuthenticationTest.php b/tests/Browser/BrowserAuthenticationTest.php new file mode 100644 index 0000000..644f26b --- /dev/null +++ b/tests/Browser/BrowserAuthenticationTest.php @@ -0,0 +1,58 @@ +get('/login') + ->assertOk() + ->assertViewIs('auth.login') + ->assertSee('name="_token"', false); + + $this->assertStringContainsString('no-store', $response->headers->get('Cache-Control')); + } + + public function test_browser_login_starts_session_and_opens_dashboard_without_internal_http(): void + { + Http::preventStrayRequests(); + $this->mock(HomeService::class, function ($service) { + $service->shouldReceive('index')->once()->andReturn([ + 'clientLabels' => collect(), 'clientData' => collect(), 'activeContracts' => collect(), + 'pendingContracts' => collect(), 'upcomingRenewals' => collect(), + ]); + }); + + $this->post('/login', ['email' => 'user@example.com', 'password' => 'secret123']) + ->assertRedirect(route('home')) + ->assertSessionHas('api_token'); + + $this->get('/') + ->assertOk() + ->assertViewIs('home'); + } + + public function test_invalid_browser_credentials_return_to_login(): void + { + $this->from('/login')->post('/login', ['email' => 'user@example.com', 'password' => 'wrong']) + ->assertRedirect('/login') + ->assertSessionHas('error', 'Credenciais invalidas.'); + } + + public function test_browser_session_with_invalid_api_token_is_invalidated(): void + { + Http::preventStrayRequests(); + $this->actingAs(User::findOrFail(1))->withSession(['api_token' => 'invalid']); + + $this->get('/') + ->assertRedirect(route('login')); + + $this->assertGuest(); + } +} diff --git a/tests/Feature/ContractControllerTotalsTest.php b/tests/Feature/ContractControllerTotalsTest.php new file mode 100644 index 0000000..a34140f --- /dev/null +++ b/tests/Feature/ContractControllerTotalsTest.php @@ -0,0 +1,102 @@ +assertSame(666.66, round($totalMargin, 2)); + } + + public function test_index_totals_are_calculated_only_for_current_page(): void + { + $user = User::factory()->create(); + + $clientType = ClientType::create([ + 'description' => 'Pessoa Física', + 'code' => 'PF', + 'status' => 'A', + ]); + + $client = Clients::create([ + 'name' => 'Cliente totalizador', + 'tax_number' => '123456789', + 'address' => 'Rua Teste', + 'phone' => '912345678', + 'email' => 'cliente@example.com', + 'seller_id' => $user->id, + 'client_type_id' => $clientType->id, + ]); + + $contractType = ContractType::create([ + 'description' => 'Contrato de teste', + 'code' => 'TST', + 'status' => 'A', + ]); + + $status = ContractStatus::create([ + 'description' => 'Ativo', + 'code' => 'ACTIVE', + 'color' => '#00ff00', + ]); + + Contract::create([ + 'client_id' => $client->id, + 'code' => 'TOTAL_SUM_001', + 'contract_type_id' => $contractType->id, + 'status_id' => $status->id, + 'seller_id' => $user->id, + 'supply_type' => 'cpe', + 'contract_value' => 100, + 'commission_value' => 10, + 'profit_value' => 90, + 'contract_date' => '2025-01-01', + 'activation_date' => '2025-01-02', + 'validity' => '2025-12-31', + ]); + + Contract::create([ + 'client_id' => $client->id, + 'code' => 'TOTAL_SUM_002', + 'contract_type_id' => $contractType->id, + 'status_id' => $status->id, + 'seller_id' => $user->id, + 'supply_type' => 'cpe', + 'contract_value' => 50, + 'commission_value' => 5, + 'profit_value' => 45, + 'contract_date' => '2025-01-05', + 'activation_date' => '2025-01-06', + 'validity' => '2025-12-31', + ]); + + $controller = new ContractController(); + $response = $controller->index(new Request([ + 'per_page' => 1, + 'contract_code' => 'TOTAL_SUM_', + ])); + + $data = $response->getData(); + + $this->assertSame(50.0, (float) $data['totalPvp']); + $this->assertSame(5.0, (float) $data['totalCommission']); + $this->assertSame(45.0, (float) $data['totalMargin']); + } +} diff --git a/tests/Feature/ContractPersistenceTest.php b/tests/Feature/ContractPersistenceTest.php new file mode 100644 index 0000000..eeb7d27 --- /dev/null +++ b/tests/Feature/ContractPersistenceTest.php @@ -0,0 +1,98 @@ + $table->decimal('go_ki')->nullable()); + } + + public function test_update_persists_chargeback_and_deducts_it_from_profit(): void + { + $user = $this->authenticate(financial: true); + $contract = Contract::create([ + 'client_id' => 1, + 'contract_value' => 882.32, + 'commission_value' => 588.92, + 'profit_value' => 293.40, + 'go_ki' => 1, + ]); + + $requestData = [ + 'contract_value' => 882.32, + 'commission_value' => 588.92, + 'chargeback_value' => -935.79, + 'chargeback_date' => '2026-09-21', + 'go_ki' => 1, + ]; + $request = $this->contractRequest($requestData, $user); + + app(ContractService::class)->update($request, (string) $contract->id); + + $this->assertDatabaseHas('contracts', [ + 'id' => $contract->id, + 'chargeback' => true, + 'chargeback_value' => -935.79, + 'chargeback_date' => '2026-09-21', + 'profit_value' => -642.39, + ]); + } + + public function test_update_reports_an_error_when_model_save_is_cancelled(): void + { + $user = $this->authenticate(financial: true); + $contract = Contract::create([ + 'client_id' => 1, + 'contract_value' => 100, + 'commission_value' => 10, + 'profit_value' => 90, + 'go_ki' => 1, + ]); + Contract::saving(fn () => false); + + $requestData = [ + 'contract_value' => 100, + 'commission_value' => 10, + 'chargeback' => false, + 'go_ki' => 1, + 'notes' => 'This save must be rejected', + ]; + $request = $this->contractRequest($requestData, $user); + + try { + app(ContractService::class)->update($request, (string) $contract->id); + $this->fail('A cancelled contract save must be reported as an error.'); + } catch (ValidationException $exception) { + $this->assertArrayHasKey('contract', $exception->errors()); + } + + $this->assertDatabaseMissing('contracts', [ + 'id' => $contract->id, + 'notes' => 'This save must be rejected', + ]); + } + + private function contractRequest(array $data, object $user): ContractRequest + { + $request = ContractRequest::create('/contract/1/update', 'PUT', $data); + $request->setUserResolver(fn () => $user); + $prepareForValidation = new \ReflectionMethod(ContractRequest::class, 'prepareForValidation'); + $prepareForValidation->invoke($request); + $requestData = $request->all(); + $rules = array_fill_keys(array_keys($requestData), ['sometimes']); + $request->setValidator(app('validator')->make($requestData, $rules)); + + return $request; + } +} diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php new file mode 100644 index 0000000..0394b8a --- /dev/null +++ b/tests/Feature/ExampleTest.php @@ -0,0 +1,23 @@ +make(); + + $response = $this->actingAs($user)->get('/'); + + $response->assertStatus(200); + } +} diff --git a/tests/Feature/RoutesTest.php b/tests/Feature/RoutesTest.php new file mode 100644 index 0000000..709e050 --- /dev/null +++ b/tests/Feature/RoutesTest.php @@ -0,0 +1,51 @@ +assertNotNull($user, "User not found"); + + $authRoutes = [ + 'login', + 'register', + 'password.request', + 'password.email', + 'password.reset', + 'password.update', + 'password.confirm', + 'verification.notice', + 'verification.verify', + 'verification.send', + 'logout', + 'admin.phpinfo' + ]; + + $routes = collect(Route::getRoutes()) + ->filter(fn($route) => in_array('GET', $route->methods())) + ->filter(fn($route) => !str_contains($route->uri(), '{')) + ->filter(fn($route) => !in_array($route->getName(), $authRoutes)) + ->map(fn($route) => $route->uri()); + + foreach ($routes as $uri) { + $response = $this->actingAs($user)->get($uri); + + $this->assertTrue( + $response->getStatusCode() === 200, + "A rota [GET {$uri}] retornou {$response->getStatusCode()} em vez de 200." + ); + } + } +} diff --git a/tests/Support/IsolatedDatabaseTestCase.php b/tests/Support/IsolatedDatabaseTestCase.php new file mode 100644 index 0000000..38653b9 --- /dev/null +++ b/tests/Support/IsolatedDatabaseTestCase.php @@ -0,0 +1,118 @@ +set([ + 'database.default' => 'sqlite', 'database.connections.sqlite.database' => ':memory:', + 'cache.default' => 'array', 'session.driver' => 'array', 'hashing.bcrypt.rounds' => 4, + ]); + DB::purge('sqlite'); + + $permissionsMigration = require base_path('vendor/spatie/laravel-permission/database/migrations/create_permission_tables.php.stub'); + $permissionsMigration->up(); + Schema::create('users', function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->string('email')->unique(); + $table->string('password'); + $table->string('pin')->nullable(); + $table->boolean('can_login')->default(true); + $table->rememberToken(); + $table->timestamps(); + }); + Schema::create('personal_access_tokens', function (Blueprint $table) { + $table->id(); + $table->morphs('tokenable'); + $table->string('name'); + $table->string('token', 64)->unique(); + $table->text('abilities')->nullable(); + $table->timestamp('last_used_at')->nullable(); + $table->timestamp('expires_at')->nullable(); + $table->timestamps(); + }); + Schema::create('password_reset_tokens', function (Blueprint $table) { + $table->string('email')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + Schema::create('client_types', function (Blueprint $table) { + $table->id(); + $table->string('description'); + }); + Schema::create('clients', function (Blueprint $table) { + $table->id(); + foreach (['name', 'tax_number', 'address', 'phone', 'email', 'contact_info', 'notes', 'locality'] as $field) { + $table->string($field)->nullable(); + } + $table->unsignedBigInteger('seller_id'); + $table->unsignedBigInteger('client_type_id'); + $table->unsignedBigInteger('lead_status_id')->nullable(); + $table->string('type')->default('client'); + $table->string('status')->default('A'); + $table->timestamps(); + }); + Schema::create('contracts', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('client_id'); + $table->string('notes')->nullable(); + $table->string('delivery_email')->nullable(); + $table->decimal('contract_value')->nullable(); + $table->decimal('commission_value')->nullable(); + $table->decimal('profit_value')->nullable(); + $table->boolean('chargeback')->default(false); + $table->decimal('chargeback_value')->nullable(); + $table->date('chargeback_date')->nullable(); + $table->timestamps(); + }); + Schema::create('contract_installments', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('contract_id'); + $table->integer('installment_number'); + $table->date('due_date'); + $table->decimal('amount'); + $table->boolean('paid')->default(false); + $table->timestamps(); + }); + Schema::create('power_tiers', function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->string('status')->default('A'); + $table->timestamps(); + }); + User::create(['name' => 'Test User', 'email' => 'user@example.com', 'password' => 'secret123', 'can_login' => true]); + DB::table('client_types')->insert(['id' => 1, 'description' => 'Particular']); + } + + protected function authenticate(bool $financial = false, bool $admin = false, bool $resources = false): User + { + $user = Mockery::mock(User::class)->makePartial(); + $user->forceFill(['id' => 1, 'name' => 'Test User', 'email' => 'user@example.com', 'can_login' => true]); + $user->shouldReceive('can')->with('view_contract_summary')->andReturn($financial); + $user->shouldReceive('hasAnyRole')->andReturn($admin); + $user->shouldReceive('checkPermissionTo')->andReturn(false); + Gate::define('manage_resources', fn () => $resources); + Gate::define('view_contract_summary', fn () => $financial); + Sanctum::actingAs($user); + return $user; + } + + protected function clientData(): array + { + return ['name' => 'Client Test', 'tax_number' => '123456789', 'email' => 'client@example.com', + 'phone' => '912345678', 'address' => 'Rua Teste', 'client_type_id' => 1, 'seller_id' => 1]; + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..fe1ffc2 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,10 @@ +assertSame('2026-09-24', $this->parseDate('24/09/2026')); + } + + public function test_parse_date_returns_null_for_empty_and_invalid_date(): void + { + $this->assertNull($this->parseDate(null)); + $this->assertNull($this->parseDate('invalid')); + } + + private function parseDate(?string $date): ?string + { + $method = new ReflectionMethod(AnalyticalService::class, 'parseDate'); + + return $method->invoke(new AnalyticalService(), $date); + } +} diff --git a/tests/Unit/ClientRequestTest.php b/tests/Unit/ClientRequestTest.php new file mode 100644 index 0000000..f6b8606 --- /dev/null +++ b/tests/Unit/ClientRequestTest.php @@ -0,0 +1,42 @@ +rules(); + + $this->assertSame('required|digits:9|unique:clients,tax_number', $rules['tax_number']); + $this->assertSame('required|email', $rules['email']); + $this->assertSame('required|string|max:20', $rules['phone']); + $this->assertSame('required|exists:client_types,id', $rules['client_type_id']); + } + + public function test_update_client_request_ignores_current_client_in_tax_number_uniqueness(): void + { + $request = UpdateClientRequest::create('/clients/17', 'PUT'); + $route = new Route('PUT', '/clients/{id}', fn () => null); + $route->bind($request); + $route->setParameter('id', 17); + $request->setRouteResolver(fn () => $route); + + $this->assertSame( + 'required|digits:9|unique:clients,tax_number,17', + $request->rules()['tax_number'] + ); + } + + public function test_client_requests_return_portuguese_validation_messages(): void + { + $this->assertSame('O nome é obrigatório.', (new CreateClientRequest())->messages()['name.required']); + $this->assertSame('O NIF é obrigatório.', (new CreateClientRequest())->messages()['tax_number.required']); + $this->assertSame('O e-mail é obrigatório.', (new UpdateClientRequest())->messages()['email.required']); + } +} diff --git a/tests/Unit/ClientsTest.php b/tests/Unit/ClientsTest.php new file mode 100644 index 0000000..9882034 --- /dev/null +++ b/tests/Unit/ClientsTest.php @@ -0,0 +1,42 @@ +shouldReceive('isPaid')->once()->andReturn(true); + $unpaidCpe = Mockery::mock(CPE::class); + $unpaidCpe->shouldReceive('isPaid')->once()->andReturn(false); + + $client = new Clients(); + $client->setRelation('cpes', new Collection([$paidCpe, $unpaidCpe])); + + $this->assertTrue($client->hasUnpaidCpes()); + } + + public function test_client_without_cpes_or_with_only_paid_cpes_has_no_unpaid_cpes(): void + { + $paidCpe = Mockery::mock(CPE::class); + $paidCpe->shouldReceive('isPaid')->once()->andReturn(true); + + $client = new Clients(); + $client->setRelation('cpes', new Collection([$paidCpe])); + + $this->assertFalse($client->hasUnpaidCpes()); + } +} diff --git a/tests/Unit/ContractControllerTest.php b/tests/Unit/ContractControllerTest.php new file mode 100644 index 0000000..2820d6a --- /dev/null +++ b/tests/Unit/ContractControllerTest.php @@ -0,0 +1,123 @@ +shouldReceive('where')->once()->with('id', 42)->andReturnSelf(); + $query->shouldReceive('where')->once()->with('status_id', 3)->andReturnSelf(); + $query->shouldReceive('whereHas')->once()->with( + 'client', + Mockery::on(function (callable $callback): bool { + $clientQuery = Mockery::mock(Builder::class); + $clientQuery->shouldReceive('where')->once()->with('client_type_id', 7)->andReturnSelf(); + $callback($clientQuery); + return true; + }) + )->andReturnSelf(); + $query->shouldReceive('whereDate')->once()->with('contract_date', '>=', '2026-09-01')->andReturnSelf(); + $query->shouldReceive('orderBy')->once()->with('id', 'desc')->andReturnSelf(); + + $request = Request::create('/contracts', 'GET', [ + 'contract_id' => 42, + 'status' => 3, + 'client_type_id' => 7, + 'validity_from' => '01/09/2026', + ]); + + $this->applyFilters($query, $request); + $this->addToAssertionCount(1); + } + + public function test_iso_date_filters_are_accepted_by_contract_query(): void + { + $query = Mockery::mock(Builder::class); + $query->shouldReceive('whereDate')->once()->with('contract_date', '>=', '2026-01-01')->andReturnSelf(); + $query->shouldReceive('orderBy')->once()->with('id', 'desc')->andReturnSelf(); + + $request = Request::create('/contracts', 'GET', [ + 'validity_from' => '2026-01-01', + ]); + + $this->applyFilters($query, $request); + $this->addToAssertionCount(1); + } + + public function test_invalid_sort_column_uses_activation_date_fallback(): void + { + $query = Mockery::mock(Builder::class); + $query->shouldReceive('orderBy')->once()->with('activation_date', 'desc')->andReturnSelf(); + + $request = Request::create('/contracts', 'GET', [ + 'sort_by' => 'contract_value', + 'order' => 'invalid', + ]); + + $this->applyFilters($query, $request); + $this->addToAssertionCount(1); + } + + public function test_history_update_rules_exclude_financial_fields_without_summary_permission(): void + { + $user = new class { + public function can(string $permission): bool + { + return false; + } + }; + + $request = Request::create('/contracts/1/history/2', 'PUT', [ + 'validity' => '2026-09-24', + 'notes' => 'Atualização sem permissão', + ]); + $request->setUserResolver(fn () => $user); + + $method = new ReflectionMethod(ContractService::class, 'getHistoryUpdateRules'); + $rules = $method->invoke(new ContractService(), $request); + + $this->assertArrayNotHasKey('contract_value', $rules); + $this->assertArrayNotHasKey('commission_value', $rules); + $this->assertArrayNotHasKey('profit_value', $rules); + $this->assertArrayHasKey('notes', $rules); + } + + public function test_edit_options_include_current_legacy_value_without_mutating_cached_options(): void + { + $activeOption = new ContractType(); + $activeOption->id = 1; + $legacyOption = new ContractType(); + $legacyOption->id = 2; + $options = new Collection([$activeOption]); + + $method = new ReflectionMethod(ContractService::class, 'includeCurrentOption'); + $editOptions = $method->invoke(new ContractService(), $options, $legacyOption); + + $this->assertCount(1, $options); + $this->assertCount(2, $editOptions); + $this->assertTrue($editOptions->contains(fn (ContractType $option) => $option->is($legacyOption))); + } + + private function applyFilters(Builder $query, Request $request): void + { + $method = new ReflectionMethod(ContractService::class, '_applyFilters'); + $method->invoke(new ContractService(), $query, $request); + } +} diff --git a/tests/Unit/ContractHistoryTest.php b/tests/Unit/ContractHistoryTest.php new file mode 100644 index 0000000..dde50a6 --- /dev/null +++ b/tests/Unit/ContractHistoryTest.php @@ -0,0 +1,25 @@ + '24/09/2026']); + + $this->assertSame('2026-09-24', $history->getAttributes()['validity']); + } + + public function test_validity_accepts_iso_dates_and_invalid_values_become_null(): void + { + $history = new ContractHistory(['validity' => '2026-09-24']); + $this->assertSame('2026-09-24', $history->getAttributes()['validity']); + + $history->validity = 'invalid'; + $this->assertNull($history->getAttributes()['validity']); + } +} diff --git a/tests/Unit/ContractRequestTest.php b/tests/Unit/ContractRequestTest.php new file mode 100644 index 0000000..f670e4f --- /dev/null +++ b/tests/Unit/ContractRequestTest.php @@ -0,0 +1,70 @@ +setUserResolver(fn () => null); + $rules = $request->rules(); + + $this->assertContains('required', $rules['client_id']); + $this->assertContains('required', $rules['supply_type']); + $this->assertContains('required', $rules['contract_type_id']); + $this->assertContains('required', $rules['status_id']); + $this->assertContains('required', $rules['payment_method_id']); + $this->assertContains('required', $rules['go_ki']); + $this->assertContains('numeric', $rules['go_ki']); + $this->assertContains('in:correio,email', $rules['delivery_method']); + } + + public function test_contract_request_removes_financial_rules_without_summary_permission(): void + { + $user = new class { + public function can(string $permission): bool + { + return false; + } + }; + + $request = new ContractRequest(); + $request->setUserResolver(fn () => $user); + $rules = $request->rules(); + + $this->assertArrayNotHasKey('contract_value', $rules); + $this->assertArrayNotHasKey('commission_value', $rules); + $this->assertArrayNotHasKey('installments.*.amount', $rules); + } + + public function test_contract_request_normalizes_iso_and_portuguese_dates_to_iso(): void + { + $request = ContractRequest::create('/contracts/1', 'PUT', [ + 'contract_date' => '2026-10-12', + 'activation_date' => '12/10/2026', + ]); + + $prepareForValidation = new ReflectionMethod(ContractRequest::class, 'prepareForValidation'); + $prepareForValidation->invoke($request); + + $this->assertSame('2026-10-12', $request->input('contract_date')); + $this->assertSame('2026-10-12', $request->input('activation_date')); + } + + public function test_submitted_chargeback_value_activates_chargeback_flag(): void + { + $request = ContractRequest::create('/contracts/1', 'PUT', [ + 'chargeback_value' => '-935.79', + ]); + + $prepareForValidation = new ReflectionMethod(ContractRequest::class, 'prepareForValidation'); + $prepareForValidation->invoke($request); + + $this->assertTrue($request->boolean('chargeback')); + } +} diff --git a/tests/Unit/ContractScopeTest.php b/tests/Unit/ContractScopeTest.php new file mode 100644 index 0000000..60bcdd5 --- /dev/null +++ b/tests/Unit/ContractScopeTest.php @@ -0,0 +1,33 @@ +shouldReceive('where')->once()->with('type', 'cpe')->andReturnSelf(); + + $this->assertSame($query, (new Contract())->scopeCpe($query)); + } + + public function test_between_dates_scope_applies_only_provided_bounds(): void + { + $query = Mockery::mock(); + $query->shouldReceive('when')->once()->with('2026-09-01', Mockery::type('Closure'))->andReturnSelf(); + $query->shouldReceive('when')->once()->with(null, Mockery::type('Closure'))->andReturnSelf(); + + $this->assertSame($query, (new Contract())->scopeBetweenDates($query, '2026-09-01', null)); + } +} diff --git a/tests/Unit/ContractTest.php b/tests/Unit/ContractTest.php new file mode 100644 index 0000000..b9465c0 --- /dev/null +++ b/tests/Unit/ContractTest.php @@ -0,0 +1,29 @@ + '24/09/2026', + 'contract_date' => '01/10/2026', + 'validity' => '31/12/2026', + ]); + + $this->assertSame('2026-09-24', $contract->getAttributes()['activation_date']); + $this->assertSame('2026-10-01', $contract->getAttributes()['contract_date']); + $this->assertSame('2026-12-31', $contract->getAttributes()['validity']); + } + + public function test_invalid_contract_date_is_stored_as_null(): void + { + $contract = new Contract(['contract_date' => 'not-a-date']); + + $this->assertNull($contract->getAttributes()['contract_date']); + } +} diff --git a/tests/Unit/CpeTest.php b/tests/Unit/CpeTest.php new file mode 100644 index 0000000..bc2353f --- /dev/null +++ b/tests/Unit/CpeTest.php @@ -0,0 +1,46 @@ +shouldReceive('where')->once()->with('status', 'paid')->andReturnSelf(); + $payments->shouldReceive('sum')->once()->with('amount')->andReturn(125.50); + + $cpe = Mockery::mock(CPE::class)->makePartial(); + $cpe->shouldReceive('payments')->once()->andReturn($payments); + + $this->assertSame(125.50, $cpe->totalPaid()); + } + + public function test_cpe_is_paid_when_total_paid_reaches_pvp(): void + { + $cpe = Mockery::mock(CPE::class)->makePartial(); + $cpe->pvp = 100; + $cpe->shouldReceive('totalPaid')->once()->andReturn(100); + + $this->assertTrue($cpe->isPaid()); + } + + public function test_cpe_is_unpaid_when_total_paid_is_below_pvp(): void + { + $cpe = Mockery::mock(CPE::class)->makePartial(); + $cpe->pvp = 100; + $cpe->shouldReceive('totalPaid')->once()->andReturn(99.99); + + $this->assertFalse($cpe->isPaid()); + } +} diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php new file mode 100644 index 0000000..5773b0c --- /dev/null +++ b/tests/Unit/ExampleTest.php @@ -0,0 +1,16 @@ +assertTrue(true); + } +} diff --git a/tests/Unit/LeadDetailTest.php b/tests/Unit/LeadDetailTest.php new file mode 100644 index 0000000..0d5f6af --- /dev/null +++ b/tests/Unit/LeadDetailTest.php @@ -0,0 +1,32 @@ + '24/09/2026', + 'contract_end_date' => '30/09/2026', + ]); + + $this->assertSame('2026-09-24', $lead->getAttributes()['contact_date']); + $this->assertSame('2026-09-30', $lead->getAttributes()['contract_end_date']); + } + + public function test_lead_dates_are_presented_in_form_format(): void + { + $lead = new LeadDetail(); + $lead->setRawAttributes([ + 'contact_date' => '2026-09-24', + 'contract_end_date' => '2026-09-30', + ]); + + $this->assertSame('24/09/2026', $lead->contact_date); + $this->assertSame('30/09/2026', $lead->contract_end_date); + } +} diff --git a/tests/Unit/LeadRequestTest.php b/tests/Unit/LeadRequestTest.php new file mode 100644 index 0000000..1ce3c64 --- /dev/null +++ b/tests/Unit/LeadRequestTest.php @@ -0,0 +1,23 @@ +rules(); + + $this->assertSame('nullable|date_format:d/m/Y', $rules['contact_date']); + $this->assertSame('nullable|date_format:d/m/Y|after_or_equal:contact_date', $rules['contract_end_date']); + $this->assertSame('nullable|in:CPE,CUI', $rules['contract_type']); + } + + public function test_lead_name_is_required(): void + { + $this->assertSame('required|string|max:255', (new LeadRequest())->rules()['name']); + } +} diff --git a/tests/Unit/RenewContractRequestTest.php b/tests/Unit/RenewContractRequestTest.php new file mode 100644 index 0000000..b208b22 --- /dev/null +++ b/tests/Unit/RenewContractRequestTest.php @@ -0,0 +1,58 @@ + '24/09/2026', + 'contract_date' => '01/10/2026', + 'activation_date' => '02/10/2026', + ]); + + $method = new ReflectionMethod($request, 'prepareForValidation'); + $method->invoke($request); + + $this->assertSame('2026-09-24', $request->input('next_due_date')); + $this->assertSame('2026-10-01', $request->input('contract_date')); + $this->assertSame('2026-10-02', $request->input('activation_date')); + } + + public function test_financial_fields_are_not_required_without_financial_access(): void + { + $request = new RenewContractRequest(); + + $this->assertContains('required_if:change_supplier,1', $request->rules()['new_supplier_id']); + $renewalTypeRules = $request->rules()['renewal_type']; + $this->assertContains('required', $renewalTypeRules); + $this->assertInstanceOf(Exists::class, $renewalTypeRules[1]); + $this->assertContains('required', $request->rules()['contract_type_id']); + $this->assertContains('exists:contract_types,id', $request->rules()['contract_type_id']); + $this->assertContains('nullable', $request->rules()['typology_id']); + $this->assertContains('exists:typologies,id', $request->rules()['typology_id']); + $this->assertArrayNotHasKey('amount_paid', $request->rules()); + $this->assertArrayNotHasKey('commission_value', $request->rules()); + } + + public function test_financial_fields_are_validated_with_financial_access(): void + { + $request = new RenewContractRequest(); + $request->setUserResolver(fn () => new class { + public function can(string $ability): bool + { + return $ability === 'view_contract_summary'; + } + }); + + $this->assertContains('required', $request->rules()['amount_paid']); + $this->assertContains('numeric', $request->rules()['amount_paid']); + $this->assertContains('numeric', $request->rules()['commission_value']); + } +} diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..dbbf333 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite'; +import laravel from 'laravel-vite-plugin'; + +export default defineConfig({ + plugins: [ + laravel({ + input: [ + 'resources/sass/app.scss', + 'resources/js/app.js', + ], + refresh: true, + }), + ], +});