From cacafbfba096d8167be4ae63e64a251a14758ba8 Mon Sep 17 00:00:00 2001 From: Mia Winter Date: Thu, 11 Jan 2024 13:54:29 +0100 Subject: [PATCH] Initial commit --- .gitattributes | 312 +++++++ .gitignore | 854 ++++++++++++++++++ Wave.sln | 25 + ...omponentsEndpointRouteBuilderExtensions.cs | 113 +++ .../Account/IdentityNoOpEmailSender.cs | 21 + .../Account/IdentityRedirectManager.cs | 59 ++ .../Account/IdentityUserAccessor.cs | 20 + .../Account/Pages/ConfirmEmail.razor | 48 + .../Account/Pages/ConfirmEmailChange.razor | 68 ++ .../Account/Pages/ExternalLogin.razor | 195 ++++ .../Account/Pages/ForgotPassword.razor | 68 ++ .../Pages/ForgotPasswordConfirmation.razor | 8 + .../Account/Pages/InvalidPasswordReset.razor | 8 + .../Account/Pages/InvalidUser.razor | 7 + Wave/Components/Account/Pages/Lockout.razor | 8 + Wave/Components/Account/Pages/Login.razor | 128 +++ .../Account/Pages/LoginWith2fa.razor | 101 +++ .../Account/Pages/LoginWithRecoveryCode.razor | 85 ++ .../Account/Pages/Manage/ChangePassword.razor | 96 ++ .../Pages/Manage/DeletePersonalData.razor | 86 ++ .../Account/Pages/Manage/Disable2fa.razor | 64 ++ .../Account/Pages/Manage/Email.razor | 123 +++ .../Pages/Manage/EnableAuthenticator.razor | 172 ++++ .../Account/Pages/Manage/ExternalLogins.razor | 140 +++ .../Pages/Manage/GenerateRecoveryCodes.razor | 68 ++ .../Account/Pages/Manage/Index.razor | 77 ++ .../Account/Pages/Manage/PersonalData.razor | 34 + .../Pages/Manage/ResetAuthenticator.razor | 52 ++ .../Account/Pages/Manage/SetPassword.razor | 87 ++ .../Manage/TwoFactorAuthentication.razor | 101 +++ .../Account/Pages/Manage/_Imports.razor | 2 + Wave/Components/Account/Pages/Register.razor | 145 +++ .../Account/Pages/RegisterConfirmation.razor | 68 ++ .../Pages/ResendEmailConfirmation.razor | 68 ++ .../Account/Pages/ResetPassword.razor | 103 +++ .../Pages/ResetPasswordConfirmation.razor | 7 + Wave/Components/Account/Pages/_Imports.razor | 2 + .../Account/Shared/AccountLayout.razor | 28 + .../Account/Shared/ExternalLoginPicker.razor | 43 + .../Account/Shared/ManageLayout.razor | 17 + .../Account/Shared/ManageNavMenu.razor | 37 + .../Account/Shared/RedirectToLogin.razor | 8 + .../Account/Shared/ShowRecoveryCodes.razor | 28 + .../Account/Shared/StatusMessage.razor | 29 + Wave/Components/App.razor | 20 + Wave/Components/Layout/MainLayout.razor | 17 + Wave/Components/Layout/MainLayout.razor.css | 96 ++ Wave/Components/Layout/NavMenu.razor | 86 ++ Wave/Components/Layout/NavMenu.razor.css | 125 +++ Wave/Components/Pages/Auth.razor | 13 + Wave/Components/Pages/Error.razor | 36 + Wave/Components/Pages/Home.razor | 7 + Wave/Components/Pages/Weather.razor | 64 ++ Wave/Components/Routes.razor | 11 + Wave/Components/_Imports.razor | 11 + Wave/Data/ApplicationDbContext.cs | 9 + Wave/Data/ApplicationUser.cs | 10 + ...000000000_CreateIdentitySchema.Designer.cs | 279 ++++++ .../00000000000000_CreateIdentitySchema.cs | 224 +++++ .../ApplicationDbContextModelSnapshot.cs | 276 ++++++ Wave/Program.cs | 59 ++ Wave/Properties/launchSettings.json | 29 + Wave/Properties/serviceDependencies.json | 8 + .../Properties/serviceDependencies.local.json | 8 + Wave/Wave.csproj | 17 + Wave/appsettings.Development.json | 8 + Wave/appsettings.json | 12 + Wave/wwwroot/app.css | 51 ++ Wave/wwwroot/bootstrap/bootstrap.min.css | 7 + Wave/wwwroot/bootstrap/bootstrap.min.css.map | Bin 0 -> 449111 bytes Wave/wwwroot/favicon.png | Bin 0 -> 1148 bytes 71 files changed, 5296 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Wave.sln create mode 100644 Wave/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs create mode 100644 Wave/Components/Account/IdentityNoOpEmailSender.cs create mode 100644 Wave/Components/Account/IdentityRedirectManager.cs create mode 100644 Wave/Components/Account/IdentityUserAccessor.cs create mode 100644 Wave/Components/Account/Pages/ConfirmEmail.razor create mode 100644 Wave/Components/Account/Pages/ConfirmEmailChange.razor create mode 100644 Wave/Components/Account/Pages/ExternalLogin.razor create mode 100644 Wave/Components/Account/Pages/ForgotPassword.razor create mode 100644 Wave/Components/Account/Pages/ForgotPasswordConfirmation.razor create mode 100644 Wave/Components/Account/Pages/InvalidPasswordReset.razor create mode 100644 Wave/Components/Account/Pages/InvalidUser.razor create mode 100644 Wave/Components/Account/Pages/Lockout.razor create mode 100644 Wave/Components/Account/Pages/Login.razor create mode 100644 Wave/Components/Account/Pages/LoginWith2fa.razor create mode 100644 Wave/Components/Account/Pages/LoginWithRecoveryCode.razor create mode 100644 Wave/Components/Account/Pages/Manage/ChangePassword.razor create mode 100644 Wave/Components/Account/Pages/Manage/DeletePersonalData.razor create mode 100644 Wave/Components/Account/Pages/Manage/Disable2fa.razor create mode 100644 Wave/Components/Account/Pages/Manage/Email.razor create mode 100644 Wave/Components/Account/Pages/Manage/EnableAuthenticator.razor create mode 100644 Wave/Components/Account/Pages/Manage/ExternalLogins.razor create mode 100644 Wave/Components/Account/Pages/Manage/GenerateRecoveryCodes.razor create mode 100644 Wave/Components/Account/Pages/Manage/Index.razor create mode 100644 Wave/Components/Account/Pages/Manage/PersonalData.razor create mode 100644 Wave/Components/Account/Pages/Manage/ResetAuthenticator.razor create mode 100644 Wave/Components/Account/Pages/Manage/SetPassword.razor create mode 100644 Wave/Components/Account/Pages/Manage/TwoFactorAuthentication.razor create mode 100644 Wave/Components/Account/Pages/Manage/_Imports.razor create mode 100644 Wave/Components/Account/Pages/Register.razor create mode 100644 Wave/Components/Account/Pages/RegisterConfirmation.razor create mode 100644 Wave/Components/Account/Pages/ResendEmailConfirmation.razor create mode 100644 Wave/Components/Account/Pages/ResetPassword.razor create mode 100644 Wave/Components/Account/Pages/ResetPasswordConfirmation.razor create mode 100644 Wave/Components/Account/Pages/_Imports.razor create mode 100644 Wave/Components/Account/Shared/AccountLayout.razor create mode 100644 Wave/Components/Account/Shared/ExternalLoginPicker.razor create mode 100644 Wave/Components/Account/Shared/ManageLayout.razor create mode 100644 Wave/Components/Account/Shared/ManageNavMenu.razor create mode 100644 Wave/Components/Account/Shared/RedirectToLogin.razor create mode 100644 Wave/Components/Account/Shared/ShowRecoveryCodes.razor create mode 100644 Wave/Components/Account/Shared/StatusMessage.razor create mode 100644 Wave/Components/App.razor create mode 100644 Wave/Components/Layout/MainLayout.razor create mode 100644 Wave/Components/Layout/MainLayout.razor.css create mode 100644 Wave/Components/Layout/NavMenu.razor create mode 100644 Wave/Components/Layout/NavMenu.razor.css create mode 100644 Wave/Components/Pages/Auth.razor create mode 100644 Wave/Components/Pages/Error.razor create mode 100644 Wave/Components/Pages/Home.razor create mode 100644 Wave/Components/Pages/Weather.razor create mode 100644 Wave/Components/Routes.razor create mode 100644 Wave/Components/_Imports.razor create mode 100644 Wave/Data/ApplicationDbContext.cs create mode 100644 Wave/Data/ApplicationUser.cs create mode 100644 Wave/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs create mode 100644 Wave/Data/Migrations/00000000000000_CreateIdentitySchema.cs create mode 100644 Wave/Data/Migrations/ApplicationDbContextModelSnapshot.cs create mode 100644 Wave/Program.cs create mode 100644 Wave/Properties/launchSettings.json create mode 100644 Wave/Properties/serviceDependencies.json create mode 100644 Wave/Properties/serviceDependencies.local.json create mode 100644 Wave/Wave.csproj create mode 100644 Wave/appsettings.Development.json create mode 100644 Wave/appsettings.json create mode 100644 Wave/wwwroot/app.css create mode 100644 Wave/wwwroot/bootstrap/bootstrap.min.css create mode 100644 Wave/wwwroot/bootstrap/bootstrap.min.css.map create mode 100644 Wave/wwwroot/favicon.png diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7827dec --- /dev/null +++ b/.gitattributes @@ -0,0 +1,312 @@ +# Common settings that generally should always be used with your language specific settings + +# Auto detect text files and perform LF normalization +* text=auto + +# +# The above will handle all files NOT found below +# + +# Documents +*.bibtex text diff=bibtex +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain +*.md text diff=markdown +*.mdx text diff=markdown +*.tex text diff=tex +*.adoc text +*.textile text +*.mustache text +*.csv text eol=crlf +*.tab text +*.tsv text +*.txt text +*.sql text +*.epub diff=astextplain + +# Graphics +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.tif binary +*.tiff binary +*.ico binary +# SVG treated as text by default. +*.svg text +# If you want to treat it as binary, +# use the following line instead. +# *.svg binary +*.eps binary + +# Scripts +*.bash text eol=lf +*.fish text eol=lf +*.sh text eol=lf +*.zsh text eol=lf +# These are explicitly windows files and should use crlf +*.bat text eol=crlf +*.cmd text eol=crlf +*.ps1 text eol=crlf + +# Serialisation +*.json text +*.toml text +*.xml text +*.yaml text +*.yml text + +# Archives +*.7z binary +*.gz binary +*.tar binary +*.tgz binary +*.zip binary + +# Text files where line endings should be preserved +*.patch -text + +# +# Exclude files from exporting +# + +.gitattributes export-ignore +.gitignore export-ignore +.gitkeep export-ignore +# Auto detect text files and perform LF normalization +* text=auto + +*.cs text diff=csharp +*.cshtml text diff=html +*.csx text diff=csharp +*.sln text eol=crlf +*.csproj text eol=crlf +# Apply override to all files in the directory +*.md linguist-detectable +# Basic .gitattributes for sql files + +*.sql linguist-detectable=true +*.sql linguist-language=sql +## GITATTRIBUTES FOR WEB PROJECTS +# +# These settings are for any web project. +# +# Details per file setting: +# text These files should be normalized (i.e. convert CRLF to LF). +# binary These files are binary and should be left untouched. +# +# Note that binary is a macro for -text -diff. +###################################################################### + +# Auto detect +## Handle line endings automatically for files detected as +## text and leave all files detected as binary untouched. +## This will handle all files NOT defined below. +* text=auto + +# Source code +*.bash text eol=lf +*.bat text eol=crlf +*.cmd text eol=crlf +*.coffee text +*.css text diff=css +*.htm text diff=html +*.html text diff=html +*.inc text +*.ini text +*.js text +*.json text +*.jsx text +*.less text +*.ls text +*.map text -diff +*.od text +*.onlydata text +*.php text diff=php +*.pl text +*.ps1 text eol=crlf +*.py text diff=python +*.rb text diff=ruby +*.sass text +*.scm text +*.scss text diff=css +*.sh text eol=lf +.husky/* text eol=lf +*.sql text +*.styl text +*.tag text +*.ts text +*.tsx text +*.xml text +*.xhtml text diff=html + +# Docker +Dockerfile text + +# Documentation +*.ipynb text eol=lf +*.markdown text diff=markdown +*.md text diff=markdown +*.mdwn text diff=markdown +*.mdown text diff=markdown +*.mkd text diff=markdown +*.mkdn text diff=markdown +*.mdtxt text +*.mdtext text +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +copyright text +*COPYRIGHT* text +INSTALL text +license text +LICENSE text +NEWS text +readme text +*README* text +TODO text + +# Templates +*.dot text +*.ejs text +*.erb text +*.haml text +*.handlebars text +*.hbs text +*.hbt text +*.jade text +*.latte text +*.mustache text +*.njk text +*.phtml text +*.svelte text +*.tmpl text +*.tpl text +*.twig text +*.vue text + +# Configs +*.cnf text +*.conf text +*.config text +.editorconfig text +.env text +.gitattributes text +.gitconfig text +.htaccess text +*.lock text -diff +package.json text eol=lf +package-lock.json text eol=lf -diff +pnpm-lock.yaml text eol=lf -diff +.prettierrc text +yarn.lock text -diff +*.toml text +*.yaml text +*.yml text +browserslist text +Makefile text +makefile text +# Fixes syntax highlighting on GitHub to allow comments +tsconfig.json linguist-language=JSON-with-Comments + +# Heroku +Procfile text + +# Graphics +*.ai binary +*.bmp binary +*.eps binary +*.gif binary +*.gifv binary +*.ico binary +*.jng binary +*.jp2 binary +*.jpg binary +*.jpeg binary +*.jpx binary +*.jxr binary +*.pdf binary +*.png binary +*.psb binary +*.psd binary +# SVG treated as an asset (binary) by default. +*.svg text +# If you want to treat it as binary, +# use the following line instead. +# *.svg binary +*.svgz binary +*.tif binary +*.tiff binary +*.wbmp binary +*.webp binary + +# Audio +*.kar binary +*.m4a binary +*.mid binary +*.midi binary +*.mp3 binary +*.ogg binary +*.ra binary + +# Video +*.3gpp binary +*.3gp binary +*.as binary +*.asf binary +*.asx binary +*.avi binary +*.fla binary +*.flv binary +*.m4v binary +*.mng binary +*.mov binary +*.mp4 binary +*.mpeg binary +*.mpg binary +*.ogv binary +*.swc binary +*.swf binary +*.webm binary + +# Archives +*.7z binary +*.gz binary +*.jar binary +*.rar binary +*.tar binary +*.zip binary + +# Fonts +*.ttf binary +*.eot binary +*.otf binary +*.woff binary +*.woff2 binary + +# Executables +*.exe binary +*.pyc binary +# Prevents massive diffs caused by vendored, minified files +**/.yarn/releases/** binary +**/.yarn/plugins/** binary + +# RC files (like .babelrc or .eslintrc) +*.*rc text + +# Ignore files (like .npmignore or .gitignore) +*.*ignore text + +# Prevents massive diffs from built files +dist/* binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0de545 --- /dev/null +++ b/.gitignore @@ -0,0 +1,854 @@ +# Created by https://www.toptal.com/developers/gitignore/api/visualstudio,csharp,dotnetcore,aspnetcore,node +# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudio,csharp,dotnetcore,aspnetcore,node + +### ASPNETCore ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/ + +### Csharp ### +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser + +# User-specific files (MonoDevelop/Xamarin Studio) + +# Mono auto generated files +mono_crash.* + +# Build results +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +# Uncomment if you have tasks that create the project's static files in wwwroot + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results + +# NUnit +nunit-*.xml + +# Build Results of an ATL Project + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_h.h +*.iobj +*.ipdb +*_wpftmp.csproj +*.tlog + +# Chutzpah Test files + +# Visual C++ cache files + +# Visual Studio profiler + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace + +# Guidance Automation Toolkit + +# ReSharper is a .NET coding add-in + +# TeamCity is a build add-in + +# DotCover is a Code Coverage Tool + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results + +# NCrunch + +# MightyMoose + +# Web workbench (sass) + +# Installshield output folder + +# DocProject is a documentation generator add-in + +# Click-Once directory + +# Publish Web Output +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted + +# NuGet Packages +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files + +# Microsoft Azure Build Output + +# Microsoft Azure Emulator + +# Windows Store app package directories and files +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) + +# RIA/Silverlight projects + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.ndf + +# Business Intelligence projects +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes + +# GhostDoc plugin setting file + +# Node.js Tools for Visual Studio + +# Visual Studio 6 build log + +# Visual Studio 6 workspace options file + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files + +# Visual Studio LightSwitch build output + +# Paket dependency manager + +# FAKE - F# Make + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider + +### DotnetCore ### +# .NET Core build folders +bin/ +obj/ + +# Common node modules locations +/node_modules +/wwwroot/node_modules + +### Node ### +# Logs +logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +### VisualStudio ### + +# User-specific files + +# User-specific files (MonoDevelop/Xamarin Studio) + +# Mono auto generated files + +# Build results + +# Visual Studio 2015/2017 cache/options directory +# Uncomment if you have tasks that create the project's static files in wwwroot + +# Visual Studio 2017 auto generated files + +# MSTest test Results + +# NUnit + +# Build Results of an ATL Project + +# Benchmark Results + +# .NET Core + +# ASP.NET Scaffolding + +# StyleCop + +# Files built by Visual Studio + +# Chutzpah Test files + +# Visual C++ cache files + +# Visual Studio profiler + +# Visual Studio Trace Files + +# TFS 2012 Local Workspace + +# Guidance Automation Toolkit + +# ReSharper is a .NET coding add-in + +# TeamCity is a build add-in + +# DotCover is a Code Coverage Tool + +# AxoCover is a Code Coverage Tool + +# Coverlet is a free, cross platform Code Coverage Tool + +# Visual Studio code coverage results + +# NCrunch + +# MightyMoose + +# Web workbench (sass) + +# Installshield output folder + +# DocProject is a documentation generator add-in + +# Click-Once directory + +# Publish Web Output +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted + +# NuGet Packages +# NuGet Symbol Packages +# The packages folder can be ignored because of Package Restore +# except build/, which is used as an MSBuild target. +# Uncomment if necessary however generally it will be regenerated when needed +# NuGet v3's project.json files produces more ignorable files + +# Microsoft Azure Build Output + +# Microsoft Azure Emulator + +# Windows Store app package directories and files + +# Visual Studio cache files +# files ending in .cache can be ignored +# but keep track of directories ending in .cache + +# Others + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) + +# RIA/Silverlight projects + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) + +# SQL Server files + +# Business Intelligence projects + +# Microsoft Fakes + +# GhostDoc plugin setting file + +# Node.js Tools for Visual Studio + +# Visual Studio 6 build log + +# Visual Studio 6 workspace options file + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) + +# Visual Studio 6 technical files + +# Visual Studio LightSwitch build output + +# Paket dependency manager + +# FAKE - F# Make + +# CodeRush personal settings + +# Python Tools for Visual Studio (PTVS) + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio + +# Telerik's JustMock configuration file + +# BizTalk build output + +# OpenCover UI analysis results + +# Azure Stream Analytics local run output + +# MSBuild Binary and Structured Log + +# NVidia Nsight GPU debugger configuration file + +# MFractors (Xamarin productivity tool) working folder + +# Local History for Visual Studio + +# Visual Studio History (VSHistory) files + +# BeatPulse healthcheck temp database + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 + +# Ionide (cross platform F# VS Code tools) working folder + +# Fody - auto-generated XML schema + +# VS Code files for those working on multiple tools + +# Local History for Visual Studio Code + +# Windows Installer files from build outputs + +# JetBrains Rider + +### VisualStudio Patch ### +# Additional files built by Visual Studio + +# End of https://www.toptal.com/developers/gitignore/api/visualstudio,csharp,dotnetcore,aspnetcore,node diff --git a/Wave.sln b/Wave.sln new file mode 100644 index 0000000..c661dc9 --- /dev/null +++ b/Wave.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34414.90 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wave", "Wave\Wave.csproj", "{F4CB9B92-89E6-457D-BC06-4469AD2EC51D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F4CB9B92-89E6-457D-BC06-4469AD2EC51D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F4CB9B92-89E6-457D-BC06-4469AD2EC51D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F4CB9B92-89E6-457D-BC06-4469AD2EC51D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F4CB9B92-89E6-457D-BC06-4469AD2EC51D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1BF5D88C-9BD0-45FB-9F55-A6FA12B1A308} + EndGlobalSection +EndGlobal diff --git a/Wave/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs b/Wave/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs new file mode 100644 index 0000000..aa300d4 --- /dev/null +++ b/Wave/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs @@ -0,0 +1,113 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Primitives; +using System.Security.Claims; +using System.Text.Json; +using Wave.Components.Account.Pages; +using Wave.Components.Account.Pages.Manage; +using Wave.Data; + +namespace Microsoft.AspNetCore.Routing +{ + internal static class IdentityComponentsEndpointRouteBuilderExtensions + { + // These endpoints are required by the Identity Razor components defined in the /Components/Account/Pages directory of this project. + public static IEndpointConventionBuilder MapAdditionalIdentityEndpoints(this IEndpointRouteBuilder endpoints) + { + ArgumentNullException.ThrowIfNull(endpoints); + + var accountGroup = endpoints.MapGroup("/Account"); + + accountGroup.MapPost("/PerformExternalLogin", ( + HttpContext context, + [FromServices] SignInManager signInManager, + [FromForm] string provider, + [FromForm] string returnUrl) => + { + IEnumerable> query = [ + new("ReturnUrl", returnUrl), + new("Action", ExternalLogin.LoginCallbackAction)]; + + var redirectUrl = UriHelper.BuildRelative( + context.Request.PathBase, + "/Account/ExternalLogin", + QueryString.Create(query)); + + var properties = signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); + return TypedResults.Challenge(properties, [provider]); + }); + + accountGroup.MapPost("/Logout", async ( + ClaimsPrincipal user, + SignInManager signInManager, + [FromForm] string returnUrl) => + { + await signInManager.SignOutAsync(); + return TypedResults.LocalRedirect($"~/{returnUrl}"); + }); + + var manageGroup = accountGroup.MapGroup("/Manage").RequireAuthorization(); + + manageGroup.MapPost("/LinkExternalLogin", async ( + HttpContext context, + [FromServices] SignInManager signInManager, + [FromForm] string provider) => + { + // Clear the existing external cookie to ensure a clean login process + await context.SignOutAsync(IdentityConstants.ExternalScheme); + + var redirectUrl = UriHelper.BuildRelative( + context.Request.PathBase, + "/Account/Manage/ExternalLogins", + QueryString.Create("Action", ExternalLogins.LinkLoginCallbackAction)); + + var properties = signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, signInManager.UserManager.GetUserId(context.User)); + return TypedResults.Challenge(properties, [provider]); + }); + + var loggerFactory = endpoints.ServiceProvider.GetRequiredService(); + var downloadLogger = loggerFactory.CreateLogger("DownloadPersonalData"); + + manageGroup.MapPost("/DownloadPersonalData", async ( + HttpContext context, + [FromServices] UserManager userManager, + [FromServices] AuthenticationStateProvider authenticationStateProvider) => + { + var user = await userManager.GetUserAsync(context.User); + if (user is null) + { + return Results.NotFound($"Unable to load user with ID '{userManager.GetUserId(context.User)}'."); + } + + var userId = await userManager.GetUserIdAsync(user); + downloadLogger.LogInformation("User with ID '{UserId}' asked for their personal data.", userId); + + // Only include personal data for download + var personalData = new Dictionary(); + var personalDataProps = typeof(ApplicationUser).GetProperties().Where( + prop => Attribute.IsDefined(prop, typeof(PersonalDataAttribute))); + foreach (var p in personalDataProps) + { + personalData.Add(p.Name, p.GetValue(user)?.ToString() ?? "null"); + } + + var logins = await userManager.GetLoginsAsync(user); + foreach (var l in logins) + { + personalData.Add($"{l.LoginProvider} external login provider key", l.ProviderKey); + } + + personalData.Add("Authenticator Key", (await userManager.GetAuthenticatorKeyAsync(user))!); + var fileBytes = JsonSerializer.SerializeToUtf8Bytes(personalData); + + context.Response.Headers.TryAdd("Content-Disposition", "attachment; filename=PersonalData.json"); + return TypedResults.File(fileBytes, contentType: "application/json", fileDownloadName: "PersonalData.json"); + }); + + return accountGroup; + } + } +} diff --git a/Wave/Components/Account/IdentityNoOpEmailSender.cs b/Wave/Components/Account/IdentityNoOpEmailSender.cs new file mode 100644 index 0000000..6184224 --- /dev/null +++ b/Wave/Components/Account/IdentityNoOpEmailSender.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; +using Wave.Data; + +namespace Wave.Components.Account +{ + // Remove the "else if (EmailSender is IdentityNoOpEmailSender)" block from RegisterConfirmation.razor after updating with a real implementation. + internal sealed class IdentityNoOpEmailSender : IEmailSender + { + private readonly IEmailSender emailSender = new NoOpEmailSender(); + + public Task SendConfirmationLinkAsync(ApplicationUser user, string email, string confirmationLink) => + emailSender.SendEmailAsync(email, "Confirm your email", $"Please confirm your account by clicking here."); + + public Task SendPasswordResetLinkAsync(ApplicationUser user, string email, string resetLink) => + emailSender.SendEmailAsync(email, "Reset your password", $"Please reset your password by clicking here."); + + public Task SendPasswordResetCodeAsync(ApplicationUser user, string email, string resetCode) => + emailSender.SendEmailAsync(email, "Reset your password", $"Please reset your password using the following code: {resetCode}"); + } +} diff --git a/Wave/Components/Account/IdentityRedirectManager.cs b/Wave/Components/Account/IdentityRedirectManager.cs new file mode 100644 index 0000000..b5abc9e --- /dev/null +++ b/Wave/Components/Account/IdentityRedirectManager.cs @@ -0,0 +1,59 @@ +using Microsoft.AspNetCore.Components; +using System.Diagnostics.CodeAnalysis; + +namespace Wave.Components.Account +{ + internal sealed class IdentityRedirectManager(NavigationManager navigationManager) + { + public const string StatusCookieName = "Identity.StatusMessage"; + + private static readonly CookieBuilder StatusCookieBuilder = new() + { + SameSite = SameSiteMode.Strict, + HttpOnly = true, + IsEssential = true, + MaxAge = TimeSpan.FromSeconds(5), + }; + + [DoesNotReturn] + public void RedirectTo(string? uri) + { + uri ??= ""; + + // Prevent open redirects. + if (!Uri.IsWellFormedUriString(uri, UriKind.Relative)) + { + uri = navigationManager.ToBaseRelativePath(uri); + } + + // During static rendering, NavigateTo throws a NavigationException which is handled by the framework as a redirect. + // So as long as this is called from a statically rendered Identity component, the InvalidOperationException is never thrown. + navigationManager.NavigateTo(uri); + throw new InvalidOperationException($"{nameof(IdentityRedirectManager)} can only be used during static rendering."); + } + + [DoesNotReturn] + public void RedirectTo(string uri, Dictionary queryParameters) + { + var uriWithoutQuery = navigationManager.ToAbsoluteUri(uri).GetLeftPart(UriPartial.Path); + var newUri = navigationManager.GetUriWithQueryParameters(uriWithoutQuery, queryParameters); + RedirectTo(newUri); + } + + [DoesNotReturn] + public void RedirectToWithStatus(string uri, string message, HttpContext context) + { + context.Response.Cookies.Append(StatusCookieName, message, StatusCookieBuilder.Build(context)); + RedirectTo(uri); + } + + private string CurrentPath => navigationManager.ToAbsoluteUri(navigationManager.Uri).GetLeftPart(UriPartial.Path); + + [DoesNotReturn] + public void RedirectToCurrentPage() => RedirectTo(CurrentPath); + + [DoesNotReturn] + public void RedirectToCurrentPageWithStatus(string message, HttpContext context) + => RedirectToWithStatus(CurrentPath, message, context); + } +} diff --git a/Wave/Components/Account/IdentityUserAccessor.cs b/Wave/Components/Account/IdentityUserAccessor.cs new file mode 100644 index 0000000..9f54db9 --- /dev/null +++ b/Wave/Components/Account/IdentityUserAccessor.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Identity; +using Wave.Data; + +namespace Wave.Components.Account +{ + internal sealed class IdentityUserAccessor(UserManager userManager, IdentityRedirectManager redirectManager) + { + public async Task GetRequiredUserAsync(HttpContext context) + { + var user = await userManager.GetUserAsync(context.User); + + if (user is null) + { + redirectManager.RedirectToWithStatus("Account/InvalidUser", $"Error: Unable to load user with ID '{userManager.GetUserId(context.User)}'.", context); + } + + return user; + } + } +} diff --git a/Wave/Components/Account/Pages/ConfirmEmail.razor b/Wave/Components/Account/Pages/ConfirmEmail.razor new file mode 100644 index 0000000..2100d34 --- /dev/null +++ b/Wave/Components/Account/Pages/ConfirmEmail.razor @@ -0,0 +1,48 @@ +@page "/Account/ConfirmEmail" + +@using System.Text +@using Microsoft.AspNetCore.Identity +@using Microsoft.AspNetCore.WebUtilities +@using Wave.Data + +@inject UserManager UserManager +@inject IdentityRedirectManager RedirectManager + +Confirm email + +

Confirm email

+ + +@code { + private string? statusMessage; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromQuery] + private string? UserId { get; set; } + + [SupplyParameterFromQuery] + private string? Code { get; set; } + + protected override async Task OnInitializedAsync() + { + if (UserId is null || Code is null) + { + RedirectManager.RedirectTo(""); + } + + var user = await UserManager.FindByIdAsync(UserId); + if (user is null) + { + HttpContext.Response.StatusCode = StatusCodes.Status404NotFound; + statusMessage = $"Error loading user with ID {UserId}"; + } + else + { + var code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Code)); + var result = await UserManager.ConfirmEmailAsync(user, code); + statusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email."; + } + } +} diff --git a/Wave/Components/Account/Pages/ConfirmEmailChange.razor b/Wave/Components/Account/Pages/ConfirmEmailChange.razor new file mode 100644 index 0000000..ee27b26 --- /dev/null +++ b/Wave/Components/Account/Pages/ConfirmEmailChange.razor @@ -0,0 +1,68 @@ +@page "/Account/ConfirmEmailChange" + +@using System.Text +@using Microsoft.AspNetCore.Identity +@using Microsoft.AspNetCore.WebUtilities +@using Wave.Data + +@inject UserManager UserManager +@inject SignInManager SignInManager +@inject IdentityRedirectManager RedirectManager + +Confirm email change + +

Confirm email change

+ + + +@code { + private string? message; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromQuery] + private string? UserId { get; set; } + + [SupplyParameterFromQuery] + private string? Email { get; set; } + + [SupplyParameterFromQuery] + private string? Code { get; set; } + + protected override async Task OnInitializedAsync() + { + if (UserId is null || Email is null || Code is null) + { + RedirectManager.RedirectToWithStatus( + "Account/Login", "Error: Invalid email change confirmation link.", HttpContext); + } + + var user = await UserManager.FindByIdAsync(UserId); + if (user is null) + { + message = "Unable to find user with Id '{userId}'"; + return; + } + + var code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Code)); + var result = await UserManager.ChangeEmailAsync(user, Email, code); + if (!result.Succeeded) + { + message = "Error changing email."; + return; + } + + // In our UI email and user name are one and the same, so when we update the email + // we need to update the user name. + var setUserNameResult = await UserManager.SetUserNameAsync(user, Email); + if (!setUserNameResult.Succeeded) + { + message = "Error changing user name."; + return; + } + + await SignInManager.RefreshSignInAsync(user); + message = "Thank you for confirming your email change."; + } +} diff --git a/Wave/Components/Account/Pages/ExternalLogin.razor b/Wave/Components/Account/Pages/ExternalLogin.razor new file mode 100644 index 0000000..a35b66c --- /dev/null +++ b/Wave/Components/Account/Pages/ExternalLogin.razor @@ -0,0 +1,195 @@ +@page "/Account/ExternalLogin" + +@using System.ComponentModel.DataAnnotations +@using System.Security.Claims +@using System.Text +@using System.Text.Encodings.Web +@using Microsoft.AspNetCore.Identity +@using Microsoft.AspNetCore.WebUtilities +@using Wave.Data + +@inject SignInManager SignInManager +@inject UserManager UserManager +@inject IUserStore UserStore +@inject IEmailSender EmailSender +@inject NavigationManager NavigationManager +@inject IdentityRedirectManager RedirectManager +@inject ILogger Logger + +Register + + +

Register

+

Associate your @ProviderDisplayName account.

+
+ +
+ You've successfully authenticated with @ProviderDisplayName. + Please enter an email address for this site below and click the Register button to finish + logging in. +
+ +
+
+ + + +
+ + + +
+ +
+
+
+ +@code { + public const string LoginCallbackAction = "LoginCallback"; + + private string? message; + private ExternalLoginInfo externalLoginInfo = default!; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + [SupplyParameterFromQuery] + private string? RemoteError { get; set; } + + [SupplyParameterFromQuery] + private string? ReturnUrl { get; set; } + + [SupplyParameterFromQuery] + private string? Action { get; set; } + + private string? ProviderDisplayName => externalLoginInfo.ProviderDisplayName; + + protected override async Task OnInitializedAsync() + { + if (RemoteError is not null) + { + RedirectManager.RedirectToWithStatus("Account/Login", $"Error from external provider: {RemoteError}", HttpContext); + } + + var info = await SignInManager.GetExternalLoginInfoAsync(); + if (info is null) + { + RedirectManager.RedirectToWithStatus("Account/Login", "Error loading external login information.", HttpContext); + } + + externalLoginInfo = info; + + if (HttpMethods.IsGet(HttpContext.Request.Method)) + { + if (Action == LoginCallbackAction) + { + await OnLoginCallbackAsync(); + return; + } + + // We should only reach this page via the login callback, so redirect back to + // the login page if we get here some other way. + RedirectManager.RedirectTo("Account/Login"); + } + } + + private async Task OnLoginCallbackAsync() + { + // Sign in the user with this external login provider if the user already has a login. + var result = await SignInManager.ExternalLoginSignInAsync( + externalLoginInfo.LoginProvider, + externalLoginInfo.ProviderKey, + isPersistent: false, + bypassTwoFactor: true); + + if (result.Succeeded) + { + Logger.LogInformation( + "{Name} logged in with {LoginProvider} provider.", + externalLoginInfo.Principal.Identity?.Name, + externalLoginInfo.LoginProvider); + RedirectManager.RedirectTo(ReturnUrl); + } + else if (result.IsLockedOut) + { + RedirectManager.RedirectTo("Account/Lockout"); + } + + // If the user does not have an account, then ask the user to create an account. + if (externalLoginInfo.Principal.HasClaim(c => c.Type == ClaimTypes.Email)) + { + Input.Email = externalLoginInfo.Principal.FindFirstValue(ClaimTypes.Email) ?? ""; + } + } + + private async Task OnValidSubmitAsync() + { + var emailStore = GetEmailStore(); + var user = CreateUser(); + + await UserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None); + await emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None); + + var result = await UserManager.CreateAsync(user); + if (result.Succeeded) + { + result = await UserManager.AddLoginAsync(user, externalLoginInfo); + if (result.Succeeded) + { + Logger.LogInformation("User created an account using {Name} provider.", externalLoginInfo.LoginProvider); + + var userId = await UserManager.GetUserIdAsync(user); + var code = await UserManager.GenerateEmailConfirmationTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + + var callbackUrl = NavigationManager.GetUriWithQueryParameters( + NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, + new Dictionary { ["userId"] = userId, ["code"] = code }); + await EmailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); + + // If account confirmation is required, we need to show the link if we don't have a real email sender + if (UserManager.Options.SignIn.RequireConfirmedAccount) + { + RedirectManager.RedirectTo("Account/RegisterConfirmation", new() { ["email"] = Input.Email }); + } + + await SignInManager.SignInAsync(user, isPersistent: false, externalLoginInfo.LoginProvider); + RedirectManager.RedirectTo(ReturnUrl); + } + } + + message = $"Error: {string.Join(",", result.Errors.Select(error => error.Description))}"; + } + + private ApplicationUser CreateUser() + { + try + { + return Activator.CreateInstance(); + } + catch + { + throw new InvalidOperationException($"Can't create an instance of '{nameof(ApplicationUser)}'. " + + $"Ensure that '{nameof(ApplicationUser)}' is not an abstract class and has a parameterless constructor"); + } + } + + private IUserEmailStore GetEmailStore() + { + if (!UserManager.SupportsUserEmail) + { + throw new NotSupportedException("The default UI requires a user store with email support."); + } + return (IUserEmailStore)UserStore; + } + + private sealed class InputModel + { + [Required] + [EmailAddress] + public string Email { get; set; } = ""; + } +} diff --git a/Wave/Components/Account/Pages/ForgotPassword.razor b/Wave/Components/Account/Pages/ForgotPassword.razor new file mode 100644 index 0000000..87ed0a4 --- /dev/null +++ b/Wave/Components/Account/Pages/ForgotPassword.razor @@ -0,0 +1,68 @@ +@page "/Account/ForgotPassword" + +@using System.ComponentModel.DataAnnotations +@using System.Text +@using System.Text.Encodings.Web +@using Microsoft.AspNetCore.Identity +@using Microsoft.AspNetCore.WebUtilities +@using Wave.Data + +@inject UserManager UserManager +@inject IEmailSender EmailSender +@inject NavigationManager NavigationManager +@inject IdentityRedirectManager RedirectManager + +Forgot your password? + +

Forgot your password?

+

Enter your email.

+
+
+
+ + + + +
+ + + +
+ +
+
+
+ +@code { + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + private async Task OnValidSubmitAsync() + { + var user = await UserManager.FindByEmailAsync(Input.Email); + if (user is null || !(await UserManager.IsEmailConfirmedAsync(user))) + { + // Don't reveal that the user does not exist or is not confirmed + RedirectManager.RedirectTo("Account/ForgotPasswordConfirmation"); + } + + // For more information on how to enable account confirmation and password reset please + // visit https://go.microsoft.com/fwlink/?LinkID=532713 + var code = await UserManager.GeneratePasswordResetTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + var callbackUrl = NavigationManager.GetUriWithQueryParameters( + NavigationManager.ToAbsoluteUri("Account/ResetPassword").AbsoluteUri, + new Dictionary { ["code"] = code }); + + await EmailSender.SendPasswordResetLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); + + RedirectManager.RedirectTo("Account/ForgotPasswordConfirmation"); + } + + private sealed class InputModel + { + [Required] + [EmailAddress] + public string Email { get; set; } = ""; + } +} diff --git a/Wave/Components/Account/Pages/ForgotPasswordConfirmation.razor b/Wave/Components/Account/Pages/ForgotPasswordConfirmation.razor new file mode 100644 index 0000000..38de01d --- /dev/null +++ b/Wave/Components/Account/Pages/ForgotPasswordConfirmation.razor @@ -0,0 +1,8 @@ +@page "/Account/ForgotPasswordConfirmation" + +Forgot password confirmation + +

Forgot password confirmation

+

+ Please check your email to reset your password. +

diff --git a/Wave/Components/Account/Pages/InvalidPasswordReset.razor b/Wave/Components/Account/Pages/InvalidPasswordReset.razor new file mode 100644 index 0000000..509578b --- /dev/null +++ b/Wave/Components/Account/Pages/InvalidPasswordReset.razor @@ -0,0 +1,8 @@ +@page "/Account/InvalidPasswordReset" + +Invalid password reset + +

Invalid password reset

+

+ The password reset link is invalid. +

diff --git a/Wave/Components/Account/Pages/InvalidUser.razor b/Wave/Components/Account/Pages/InvalidUser.razor new file mode 100644 index 0000000..e61fe5d --- /dev/null +++ b/Wave/Components/Account/Pages/InvalidUser.razor @@ -0,0 +1,7 @@ +@page "/Account/InvalidUser" + +Invalid user + +

Invalid user

+ + diff --git a/Wave/Components/Account/Pages/Lockout.razor b/Wave/Components/Account/Pages/Lockout.razor new file mode 100644 index 0000000..a8d1e0a --- /dev/null +++ b/Wave/Components/Account/Pages/Lockout.razor @@ -0,0 +1,8 @@ +@page "/Account/Lockout" + +Locked out + +
+

Locked out

+

This account has been locked out, please try again later.

+
diff --git a/Wave/Components/Account/Pages/Login.razor b/Wave/Components/Account/Pages/Login.razor new file mode 100644 index 0000000..8ef8937 --- /dev/null +++ b/Wave/Components/Account/Pages/Login.razor @@ -0,0 +1,128 @@ +@page "/Account/Login" + +@using System.ComponentModel.DataAnnotations +@using Microsoft.AspNetCore.Authentication +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject SignInManager SignInManager +@inject ILogger Logger +@inject NavigationManager NavigationManager +@inject IdentityRedirectManager RedirectManager + +Log in + +

Log in

+
+
+
+ + + +

Use a local account to log in.

+
+ +
+ + + +
+
+ + + +
+
+ +
+
+ +
+ +
+
+
+
+
+

Use another service to log in.

+
+ +
+
+
+ +@code { + private string? errorMessage; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + [SupplyParameterFromQuery] + private string? ReturnUrl { get; set; } + + protected override async Task OnInitializedAsync() + { + if (HttpMethods.IsGet(HttpContext.Request.Method)) + { + // Clear the existing external cookie to ensure a clean login process + await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); + } + } + + public async Task LoginUser() + { + // This doesn't count login failures towards account lockout + // To enable password failures to trigger account lockout, set lockoutOnFailure: true + var result = await SignInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false); + if (result.Succeeded) + { + Logger.LogInformation("User logged in."); + RedirectManager.RedirectTo(ReturnUrl); + } + else if (result.RequiresTwoFactor) + { + RedirectManager.RedirectTo( + "Account/LoginWith2fa", + new() { ["returnUrl"] = ReturnUrl, ["rememberMe"] = Input.RememberMe }); + } + else if (result.IsLockedOut) + { + Logger.LogWarning("User account locked out."); + RedirectManager.RedirectTo("Account/Lockout"); + } + else + { + errorMessage = "Error: Invalid login attempt."; + } + } + + private sealed class InputModel + { + [Required] + [EmailAddress] + public string Email { get; set; } = ""; + + [Required] + [DataType(DataType.Password)] + public string Password { get; set; } = ""; + + [Display(Name = "Remember me?")] + public bool RememberMe { get; set; } + } +} diff --git a/Wave/Components/Account/Pages/LoginWith2fa.razor b/Wave/Components/Account/Pages/LoginWith2fa.razor new file mode 100644 index 0000000..ce563c7 --- /dev/null +++ b/Wave/Components/Account/Pages/LoginWith2fa.razor @@ -0,0 +1,101 @@ +@page "/Account/LoginWith2fa" + +@using System.ComponentModel.DataAnnotations +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject SignInManager SignInManager +@inject UserManager UserManager +@inject IdentityRedirectManager RedirectManager +@inject ILogger Logger + +Two-factor authentication + +

Two-factor authentication

+
+ +

Your login is protected with an authenticator app. Enter your authenticator code below.

+
+
+ + + + + +
+ + + +
+
+ +
+
+ +
+
+
+
+

+ Don't have access to your authenticator device? You can + log in with a recovery code. +

+ +@code { + private string? message; + private ApplicationUser user = default!; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + [SupplyParameterFromQuery] + private string? ReturnUrl { get; set; } + + [SupplyParameterFromQuery] + private bool RememberMe { get; set; } + + protected override async Task OnInitializedAsync() + { + // Ensure the user has gone through the username & password screen first + user = await SignInManager.GetTwoFactorAuthenticationUserAsync() ?? + throw new InvalidOperationException("Unable to load two-factor authentication user."); + } + + private async Task OnValidSubmitAsync() + { + var authenticatorCode = Input.TwoFactorCode!.Replace(" ", string.Empty).Replace("-", string.Empty); + var result = await SignInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, RememberMe, Input.RememberMachine); + var userId = await UserManager.GetUserIdAsync(user); + + if (result.Succeeded) + { + Logger.LogInformation("User with ID '{UserId}' logged in with 2fa.", userId); + RedirectManager.RedirectTo(ReturnUrl); + } + else if (result.IsLockedOut) + { + Logger.LogWarning("User with ID '{UserId}' account locked out.", userId); + RedirectManager.RedirectTo("Account/Lockout"); + } + else + { + Logger.LogWarning("Invalid authenticator code entered for user with ID '{UserId}'.", userId); + message = "Error: Invalid authenticator code."; + } + } + + private sealed class InputModel + { + [Required] + [StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Text)] + [Display(Name = "Authenticator code")] + public string? TwoFactorCode { get; set; } + + [Display(Name = "Remember this machine")] + public bool RememberMachine { get; set; } + } +} diff --git a/Wave/Components/Account/Pages/LoginWithRecoveryCode.razor b/Wave/Components/Account/Pages/LoginWithRecoveryCode.razor new file mode 100644 index 0000000..4c06b7b --- /dev/null +++ b/Wave/Components/Account/Pages/LoginWithRecoveryCode.razor @@ -0,0 +1,85 @@ +@page "/Account/LoginWithRecoveryCode" + +@using System.ComponentModel.DataAnnotations +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject SignInManager SignInManager +@inject UserManager UserManager +@inject IdentityRedirectManager RedirectManager +@inject ILogger Logger + +Recovery code verification + +

Recovery code verification

+
+ +

+ You have requested to log in with a recovery code. This login will not be remembered until you provide + an authenticator app code at log in or disable 2FA and log in again. +

+
+
+ + + +
+ + + +
+ +
+
+
+ +@code { + private string? message; + private ApplicationUser user = default!; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + [SupplyParameterFromQuery] + private string? ReturnUrl { get; set; } + + protected override async Task OnInitializedAsync() + { + // Ensure the user has gone through the username & password screen first + user = await SignInManager.GetTwoFactorAuthenticationUserAsync() ?? + throw new InvalidOperationException("Unable to load two-factor authentication user."); + } + + private async Task OnValidSubmitAsync() + { + var recoveryCode = Input.RecoveryCode.Replace(" ", string.Empty); + + var result = await SignInManager.TwoFactorRecoveryCodeSignInAsync(recoveryCode); + + var userId = await UserManager.GetUserIdAsync(user); + + if (result.Succeeded) + { + Logger.LogInformation("User with ID '{UserId}' logged in with a recovery code.", userId); + RedirectManager.RedirectTo(ReturnUrl); + } + else if (result.IsLockedOut) + { + Logger.LogWarning("User account locked out."); + RedirectManager.RedirectTo("Account/Lockout"); + } + else + { + Logger.LogWarning("Invalid recovery code entered for user with ID '{UserId}' ", userId); + message = "Error: Invalid recovery code entered."; + } + } + + private sealed class InputModel + { + [Required] + [DataType(DataType.Text)] + [Display(Name = "Recovery Code")] + public string RecoveryCode { get; set; } = ""; + } +} diff --git a/Wave/Components/Account/Pages/Manage/ChangePassword.razor b/Wave/Components/Account/Pages/Manage/ChangePassword.razor new file mode 100644 index 0000000..b272d7b --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/ChangePassword.razor @@ -0,0 +1,96 @@ +@page "/Account/Manage/ChangePassword" + +@using System.ComponentModel.DataAnnotations +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject UserManager UserManager +@inject SignInManager SignInManager +@inject IdentityUserAccessor UserAccessor +@inject IdentityRedirectManager RedirectManager +@inject ILogger Logger + +Change password + +

Change password

+ +
+
+ + + +
+ + + +
+
+ + + +
+
+ + + +
+ +
+
+
+ +@code { + private string? message; + private ApplicationUser user = default!; + private bool hasPassword; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + protected override async Task OnInitializedAsync() + { + user = await UserAccessor.GetRequiredUserAsync(HttpContext); + hasPassword = await UserManager.HasPasswordAsync(user); + if (!hasPassword) + { + RedirectManager.RedirectTo("Account/Manage/SetPassword"); + } + } + + private async Task OnValidSubmitAsync() + { + var changePasswordResult = await UserManager.ChangePasswordAsync(user, Input.OldPassword, Input.NewPassword); + if (!changePasswordResult.Succeeded) + { + message = $"Error: {string.Join(",", changePasswordResult.Errors.Select(error => error.Description))}"; + return; + } + + await SignInManager.RefreshSignInAsync(user); + Logger.LogInformation("User changed their password successfully."); + + RedirectManager.RedirectToCurrentPageWithStatus("Your password has been changed", HttpContext); + } + + private sealed class InputModel + { + [Required] + [DataType(DataType.Password)] + [Display(Name = "Current password")] + public string OldPassword { get; set; } = ""; + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "New password")] + public string NewPassword { get; set; } = ""; + + [DataType(DataType.Password)] + [Display(Name = "Confirm new password")] + [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } = ""; + } +} diff --git a/Wave/Components/Account/Pages/Manage/DeletePersonalData.razor b/Wave/Components/Account/Pages/Manage/DeletePersonalData.razor new file mode 100644 index 0000000..02ea7af --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/DeletePersonalData.razor @@ -0,0 +1,86 @@ +@page "/Account/Manage/DeletePersonalData" + +@using System.ComponentModel.DataAnnotations +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject UserManager UserManager +@inject SignInManager SignInManager +@inject IdentityUserAccessor UserAccessor +@inject IdentityRedirectManager RedirectManager +@inject ILogger Logger + +Delete Personal Data + + + +

Delete Personal Data

+ + + +
+ + + + @if (requirePassword) + { +
+ + + +
+ } + +
+
+ +@code { + private string? message; + private ApplicationUser user = default!; + private bool requirePassword; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + protected override async Task OnInitializedAsync() + { + Input ??= new(); + user = await UserAccessor.GetRequiredUserAsync(HttpContext); + requirePassword = await UserManager.HasPasswordAsync(user); + } + + private async Task OnValidSubmitAsync() + { + if (requirePassword && !await UserManager.CheckPasswordAsync(user, Input.Password)) + { + message = "Error: Incorrect password."; + return; + } + + var result = await UserManager.DeleteAsync(user); + if (!result.Succeeded) + { + throw new InvalidOperationException("Unexpected error occurred deleting user."); + } + + await SignInManager.SignOutAsync(); + + var userId = await UserManager.GetUserIdAsync(user); + Logger.LogInformation("User with ID '{UserId}' deleted themselves.", userId); + + RedirectManager.RedirectToCurrentPage(); + } + + private sealed class InputModel + { + [DataType(DataType.Password)] + public string Password { get; set; } = ""; + } +} diff --git a/Wave/Components/Account/Pages/Manage/Disable2fa.razor b/Wave/Components/Account/Pages/Manage/Disable2fa.razor new file mode 100644 index 0000000..89a550e --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/Disable2fa.razor @@ -0,0 +1,64 @@ +@page "/Account/Manage/Disable2fa" + +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject UserManager UserManager +@inject IdentityUserAccessor UserAccessor +@inject IdentityRedirectManager RedirectManager +@inject ILogger Logger + +Disable two-factor authentication (2FA) + + +

Disable two-factor authentication (2FA)

+ + + +
+
+ + + +
+ +@code { + private ApplicationUser user = default!; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + protected override async Task OnInitializedAsync() + { + user = await UserAccessor.GetRequiredUserAsync(HttpContext); + + if (HttpMethods.IsGet(HttpContext.Request.Method) && !await UserManager.GetTwoFactorEnabledAsync(user)) + { + throw new InvalidOperationException("Cannot disable 2FA for user as it's not currently enabled."); + } + } + + private async Task OnSubmitAsync() + { + var disable2faResult = await UserManager.SetTwoFactorEnabledAsync(user, false); + if (!disable2faResult.Succeeded) + { + throw new InvalidOperationException("Unexpected error occurred disabling 2FA."); + } + + var userId = await UserManager.GetUserIdAsync(user); + Logger.LogInformation("User with ID '{UserId}' has disabled 2fa.", userId); + RedirectManager.RedirectToWithStatus( + "Account/Manage/TwoFactorAuthentication", + "2fa has been disabled. You can reenable 2fa when you setup an authenticator app", + HttpContext); + } +} diff --git a/Wave/Components/Account/Pages/Manage/Email.razor b/Wave/Components/Account/Pages/Manage/Email.razor new file mode 100644 index 0000000..8793cd9 --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/Email.razor @@ -0,0 +1,123 @@ +@page "/Account/Manage/Email" + +@using System.ComponentModel.DataAnnotations +@using System.Text +@using System.Text.Encodings.Web +@using Microsoft.AspNetCore.Identity +@using Microsoft.AspNetCore.WebUtilities +@using Wave.Data + +@inject UserManager UserManager +@inject IEmailSender EmailSender +@inject IdentityUserAccessor UserAccessor +@inject NavigationManager NavigationManager + +Manage email + +

Manage email

+ + +
+
+
+ + + + + + @if (isEmailConfirmed) + { +
+ +
+ +
+ +
+ } + else + { +
+ + + +
+ } +
+ + + +
+ +
+
+
+ +@code { + private string? message; + private ApplicationUser user = default!; + private string? email; + private bool isEmailConfirmed; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromForm(FormName = "change-email")] + private InputModel Input { get; set; } = new(); + + protected override async Task OnInitializedAsync() + { + user = await UserAccessor.GetRequiredUserAsync(HttpContext); + email = await UserManager.GetEmailAsync(user); + isEmailConfirmed = await UserManager.IsEmailConfirmedAsync(user); + + Input.NewEmail ??= email; + } + + private async Task OnValidSubmitAsync() + { + if (Input.NewEmail is null || Input.NewEmail == email) + { + message = "Your email is unchanged."; + return; + } + + var userId = await UserManager.GetUserIdAsync(user); + var code = await UserManager.GenerateChangeEmailTokenAsync(user, Input.NewEmail); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + var callbackUrl = NavigationManager.GetUriWithQueryParameters( + NavigationManager.ToAbsoluteUri("Account/ConfirmEmailChange").AbsoluteUri, + new Dictionary { ["userId"] = userId, ["email"] = Input.NewEmail, ["code"] = code }); + + await EmailSender.SendConfirmationLinkAsync(user, Input.NewEmail, HtmlEncoder.Default.Encode(callbackUrl)); + + message = "Confirmation link to change email sent. Please check your email."; + } + + private async Task OnSendEmailVerificationAsync() + { + if (email is null) + { + return; + } + + var userId = await UserManager.GetUserIdAsync(user); + var code = await UserManager.GenerateEmailConfirmationTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + var callbackUrl = NavigationManager.GetUriWithQueryParameters( + NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, + new Dictionary { ["userId"] = userId, ["code"] = code }); + + await EmailSender.SendConfirmationLinkAsync(user, email, HtmlEncoder.Default.Encode(callbackUrl)); + + message = "Verification email sent. Please check your email."; + } + + private sealed class InputModel + { + [Required] + [EmailAddress] + [Display(Name = "New email")] + public string? NewEmail { get; set; } + } +} diff --git a/Wave/Components/Account/Pages/Manage/EnableAuthenticator.razor b/Wave/Components/Account/Pages/Manage/EnableAuthenticator.razor new file mode 100644 index 0000000..50e22fd --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/EnableAuthenticator.razor @@ -0,0 +1,172 @@ +@page "/Account/Manage/EnableAuthenticator" + +@using System.ComponentModel.DataAnnotations +@using System.Globalization +@using System.Text +@using System.Text.Encodings.Web +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject UserManager UserManager +@inject IdentityUserAccessor UserAccessor +@inject UrlEncoder UrlEncoder +@inject IdentityRedirectManager RedirectManager +@inject ILogger Logger + +Configure authenticator app + +@if (recoveryCodes is not null) +{ + +} +else +{ + +

Configure authenticator app

+
+

To use an authenticator app go through the following steps:

+
    +
  1. +

    + Download a two-factor authenticator app like Microsoft Authenticator for + Android and + iOS or + Google Authenticator for + Android and + iOS. +

    +
  2. +
  3. +

    Scan the QR Code or enter this key @sharedKey into your two factor authenticator app. Spaces and casing do not matter.

    + +
    +
    +
  4. +
  5. +

    + Once you have scanned the QR code or input the key above, your two factor authentication app will provide you + with a unique code. Enter the code in the confirmation box below. +

    +
    +
    + + +
    + + + +
    + + +
    +
    +
    +
  6. +
+
+} + +@code { + private const string AuthenticatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6"; + + private string? message; + private ApplicationUser user = default!; + private string? sharedKey; + private string? authenticatorUri; + private IEnumerable? recoveryCodes; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + protected override async Task OnInitializedAsync() + { + user = await UserAccessor.GetRequiredUserAsync(HttpContext); + + await LoadSharedKeyAndQrCodeUriAsync(user); + } + + private async Task OnValidSubmitAsync() + { + // Strip spaces and hyphens + var verificationCode = Input.Code.Replace(" ", string.Empty).Replace("-", string.Empty); + + var is2faTokenValid = await UserManager.VerifyTwoFactorTokenAsync( + user, UserManager.Options.Tokens.AuthenticatorTokenProvider, verificationCode); + + if (!is2faTokenValid) + { + message = "Error: Verification code is invalid."; + return; + } + + await UserManager.SetTwoFactorEnabledAsync(user, true); + var userId = await UserManager.GetUserIdAsync(user); + Logger.LogInformation("User with ID '{UserId}' has enabled 2FA with an authenticator app.", userId); + + message = "Your authenticator app has been verified."; + + if (await UserManager.CountRecoveryCodesAsync(user) == 0) + { + recoveryCodes = await UserManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10); + } + else + { + RedirectManager.RedirectToWithStatus("Account/Manage/TwoFactorAuthentication", message, HttpContext); + } + } + + private async ValueTask LoadSharedKeyAndQrCodeUriAsync(ApplicationUser user) + { + // Load the authenticator key & QR code URI to display on the form + var unformattedKey = await UserManager.GetAuthenticatorKeyAsync(user); + if (string.IsNullOrEmpty(unformattedKey)) + { + await UserManager.ResetAuthenticatorKeyAsync(user); + unformattedKey = await UserManager.GetAuthenticatorKeyAsync(user); + } + + sharedKey = FormatKey(unformattedKey!); + + var email = await UserManager.GetEmailAsync(user); + authenticatorUri = GenerateQrCodeUri(email!, unformattedKey!); + } + + private string FormatKey(string unformattedKey) + { + var result = new StringBuilder(); + int currentPosition = 0; + while (currentPosition + 4 < unformattedKey.Length) + { + result.Append(unformattedKey.AsSpan(currentPosition, 4)).Append(' '); + currentPosition += 4; + } + if (currentPosition < unformattedKey.Length) + { + result.Append(unformattedKey.AsSpan(currentPosition)); + } + + return result.ToString().ToLowerInvariant(); + } + + private string GenerateQrCodeUri(string email, string unformattedKey) + { + return string.Format( + CultureInfo.InvariantCulture, + AuthenticatorUriFormat, + UrlEncoder.Encode("Microsoft.AspNetCore.Identity.UI"), + UrlEncoder.Encode(email), + unformattedKey); + } + + private sealed class InputModel + { + [Required] + [StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Text)] + [Display(Name = "Verification Code")] + public string Code { get; set; } = ""; + } +} diff --git a/Wave/Components/Account/Pages/Manage/ExternalLogins.razor b/Wave/Components/Account/Pages/Manage/ExternalLogins.razor new file mode 100644 index 0000000..72e0a85 --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/ExternalLogins.razor @@ -0,0 +1,140 @@ +@page "/Account/Manage/ExternalLogins" + +@using Microsoft.AspNetCore.Authentication +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject UserManager UserManager +@inject SignInManager SignInManager +@inject IdentityUserAccessor UserAccessor +@inject IUserStore UserStore +@inject IdentityRedirectManager RedirectManager + +Manage your external logins + + +@if (currentLogins?.Count > 0) +{ +

Registered Logins

+ + + @foreach (var login in currentLogins) + { + + + + + } + +
@login.ProviderDisplayName + @if (showRemoveButton) + { +
+ +
+ + + +
+ + } + else + { + @:   + } +
+} +@if (otherLogins?.Count > 0) +{ +

Add another service to log in.

+
+
+ +
+

+ @foreach (var provider in otherLogins) + { + + } +

+
+ +} + +@code { + public const string LinkLoginCallbackAction = "LinkLoginCallback"; + + private ApplicationUser user = default!; + private IList? currentLogins; + private IList? otherLogins; + private bool showRemoveButton; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromForm] + private string? LoginProvider { get; set; } + + [SupplyParameterFromForm] + private string? ProviderKey { get; set; } + + [SupplyParameterFromQuery] + private string? Action { get; set; } + + protected override async Task OnInitializedAsync() + { + user = await UserAccessor.GetRequiredUserAsync(HttpContext); + currentLogins = await UserManager.GetLoginsAsync(user); + otherLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()) + .Where(auth => currentLogins.All(ul => auth.Name != ul.LoginProvider)) + .ToList(); + + string? passwordHash = null; + if (UserStore is IUserPasswordStore userPasswordStore) + { + passwordHash = await userPasswordStore.GetPasswordHashAsync(user, HttpContext.RequestAborted); + } + + showRemoveButton = passwordHash is not null || currentLogins.Count > 1; + + if (HttpMethods.IsGet(HttpContext.Request.Method) && Action == LinkLoginCallbackAction) + { + await OnGetLinkLoginCallbackAsync(); + } + } + + private async Task OnSubmitAsync() + { + var result = await UserManager.RemoveLoginAsync(user, LoginProvider!, ProviderKey!); + if (!result.Succeeded) + { + RedirectManager.RedirectToCurrentPageWithStatus("Error: The external login was not removed.", HttpContext); + } + + await SignInManager.RefreshSignInAsync(user); + RedirectManager.RedirectToCurrentPageWithStatus("The external login was removed.", HttpContext); + } + + private async Task OnGetLinkLoginCallbackAsync() + { + var userId = await UserManager.GetUserIdAsync(user); + var info = await SignInManager.GetExternalLoginInfoAsync(userId); + if (info is null) + { + RedirectManager.RedirectToCurrentPageWithStatus("Error: Could not load external login info.", HttpContext); + } + + var result = await UserManager.AddLoginAsync(user, info); + if (!result.Succeeded) + { + RedirectManager.RedirectToCurrentPageWithStatus("Error: The external login was not added. External logins can only be associated with one account.", HttpContext); + } + + // Clear the existing external cookie to ensure a clean login process + await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); + + RedirectManager.RedirectToCurrentPageWithStatus("The external login was added.", HttpContext); + } +} diff --git a/Wave/Components/Account/Pages/Manage/GenerateRecoveryCodes.razor b/Wave/Components/Account/Pages/Manage/GenerateRecoveryCodes.razor new file mode 100644 index 0000000..7ac5c9e --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/GenerateRecoveryCodes.razor @@ -0,0 +1,68 @@ +@page "/Account/Manage/GenerateRecoveryCodes" + +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject UserManager UserManager +@inject IdentityUserAccessor UserAccessor +@inject IdentityRedirectManager RedirectManager +@inject ILogger Logger + +Generate two-factor authentication (2FA) recovery codes + +@if (recoveryCodes is not null) +{ + +} +else +{ +

Generate two-factor authentication (2FA) recovery codes

+ +
+
+ + + +
+} + +@code { + private string? message; + private ApplicationUser user = default!; + private IEnumerable? recoveryCodes; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + protected override async Task OnInitializedAsync() + { + user = await UserAccessor.GetRequiredUserAsync(HttpContext); + + var isTwoFactorEnabled = await UserManager.GetTwoFactorEnabledAsync(user); + if (!isTwoFactorEnabled) + { + throw new InvalidOperationException("Cannot generate recovery codes for user because they do not have 2FA enabled."); + } + } + + private async Task OnSubmitAsync() + { + var userId = await UserManager.GetUserIdAsync(user); + recoveryCodes = await UserManager.GenerateNewTwoFactorRecoveryCodesAsync(user, 10); + message = "You have generated new recovery codes."; + + Logger.LogInformation("User with ID '{UserId}' has generated new 2FA recovery codes.", userId); + } +} diff --git a/Wave/Components/Account/Pages/Manage/Index.razor b/Wave/Components/Account/Pages/Manage/Index.razor new file mode 100644 index 0000000..634f5a5 --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/Index.razor @@ -0,0 +1,77 @@ +@page "/Account/Manage" + +@using System.ComponentModel.DataAnnotations +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject UserManager UserManager +@inject SignInManager SignInManager +@inject IdentityUserAccessor UserAccessor +@inject IdentityRedirectManager RedirectManager + +Profile + +

Profile

+ + +
+
+ + + +
+ + +
+
+ + + +
+ +
+
+
+ +@code { + private ApplicationUser user = default!; + private string? username; + private string? phoneNumber; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + protected override async Task OnInitializedAsync() + { + user = await UserAccessor.GetRequiredUserAsync(HttpContext); + username = await UserManager.GetUserNameAsync(user); + phoneNumber = await UserManager.GetPhoneNumberAsync(user); + + Input.PhoneNumber ??= phoneNumber; + } + + private async Task OnValidSubmitAsync() + { + if (Input.PhoneNumber != phoneNumber) + { + var setPhoneResult = await UserManager.SetPhoneNumberAsync(user, Input.PhoneNumber); + if (!setPhoneResult.Succeeded) + { + RedirectManager.RedirectToCurrentPageWithStatus("Error: Failed to set phone number.", HttpContext); + } + } + + await SignInManager.RefreshSignInAsync(user); + RedirectManager.RedirectToCurrentPageWithStatus("Your profile has been updated", HttpContext); + } + + private sealed class InputModel + { + [Phone] + [Display(Name = "Phone number")] + public string? PhoneNumber { get; set; } + } +} diff --git a/Wave/Components/Account/Pages/Manage/PersonalData.razor b/Wave/Components/Account/Pages/Manage/PersonalData.razor new file mode 100644 index 0000000..851eb54 --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/PersonalData.razor @@ -0,0 +1,34 @@ +@page "/Account/Manage/PersonalData" + +@inject IdentityUserAccessor UserAccessor + +Personal Data + + +

Personal Data

+ +
+
+

Your account contains personal data that you have given us. This page allows you to download or delete that data.

+

+ Deleting this data will permanently remove your account, and this cannot be recovered. +

+
+ + + +

+ Delete +

+
+
+ +@code { + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + protected override async Task OnInitializedAsync() + { + _ = await UserAccessor.GetRequiredUserAsync(HttpContext); + } +} diff --git a/Wave/Components/Account/Pages/Manage/ResetAuthenticator.razor b/Wave/Components/Account/Pages/Manage/ResetAuthenticator.razor new file mode 100644 index 0000000..30d8a8e --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/ResetAuthenticator.razor @@ -0,0 +1,52 @@ +@page "/Account/Manage/ResetAuthenticator" + +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject UserManager UserManager +@inject SignInManager SignInManager +@inject IdentityUserAccessor UserAccessor +@inject IdentityRedirectManager RedirectManager +@inject ILogger Logger + +Reset authenticator key + + +

Reset authenticator key

+ +
+
+ + + +
+ +@code { + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + private async Task OnSubmitAsync() + { + var user = await UserAccessor.GetRequiredUserAsync(HttpContext); + await UserManager.SetTwoFactorEnabledAsync(user, false); + await UserManager.ResetAuthenticatorKeyAsync(user); + var userId = await UserManager.GetUserIdAsync(user); + Logger.LogInformation("User with ID '{UserId}' has reset their authentication app key.", userId); + + await SignInManager.RefreshSignInAsync(user); + + RedirectManager.RedirectToWithStatus( + "Account/Manage/EnableAuthenticator", + "Your authenticator app key has been reset, you will need to configure your authenticator app using the new key.", + HttpContext); + } +} diff --git a/Wave/Components/Account/Pages/Manage/SetPassword.razor b/Wave/Components/Account/Pages/Manage/SetPassword.razor new file mode 100644 index 0000000..196d766 --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/SetPassword.razor @@ -0,0 +1,87 @@ +@page "/Account/Manage/SetPassword" + +@using System.ComponentModel.DataAnnotations +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject UserManager UserManager +@inject SignInManager SignInManager +@inject IdentityUserAccessor UserAccessor +@inject IdentityRedirectManager RedirectManager + +Set password + +

Set your password

+ +

+ You do not have a local username/password for this site. Add a local + account so you can log in without an external login. +

+
+
+ + + +
+ + + +
+
+ + + +
+ +
+
+
+ +@code { + private string? message; + private ApplicationUser user = default!; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + protected override async Task OnInitializedAsync() + { + user = await UserAccessor.GetRequiredUserAsync(HttpContext); + + var hasPassword = await UserManager.HasPasswordAsync(user); + if (hasPassword) + { + RedirectManager.RedirectTo("Account/Manage/ChangePassword"); + } + } + + private async Task OnValidSubmitAsync() + { + var addPasswordResult = await UserManager.AddPasswordAsync(user, Input.NewPassword!); + if (!addPasswordResult.Succeeded) + { + message = $"Error: {string.Join(",", addPasswordResult.Errors.Select(error => error.Description))}"; + return; + } + + await SignInManager.RefreshSignInAsync(user); + RedirectManager.RedirectToCurrentPageWithStatus("Your password has been set.", HttpContext); + } + + private sealed class InputModel + { + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "New password")] + public string? NewPassword { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm new password")] + [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] + public string? ConfirmPassword { get; set; } + } +} diff --git a/Wave/Components/Account/Pages/Manage/TwoFactorAuthentication.razor b/Wave/Components/Account/Pages/Manage/TwoFactorAuthentication.razor new file mode 100644 index 0000000..c9d3e58 --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/TwoFactorAuthentication.razor @@ -0,0 +1,101 @@ +@page "/Account/Manage/TwoFactorAuthentication" + +@using Microsoft.AspNetCore.Http.Features +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject UserManager UserManager +@inject SignInManager SignInManager +@inject IdentityUserAccessor UserAccessor +@inject IdentityRedirectManager RedirectManager + +Two-factor authentication (2FA) + + +

Two-factor authentication (2FA)

+@if (canTrack) +{ + if (is2faEnabled) + { + if (recoveryCodesLeft == 0) + { +
+ You have no recovery codes left. +

You must generate a new set of recovery codes before you can log in with a recovery code.

+
+ } + else if (recoveryCodesLeft == 1) + { +
+ You have 1 recovery code left. +

You can generate a new set of recovery codes.

+
+ } + else if (recoveryCodesLeft <= 3) + { +
+ You have @recoveryCodesLeft recovery codes left. +

You should generate a new set of recovery codes.

+
+ } + + if (isMachineRemembered) + { +
+ + + + } + + Disable 2FA + Reset recovery codes + } + +

Authenticator app

+ @if (!hasAuthenticator) + { + Add authenticator app + } + else + { + Set up authenticator app + Reset authenticator app + } +} +else +{ +
+ Privacy and cookie policy have not been accepted. +

You must accept the policy before you can enable two factor authentication.

+
+} + +@code { + private bool canTrack; + private bool hasAuthenticator; + private int recoveryCodesLeft; + private bool is2faEnabled; + private bool isMachineRemembered; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + protected override async Task OnInitializedAsync() + { + var user = await UserAccessor.GetRequiredUserAsync(HttpContext); + canTrack = HttpContext.Features.Get()?.CanTrack ?? true; + hasAuthenticator = await UserManager.GetAuthenticatorKeyAsync(user) is not null; + is2faEnabled = await UserManager.GetTwoFactorEnabledAsync(user); + isMachineRemembered = await SignInManager.IsTwoFactorClientRememberedAsync(user); + recoveryCodesLeft = await UserManager.CountRecoveryCodesAsync(user); + } + + private async Task OnSubmitForgetBrowserAsync() + { + await SignInManager.ForgetTwoFactorClientAsync(); + + RedirectManager.RedirectToCurrentPageWithStatus( + "The current browser has been forgotten. When you login again from this browser you will be prompted for your 2fa code.", + HttpContext); + } +} diff --git a/Wave/Components/Account/Pages/Manage/_Imports.razor b/Wave/Components/Account/Pages/Manage/_Imports.razor new file mode 100644 index 0000000..ada5bb0 --- /dev/null +++ b/Wave/Components/Account/Pages/Manage/_Imports.razor @@ -0,0 +1,2 @@ +@layout ManageLayout +@attribute [Microsoft.AspNetCore.Authorization.Authorize] diff --git a/Wave/Components/Account/Pages/Register.razor b/Wave/Components/Account/Pages/Register.razor new file mode 100644 index 0000000..8cd227f --- /dev/null +++ b/Wave/Components/Account/Pages/Register.razor @@ -0,0 +1,145 @@ +@page "/Account/Register" + +@using System.ComponentModel.DataAnnotations +@using System.Text +@using System.Text.Encodings.Web +@using Microsoft.AspNetCore.Identity +@using Microsoft.AspNetCore.WebUtilities +@using Wave.Data + +@inject UserManager UserManager +@inject IUserStore UserStore +@inject SignInManager SignInManager +@inject IEmailSender EmailSender +@inject ILogger Logger +@inject NavigationManager NavigationManager +@inject IdentityRedirectManager RedirectManager + +Register + +

Register

+ +
+
+ + + +

Create a new account.

+
+ +
+ + + +
+
+ + + +
+
+ + + +
+ +
+
+
+
+

Use another service to register.

+
+ +
+
+
+ +@code { + private IEnumerable? identityErrors; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + [SupplyParameterFromQuery] + private string? ReturnUrl { get; set; } + + private string? Message => identityErrors is null ? null : $"Error: {string.Join(", ", identityErrors.Select(error => error.Description))}"; + + public async Task RegisterUser(EditContext editContext) + { + var user = CreateUser(); + + await UserStore.SetUserNameAsync(user, Input.Email, CancellationToken.None); + var emailStore = GetEmailStore(); + await emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None); + var result = await UserManager.CreateAsync(user, Input.Password); + + if (!result.Succeeded) + { + identityErrors = result.Errors; + return; + } + + Logger.LogInformation("User created a new account with password."); + + var userId = await UserManager.GetUserIdAsync(user); + var code = await UserManager.GenerateEmailConfirmationTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + var callbackUrl = NavigationManager.GetUriWithQueryParameters( + NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, + new Dictionary { ["userId"] = userId, ["code"] = code, ["returnUrl"] = ReturnUrl }); + + await EmailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); + + if (UserManager.Options.SignIn.RequireConfirmedAccount) + { + RedirectManager.RedirectTo( + "Account/RegisterConfirmation", + new() { ["email"] = Input.Email, ["returnUrl"] = ReturnUrl }); + } + + await SignInManager.SignInAsync(user, isPersistent: false); + RedirectManager.RedirectTo(ReturnUrl); + } + + private ApplicationUser CreateUser() + { + try + { + return Activator.CreateInstance(); + } + catch + { + throw new InvalidOperationException($"Can't create an instance of '{nameof(ApplicationUser)}'. " + + $"Ensure that '{nameof(ApplicationUser)}' is not an abstract class and has a parameterless constructor."); + } + } + + private IUserEmailStore GetEmailStore() + { + if (!UserManager.SupportsUserEmail) + { + throw new NotSupportedException("The default UI requires a user store with email support."); + } + return (IUserEmailStore)UserStore; + } + + private sealed class InputModel + { + [Required] + [EmailAddress] + [Display(Name = "Email")] + public string Email { get; set; } = ""; + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string Password { get; set; } = ""; + + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } = ""; + } +} diff --git a/Wave/Components/Account/Pages/RegisterConfirmation.razor b/Wave/Components/Account/Pages/RegisterConfirmation.razor new file mode 100644 index 0000000..d31b6ef --- /dev/null +++ b/Wave/Components/Account/Pages/RegisterConfirmation.razor @@ -0,0 +1,68 @@ +@page "/Account/RegisterConfirmation" + +@using System.Text +@using Microsoft.AspNetCore.Identity +@using Microsoft.AspNetCore.WebUtilities +@using Wave.Data + +@inject UserManager UserManager +@inject IEmailSender EmailSender +@inject NavigationManager NavigationManager +@inject IdentityRedirectManager RedirectManager + +Register confirmation + +

Register confirmation

+ + + +@if (emailConfirmationLink is not null) +{ +

+ This app does not currently have a real email sender registered, see these docs for how to configure a real email sender. + Normally this would be emailed: Click here to confirm your account +

+} +else +{ +

Please check your email to confirm your account.

+} + +@code { + private string? emailConfirmationLink; + private string? statusMessage; + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + [SupplyParameterFromQuery] + private string? Email { get; set; } + + [SupplyParameterFromQuery] + private string? ReturnUrl { get; set; } + + protected override async Task OnInitializedAsync() + { + if (Email is null) + { + RedirectManager.RedirectTo(""); + } + + var user = await UserManager.FindByEmailAsync(Email); + if (user is null) + { + HttpContext.Response.StatusCode = StatusCodes.Status404NotFound; + statusMessage = "Error finding user for unspecified email"; + } + else if (EmailSender is IdentityNoOpEmailSender) + { + // Once you add a real email sender, you should remove this code that lets you confirm the account + var userId = await UserManager.GetUserIdAsync(user); + var code = await UserManager.GenerateEmailConfirmationTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + emailConfirmationLink = NavigationManager.GetUriWithQueryParameters( + NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, + new Dictionary { ["userId"] = userId, ["code"] = code, ["returnUrl"] = ReturnUrl }); + } + } +} diff --git a/Wave/Components/Account/Pages/ResendEmailConfirmation.razor b/Wave/Components/Account/Pages/ResendEmailConfirmation.razor new file mode 100644 index 0000000..30dfb0f --- /dev/null +++ b/Wave/Components/Account/Pages/ResendEmailConfirmation.razor @@ -0,0 +1,68 @@ +@page "/Account/ResendEmailConfirmation" + +@using System.ComponentModel.DataAnnotations +@using System.Text +@using System.Text.Encodings.Web +@using Microsoft.AspNetCore.Identity +@using Microsoft.AspNetCore.WebUtilities +@using Wave.Data + +@inject UserManager UserManager +@inject IEmailSender EmailSender +@inject NavigationManager NavigationManager +@inject IdentityRedirectManager RedirectManager + +Resend email confirmation + +

Resend email confirmation

+

Enter your email.

+
+ +
+
+ + + +
+ + + +
+ +
+
+
+ +@code { + private string? message; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + private async Task OnValidSubmitAsync() + { + var user = await UserManager.FindByEmailAsync(Input.Email!); + if (user is null) + { + message = "Verification email sent. Please check your email."; + return; + } + + var userId = await UserManager.GetUserIdAsync(user); + var code = await UserManager.GenerateEmailConfirmationTokenAsync(user); + code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); + var callbackUrl = NavigationManager.GetUriWithQueryParameters( + NavigationManager.ToAbsoluteUri("Account/ConfirmEmail").AbsoluteUri, + new Dictionary { ["userId"] = userId, ["code"] = code }); + await EmailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); + + message = "Verification email sent. Please check your email."; + } + + private sealed class InputModel + { + [Required] + [EmailAddress] + public string Email { get; set; } = ""; + } +} diff --git a/Wave/Components/Account/Pages/ResetPassword.razor b/Wave/Components/Account/Pages/ResetPassword.razor new file mode 100644 index 0000000..9592fe8 --- /dev/null +++ b/Wave/Components/Account/Pages/ResetPassword.razor @@ -0,0 +1,103 @@ +@page "/Account/ResetPassword" + +@using System.ComponentModel.DataAnnotations +@using System.Text +@using Microsoft.AspNetCore.Identity +@using Microsoft.AspNetCore.WebUtilities +@using Wave.Data + +@inject IdentityRedirectManager RedirectManager +@inject UserManager UserManager + +Reset password + +

Reset password

+

Reset your password.

+
+
+
+ + + + + + +
+ + + +
+
+ + + +
+
+ + + +
+ +
+
+
+ +@code { + private IEnumerable? identityErrors; + + [SupplyParameterFromForm] + private InputModel Input { get; set; } = new(); + + [SupplyParameterFromQuery] + private string? Code { get; set; } + + private string? Message => identityErrors is null ? null : $"Error: {string.Join(", ", identityErrors.Select(error => error.Description))}"; + + protected override void OnInitialized() + { + if (Code is null) + { + RedirectManager.RedirectTo("Account/InvalidPasswordReset"); + } + + Input.Code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(Code)); + } + + private async Task OnValidSubmitAsync() + { + var user = await UserManager.FindByEmailAsync(Input.Email); + if (user is null) + { + // Don't reveal that the user does not exist + RedirectManager.RedirectTo("Account/ResetPasswordConfirmation"); + } + + var result = await UserManager.ResetPasswordAsync(user, Input.Code, Input.Password); + if (result.Succeeded) + { + RedirectManager.RedirectTo("Account/ResetPasswordConfirmation"); + } + + identityErrors = result.Errors; + } + + private sealed class InputModel + { + [Required] + [EmailAddress] + public string Email { get; set; } = ""; + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + public string Password { get; set; } = ""; + + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string ConfirmPassword { get; set; } = ""; + + [Required] + public string Code { get; set; } = ""; + } +} diff --git a/Wave/Components/Account/Pages/ResetPasswordConfirmation.razor b/Wave/Components/Account/Pages/ResetPasswordConfirmation.razor new file mode 100644 index 0000000..7f7347d --- /dev/null +++ b/Wave/Components/Account/Pages/ResetPasswordConfirmation.razor @@ -0,0 +1,7 @@ +@page "/Account/ResetPasswordConfirmation" +Reset password confirmation + +

Reset password confirmation

+

+ Your password has been reset. Please click here to log in. +

diff --git a/Wave/Components/Account/Pages/_Imports.razor b/Wave/Components/Account/Pages/_Imports.razor new file mode 100644 index 0000000..b3cca4e --- /dev/null +++ b/Wave/Components/Account/Pages/_Imports.razor @@ -0,0 +1,2 @@ +@using Wave.Components.Account.Shared +@layout AccountLayout diff --git a/Wave/Components/Account/Shared/AccountLayout.razor b/Wave/Components/Account/Shared/AccountLayout.razor new file mode 100644 index 0000000..cac8207 --- /dev/null +++ b/Wave/Components/Account/Shared/AccountLayout.razor @@ -0,0 +1,28 @@ +@inherits LayoutComponentBase +@layout Wave.Components.Layout.MainLayout +@inject NavigationManager NavigationManager + +@if (HttpContext is null) +{ +

Loading...

+} +else +{ + @Body +} + +@code { + [CascadingParameter] + private HttpContext? HttpContext { get; set; } + + protected override void OnParametersSet() + { + if (HttpContext is null) + { + // If this code runs, we're currently rendering in interactive mode, so there is no HttpContext. + // The identity pages need to set cookies, so they require an HttpContext. To achieve this we + // must transition back from interactive mode to a server-rendered page. + NavigationManager.Refresh(forceReload: true); + } + } +} diff --git a/Wave/Components/Account/Shared/ExternalLoginPicker.razor b/Wave/Components/Account/Shared/ExternalLoginPicker.razor new file mode 100644 index 0000000..eaa94d2 --- /dev/null +++ b/Wave/Components/Account/Shared/ExternalLoginPicker.razor @@ -0,0 +1,43 @@ +@using Microsoft.AspNetCore.Authentication +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject SignInManager SignInManager +@inject IdentityRedirectManager RedirectManager + +@if (externalLogins.Length == 0) +{ +
+

+ There are no external authentication services configured. See this article + about setting up this ASP.NET application to support logging in via external services. +

+
+} +else +{ +
+
+ + +

+ @foreach (var provider in externalLogins) + { + + } +

+
+
+} + +@code { + private AuthenticationScheme[] externalLogins = []; + + [SupplyParameterFromQuery] + private string? ReturnUrl { get; set; } + + protected override async Task OnInitializedAsync() + { + externalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).ToArray(); + } +} diff --git a/Wave/Components/Account/Shared/ManageLayout.razor b/Wave/Components/Account/Shared/ManageLayout.razor new file mode 100644 index 0000000..949bc92 --- /dev/null +++ b/Wave/Components/Account/Shared/ManageLayout.razor @@ -0,0 +1,17 @@ +@inherits LayoutComponentBase +@layout AccountLayout + +

Manage your account

+ +
+

Change your account settings

+
+
+
+ +
+
+ @Body +
+
+
diff --git a/Wave/Components/Account/Shared/ManageNavMenu.razor b/Wave/Components/Account/Shared/ManageNavMenu.razor new file mode 100644 index 0000000..ce96bb5 --- /dev/null +++ b/Wave/Components/Account/Shared/ManageNavMenu.razor @@ -0,0 +1,37 @@ +@using Microsoft.AspNetCore.Identity +@using Wave.Data + +@inject SignInManager SignInManager + + + +@code { + private bool hasExternalLogins; + + protected override async Task OnInitializedAsync() + { + hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any(); + } +} diff --git a/Wave/Components/Account/Shared/RedirectToLogin.razor b/Wave/Components/Account/Shared/RedirectToLogin.razor new file mode 100644 index 0000000..c8b8eff --- /dev/null +++ b/Wave/Components/Account/Shared/RedirectToLogin.razor @@ -0,0 +1,8 @@ +@inject NavigationManager NavigationManager + +@code { + protected override void OnInitialized() + { + NavigationManager.NavigateTo($"Account/Login?returnUrl={Uri.EscapeDataString(NavigationManager.Uri)}", forceLoad: true); + } +} diff --git a/Wave/Components/Account/Shared/ShowRecoveryCodes.razor b/Wave/Components/Account/Shared/ShowRecoveryCodes.razor new file mode 100644 index 0000000..aa92e11 --- /dev/null +++ b/Wave/Components/Account/Shared/ShowRecoveryCodes.razor @@ -0,0 +1,28 @@ + +

Recovery codes

+ +
+
+ @foreach (var recoveryCode in RecoveryCodes) + { +
+ @recoveryCode +
+ } +
+
+ +@code { + [Parameter] + public string[] RecoveryCodes { get; set; } = []; + + [Parameter] + public string? StatusMessage { get; set; } +} diff --git a/Wave/Components/Account/Shared/StatusMessage.razor b/Wave/Components/Account/Shared/StatusMessage.razor new file mode 100644 index 0000000..12cd544 --- /dev/null +++ b/Wave/Components/Account/Shared/StatusMessage.razor @@ -0,0 +1,29 @@ +@if (!string.IsNullOrEmpty(DisplayMessage)) +{ + var statusMessageClass = DisplayMessage.StartsWith("Error") ? "danger" : "success"; + +} + +@code { + private string? messageFromCookie; + + [Parameter] + public string? Message { get; set; } + + [CascadingParameter] + private HttpContext HttpContext { get; set; } = default!; + + private string? DisplayMessage => Message ?? messageFromCookie; + + protected override void OnInitialized() + { + messageFromCookie = HttpContext.Request.Cookies[IdentityRedirectManager.StatusCookieName]; + + if (messageFromCookie is not null) + { + HttpContext.Response.Cookies.Delete(IdentityRedirectManager.StatusCookieName); + } + } +} diff --git a/Wave/Components/App.razor b/Wave/Components/App.razor new file mode 100644 index 0000000..d723113 --- /dev/null +++ b/Wave/Components/App.razor @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Wave/Components/Layout/MainLayout.razor b/Wave/Components/Layout/MainLayout.razor new file mode 100644 index 0000000..7cd63fe --- /dev/null +++ b/Wave/Components/Layout/MainLayout.razor @@ -0,0 +1,17 @@ +@inherits LayoutComponentBase + +
+ + +
+
+ About +
+ +
+ @Body +
+
+
diff --git a/Wave/Components/Layout/MainLayout.razor.css b/Wave/Components/Layout/MainLayout.razor.css new file mode 100644 index 0000000..038baf1 --- /dev/null +++ b/Wave/Components/Layout/MainLayout.razor.css @@ -0,0 +1,96 @@ +.page { + position: relative; + display: flex; + flex-direction: column; +} + +main { + flex: 1; +} + +.sidebar { + background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); +} + +.top-row { + background-color: #f7f7f7; + border-bottom: 1px solid #d6d5d5; + justify-content: flex-end; + height: 3.5rem; + display: flex; + align-items: center; +} + + .top-row ::deep a, .top-row ::deep .btn-link { + white-space: nowrap; + margin-left: 1.5rem; + text-decoration: none; + } + + .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { + text-decoration: underline; + } + + .top-row ::deep a:first-child { + overflow: hidden; + text-overflow: ellipsis; + } + +@media (max-width: 640.98px) { + .top-row { + justify-content: space-between; + } + + .top-row ::deep a, .top-row ::deep .btn-link { + margin-left: 0; + } +} + +@media (min-width: 641px) { + .page { + flex-direction: row; + } + + .sidebar { + width: 250px; + height: 100vh; + position: sticky; + top: 0; + } + + .top-row { + position: sticky; + top: 0; + z-index: 1; + } + + .top-row.auth ::deep a:first-child { + flex: 1; + text-align: right; + width: 0; + } + + .top-row, article { + padding-left: 2rem !important; + padding-right: 1.5rem !important; + } +} + +#blazor-error-ui { + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; +} + + #blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; + } diff --git a/Wave/Components/Layout/NavMenu.razor b/Wave/Components/Layout/NavMenu.razor new file mode 100644 index 0000000..4fd66fc --- /dev/null +++ b/Wave/Components/Layout/NavMenu.razor @@ -0,0 +1,86 @@ +@implements IDisposable + +@inject NavigationManager NavigationManager + + + + + + + +@code { + private string? currentUrl; + + protected override void OnInitialized() + { + currentUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); + NavigationManager.LocationChanged += OnLocationChanged; + } + + private void OnLocationChanged(object? sender, LocationChangedEventArgs e) + { + currentUrl = NavigationManager.ToBaseRelativePath(e.Location); + StateHasChanged(); + } + + public void Dispose() + { + NavigationManager.LocationChanged -= OnLocationChanged; + } +} + diff --git a/Wave/Components/Layout/NavMenu.razor.css b/Wave/Components/Layout/NavMenu.razor.css new file mode 100644 index 0000000..16700eb --- /dev/null +++ b/Wave/Components/Layout/NavMenu.razor.css @@ -0,0 +1,125 @@ +.navbar-toggler { + appearance: none; + cursor: pointer; + width: 3.5rem; + height: 2.5rem; + color: white; + position: absolute; + top: 0.5rem; + right: 1rem; + border: 1px solid rgba(255, 255, 255, 0.1); + background: 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") no-repeat center/1.75rem rgba(255, 255, 255, 0.1); +} + +.navbar-toggler:checked { + background-color: rgba(255, 255, 255, 0.5); +} + +.top-row { + height: 3.5rem; + background-color: rgba(0,0,0,0.4); +} + +.navbar-brand { + font-size: 1.1rem; +} + +.bi { + display: inline-block; + position: relative; + width: 1.25rem; + height: 1.25rem; + margin-right: 0.75rem; + top: -1px; + background-size: cover; +} + +.bi-house-door-fill-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E"); +} + +.bi-plus-square-fill-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E"); +} + +.bi-list-nested-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E"); +} + +.bi-lock-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM5 8h6a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1z'/%3E%3C/svg%3E"); +} + +.bi-person-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person' viewBox='0 0 16 16'%3E%3Cpath d='M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0Zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4Zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10Z'/%3E%3C/svg%3E"); +} + +.bi-person-badge-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-badge' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z'/%3E%3Cpath d='M4.5 0A2.5 2.5 0 0 0 2 2.5V14a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2.5A2.5 2.5 0 0 0 11.5 0h-7zM3 2.5A1.5 1.5 0 0 1 4.5 1h7A1.5 1.5 0 0 1 13 2.5v10.795a4.2 4.2 0 0 0-.776-.492C11.392 12.387 10.063 12 8 12s-3.392.387-4.224.803a4.2 4.2 0 0 0-.776.492V2.5z'/%3E%3C/svg%3E"); +} + +.bi-person-fill-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-fill' viewBox='0 0 16 16'%3E%3Cpath d='M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3Zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z'/%3E%3C/svg%3E"); +} + +.bi-arrow-bar-left-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-arrow-bar-left' viewBox='0 0 16 16'%3E%3Cpath d='M12.5 15a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5ZM10 8a.5.5 0 0 1-.5.5H3.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L3.707 7.5H9.5a.5.5 0 0 1 .5.5Z'/%3E%3C/svg%3E"); +} + +.nav-item { + font-size: 0.9rem; + padding-bottom: 0.5rem; +} + + .nav-item:first-of-type { + padding-top: 1rem; + } + + .nav-item:last-of-type { + padding-bottom: 1rem; + } + + .nav-item ::deep .nav-link { + color: #d7d7d7; + background: none; + border: none; + border-radius: 4px; + height: 3rem; + display: flex; + align-items: center; + line-height: 3rem; + width: 100%; + } + +.nav-item ::deep a.active { + background-color: rgba(255,255,255,0.37); + color: white; +} + +.nav-item ::deep .nav-link:hover { + background-color: rgba(255,255,255,0.1); + color: white; +} + +.nav-scrollable { + display: none; +} + +.navbar-toggler:checked ~ .nav-scrollable { + display: block; +} + +@media (min-width: 641px) { + .navbar-toggler { + display: none; + } + + .nav-scrollable { + /* Never collapse the sidebar for wide screens */ + display: block; + + /* Allow sidebar to scroll for tall menus */ + height: calc(100vh - 3.5rem); + overflow-y: auto; + } +} diff --git a/Wave/Components/Pages/Auth.razor b/Wave/Components/Pages/Auth.razor new file mode 100644 index 0000000..b7bbe6e --- /dev/null +++ b/Wave/Components/Pages/Auth.razor @@ -0,0 +1,13 @@ +@page "/auth" + +@using Microsoft.AspNetCore.Authorization + +@attribute [Authorize] + +Auth + +

You are authenticated

+ + + Hello @context.User.Identity?.Name! + diff --git a/Wave/Components/Pages/Error.razor b/Wave/Components/Pages/Error.razor new file mode 100644 index 0000000..576cc2d --- /dev/null +++ b/Wave/Components/Pages/Error.razor @@ -0,0 +1,36 @@ +@page "/Error" +@using System.Diagnostics + +Error + +

Error.

+

An error occurred while processing your request.

+ +@if (ShowRequestId) +{ +

+ Request ID: @RequestId +

+} + +

Development Mode

+

+ Swapping to Development environment will display more detailed information about the error that occurred. +

+

+ The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

+ +@code{ + [CascadingParameter] + private HttpContext? HttpContext { get; set; } + + private string? RequestId { get; set; } + private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + protected override void OnInitialized() => + RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; +} diff --git a/Wave/Components/Pages/Home.razor b/Wave/Components/Pages/Home.razor new file mode 100644 index 0000000..9001e0b --- /dev/null +++ b/Wave/Components/Pages/Home.razor @@ -0,0 +1,7 @@ +@page "/" + +Home + +

Hello, world!

+ +Welcome to your new app. diff --git a/Wave/Components/Pages/Weather.razor b/Wave/Components/Pages/Weather.razor new file mode 100644 index 0000000..43a1ecb --- /dev/null +++ b/Wave/Components/Pages/Weather.razor @@ -0,0 +1,64 @@ +@page "/weather" +@attribute [StreamRendering] + +Weather + +

Weather

+ +

This component demonstrates showing data.

+ +@if (forecasts == null) +{ +

Loading...

+} +else +{ + + + + + + + + + + + @foreach (var forecast in forecasts) + { + + + + + + + } + +
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
+} + +@code { + private WeatherForecast[]? forecasts; + + protected override async Task OnInitializedAsync() + { + // Simulate asynchronous loading to demonstrate streaming rendering + await Task.Delay(500); + + var startDate = DateOnly.FromDateTime(DateTime.Now); + var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; + forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = startDate.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = summaries[Random.Shared.Next(summaries.Length)] + }).ToArray(); + } + + private class WeatherForecast + { + public DateOnly Date { get; set; } + public int TemperatureC { get; set; } + public string? Summary { get; set; } + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + } +} diff --git a/Wave/Components/Routes.razor b/Wave/Components/Routes.razor new file mode 100644 index 0000000..6859d17 --- /dev/null +++ b/Wave/Components/Routes.razor @@ -0,0 +1,11 @@ +@using Wave.Components.Account.Shared + + + + + + + + + + diff --git a/Wave/Components/_Imports.razor b/Wave/Components/_Imports.razor new file mode 100644 index 0000000..888cabe --- /dev/null +++ b/Wave/Components/_Imports.razor @@ -0,0 +1,11 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Authorization +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using Wave +@using Wave.Components diff --git a/Wave/Data/ApplicationDbContext.cs b/Wave/Data/ApplicationDbContext.cs new file mode 100644 index 0000000..2b5734d --- /dev/null +++ b/Wave/Data/ApplicationDbContext.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; + +namespace Wave.Data +{ + public class ApplicationDbContext(DbContextOptions options) : IdentityDbContext(options) + { + } +} diff --git a/Wave/Data/ApplicationUser.cs b/Wave/Data/ApplicationUser.cs new file mode 100644 index 0000000..758eca5 --- /dev/null +++ b/Wave/Data/ApplicationUser.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Identity; + +namespace Wave.Data +{ + // Add profile data for application users by adding properties to the ApplicationUser class + public class ApplicationUser : IdentityUser + { + } + +} diff --git a/Wave/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs b/Wave/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs new file mode 100644 index 0000000..2923e82 --- /dev/null +++ b/Wave/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs @@ -0,0 +1,279 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using System; +using Wave.Data; + +#nullable disable + +namespace Wave.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("00000000000000_CreateIdentitySchema")] + partial class CreateIdentitySchema + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Wave.Data.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Wave.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Wave.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Wave.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Wave.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Wave/Data/Migrations/00000000000000_CreateIdentitySchema.cs b/Wave/Data/Migrations/00000000000000_CreateIdentitySchema.cs new file mode 100644 index 0000000..d4d43ef --- /dev/null +++ b/Wave/Data/Migrations/00000000000000_CreateIdentitySchema.cs @@ -0,0 +1,224 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; + +#nullable disable + +namespace Wave.Migrations +{ + /// + public partial class CreateIdentitySchema : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AspNetRoles", + columns: table => new + { + Id = table.Column(type: "nvarchar(450)", nullable: false), + Name = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + NormalizedName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column(type: "nvarchar(450)", nullable: false), + UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + NormalizedUserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + Email = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + NormalizedEmail = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), + EmailConfirmed = table.Column(type: "bit", nullable: false), + PasswordHash = table.Column(type: "nvarchar(max)", nullable: true), + SecurityStamp = table.Column(type: "nvarchar(max)", nullable: true), + ConcurrencyStamp = table.Column(type: "nvarchar(max)", nullable: true), + PhoneNumber = table.Column(type: "nvarchar(max)", nullable: true), + PhoneNumberConfirmed = table.Column(type: "bit", nullable: false), + TwoFactorEnabled = table.Column(type: "bit", nullable: false), + LockoutEnd = table.Column(type: "datetimeoffset", nullable: true), + LockoutEnabled = table.Column(type: "bit", nullable: false), + AccessFailedCount = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoleClaims", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + RoleId = table.Column(type: "nvarchar(450)", nullable: false), + ClaimType = table.Column(type: "nvarchar(max)", nullable: true), + ClaimValue = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserClaims", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + UserId = table.Column(type: "nvarchar(450)", nullable: false), + ClaimType = table.Column(type: "nvarchar(max)", nullable: true), + ClaimValue = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUserClaims_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserLogins", + columns: table => new + { + LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), + ProviderKey = table.Column(type: "nvarchar(450)", nullable: false), + ProviderDisplayName = table.Column(type: "nvarchar(max)", nullable: true), + UserId = table.Column(type: "nvarchar(450)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); + table.ForeignKey( + name: "FK_AspNetUserLogins_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserRoles", + columns: table => new + { + UserId = table.Column(type: "nvarchar(450)", nullable: false), + RoleId = table.Column(type: "nvarchar(450)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserTokens", + columns: table => new + { + UserId = table.Column(type: "nvarchar(450)", nullable: false), + LoginProvider = table.Column(type: "nvarchar(450)", nullable: false), + Name = table.Column(type: "nvarchar(450)", nullable: false), + Value = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AspNetUserTokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AspNetRoleClaims_RoleId", + table: "AspNetRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + table: "AspNetRoles", + column: "NormalizedName", + unique: true, + filter: "[NormalizedName] IS NOT NULL"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserClaims_UserId", + table: "AspNetUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserLogins_UserId", + table: "AspNetUserLogins", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserRoles_RoleId", + table: "AspNetUserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "EmailIndex", + table: "AspNetUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + table: "AspNetUsers", + column: "NormalizedUserName", + unique: true, + filter: "[NormalizedUserName] IS NOT NULL"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AspNetRoleClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserLogins"); + + migrationBuilder.DropTable( + name: "AspNetUserRoles"); + + migrationBuilder.DropTable( + name: "AspNetUserTokens"); + + migrationBuilder.DropTable( + name: "AspNetRoles"); + + migrationBuilder.DropTable( + name: "AspNetUsers"); + } + } +} diff --git a/Wave/Data/Migrations/ApplicationDbContextModelSnapshot.cs b/Wave/Data/Migrations/ApplicationDbContextModelSnapshot.cs new file mode 100644 index 0000000..89593d1 --- /dev/null +++ b/Wave/Data/Migrations/ApplicationDbContextModelSnapshot.cs @@ -0,0 +1,276 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using System; +using Wave.Data; + +#nullable disable + +namespace Wave.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + partial class ApplicationDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Wave.Data.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Wave.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Wave.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Wave.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Wave.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Wave/Program.cs b/Wave/Program.cs new file mode 100644 index 0000000..3c69275 --- /dev/null +++ b/Wave/Program.cs @@ -0,0 +1,59 @@ +using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.AspNetCore.Components.Server; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using Wave.Components; +using Wave.Components.Account; +using Wave.Data; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +builder.Services.AddRazorComponents(); + +builder.Services.AddCascadingAuthenticationState(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); + +builder.Services.AddAuthorization(); +builder.Services.AddAuthentication(options => + { + options.DefaultScheme = IdentityConstants.ApplicationScheme; + options.DefaultSignInScheme = IdentityConstants.ExternalScheme; + }) + .AddIdentityCookies(); + +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); +builder.Services.AddDbContext(options => + options.UseSqlServer(connectionString)); +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + +builder.Services.AddIdentityCore(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores() + .AddSignInManager() + .AddDefaultTokenProviders(); + +builder.Services.AddSingleton, IdentityNoOpEmailSender>(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseMigrationsEndPoint(); +} +else +{ + app.UseExceptionHandler("/Error", createScopeForErrors: true); +} + +app.UseStaticFiles(); +app.UseAntiforgery(); + +app.MapRazorComponents(); + +// Add additional endpoints required by the Identity /Account Razor components. +app.MapAdditionalIdentityEndpoints(); + +app.Run(); diff --git a/Wave/Properties/launchSettings.json b/Wave/Properties/launchSettings.json new file mode 100644 index 0000000..f6ab87f --- /dev/null +++ b/Wave/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:49647", + "sslPort": 0 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:5272", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } + } diff --git a/Wave/Properties/serviceDependencies.json b/Wave/Properties/serviceDependencies.json new file mode 100644 index 0000000..d8177e0 --- /dev/null +++ b/Wave/Properties/serviceDependencies.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "mssql1": { + "type": "mssql", + "connectionId": "ConnectionStrings:DefaultConnection" + } + } +} \ No newline at end of file diff --git a/Wave/Properties/serviceDependencies.local.json b/Wave/Properties/serviceDependencies.local.json new file mode 100644 index 0000000..299aa9a --- /dev/null +++ b/Wave/Properties/serviceDependencies.local.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "mssql1": { + "type": "mssql.local", + "connectionId": "ConnectionStrings:DefaultConnection" + } + } +} \ No newline at end of file diff --git a/Wave/Wave.csproj b/Wave/Wave.csproj new file mode 100644 index 0000000..30ef7f5 --- /dev/null +++ b/Wave/Wave.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + aspnet-Wave-e004be03-56b7-4c24-aea7-ae4fda617143 + + + + + + + + + + diff --git a/Wave/appsettings.Development.json b/Wave/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/Wave/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Wave/appsettings.json b/Wave/appsettings.json new file mode 100644 index 0000000..5ed0b78 --- /dev/null +++ b/Wave/appsettings.json @@ -0,0 +1,12 @@ +{ + "ConnectionStrings": { + "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-Wave-e004be03-56b7-4c24-aea7-ae4fda617143;Trusted_Connection=True;MultipleActiveResultSets=true" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/Wave/wwwroot/app.css b/Wave/wwwroot/app.css new file mode 100644 index 0000000..2bd9b78 --- /dev/null +++ b/Wave/wwwroot/app.css @@ -0,0 +1,51 @@ +html, body { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +a, .btn-link { + color: #006bb7; +} + +.btn-primary { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { + box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; +} + +.content { + padding-top: 1.1rem; +} + +h1:focus { + outline: none; +} + +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid #e50000; +} + +.validation-message { + color: #e50000; +} + +.blazor-error-boundary { + background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; + padding: 1rem 1rem 1rem 3.7rem; + color: white; +} + + .blazor-error-boundary::after { + content: "An error has occurred." + } + +.darker-border-checkbox.form-check-input { + border-color: #929292; +} diff --git a/Wave/wwwroot/bootstrap/bootstrap.min.css b/Wave/wwwroot/bootstrap/bootstrap.min.css new file mode 100644 index 0000000..02ae65b --- /dev/null +++ b/Wave/wwwroot/bootstrap/bootstrap.min.css @@ -0,0 +1,7 @@ +@charset "UTF-8";/*! + * Bootstrap v5.1.0 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors + * Copyright 2011-2021 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-rgb:33,37,41;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",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:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-bg:#fff}*,::after,::before{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:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],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}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,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]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button: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:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-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.25rem;font-weight:300}.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:.5rem}.initialism{font-size:.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:.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:#6c757d}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{width:100%;padding-right:var(--bs-gutter-x,.75rem);padding-left:var(--bs-gutter-x,.75rem);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(var(--bs-gutter-y) * -1);margin-right:calc(var(--bs-gutter-x) * -.5);margin-left:calc(var(--bs-gutter-x) * -.5)}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .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:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@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:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@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:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@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:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@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:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.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:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-bg:transparent;--bs-table-accent-bg:transparent;--bs-table-striped-color:#212529;--bs-table-striped-bg:rgba(0, 0, 0, 0.05);--bs-table-active-color:#212529;--bs-table-active-bg:rgba(0, 0, 0, 0.1);--bs-table-hover-color:#212529;--bs-table-hover-bg:rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#212529;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:last-child)>:last-child>*{border-bottom-color:currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-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-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg:#cfe2ff;--bs-table-striped-bg:#c5d7f2;--bs-table-striped-color:#000;--bs-table-active-bg:#bacbe6;--bs-table-active-color:#000;--bs-table-hover-bg:#bfd1ec;--bs-table-hover-color:#000;color:#000;border-color:#bacbe6}.table-secondary{--bs-table-bg:#e2e3e5;--bs-table-striped-bg:#d7d8da;--bs-table-striped-color:#000;--bs-table-active-bg:#cbccce;--bs-table-active-color:#000;--bs-table-hover-bg:#d1d2d4;--bs-table-hover-color:#000;color:#000;border-color:#cbccce}.table-success{--bs-table-bg:#d1e7dd;--bs-table-striped-bg:#c7dbd2;--bs-table-striped-color:#000;--bs-table-active-bg:#bcd0c7;--bs-table-active-color:#000;--bs-table-hover-bg:#c1d6cc;--bs-table-hover-color:#000;color:#000;border-color:#bcd0c7}.table-info{--bs-table-bg:#cff4fc;--bs-table-striped-bg:#c5e8ef;--bs-table-striped-color:#000;--bs-table-active-bg:#badce3;--bs-table-active-color:#000;--bs-table-hover-bg:#bfe2e9;--bs-table-hover-color:#000;color:#000;border-color:#badce3}.table-warning{--bs-table-bg:#fff3cd;--bs-table-striped-bg:#f2e7c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e6dbb9;--bs-table-active-color:#000;--bs-table-hover-bg:#ece1be;--bs-table-hover-color:#000;color:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg:#f8d7da;--bs-table-striped-bg:#eccccf;--bs-table-striped-color:#000;--bs-table-active-bg:#dfc2c4;--bs-table-active-color:#000;--bs-table-hover-bg:#e5c7ca;--bs-table-hover-color:#000;color:#000;border-color:#dfc2c4}.table-light{--bs-table-bg:#f8f9fa;--bs-table-striped-bg:#ecedee;--bs-table-striped-color:#000;--bs-table-active-bg:#dfe0e1;--bs-table-active-color:#000;--bs-table-hover-bg:#e5e6e7;--bs-table-hover-color:#000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg:#212529;--bs-table-striped-bg:#2c3034;--bs-table-striped-color:#fff;--bs-table-active-bg:#373b3e;--bs-table-active-color:#fff;--bs-table-hover-bg:#323539;--bs-table-hover-color:#fff;color:#fff;border-color:#373b3e}.table-responsive{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:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-.375rem -.75rem;-webkit-margin-end:.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-.25rem -.5rem;-webkit-margin-end:.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + .5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;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='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-print-color-adjust:exact;color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.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 10l3 3l6-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:#0d6efd;border-color:#0d6efd;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:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{opacity:.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 .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='%2386b7fe'/%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-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:.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 #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#0d6efd;border:0;border-radius:1rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .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:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .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:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu){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}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(25,135,84,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#198754;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.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(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:#198754}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{padding-right:4.125rem;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='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 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='%23198754' d='M2.3 6.73L.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 .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:#198754}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:#198754}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group .form-control.is-valid,.input-group .form-select.is-valid,.was-validated .input-group .form-control:valid,.was-validated .input-group .form-select:valid{z-index:1}.input-group .form-control.is-valid:focus,.input-group .form-select.is-valid:focus,.was-validated .input-group .form-control:valid:focus,.was-validated .input-group .form-select:valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .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='%23dc3545'%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='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:#dc3545}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{padding-right:4.125rem;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='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 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='%23dc3545'%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='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:#dc3545}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:#dc3545}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group .form-control.is-invalid,.input-group .form-select.is-invalid,.was-validated .input-group .form-control:invalid,.was-validated .input-group .form-select:invalid{z-index:2}.input-group .form-control.is-invalid:focus,.input-group .form-select.is-invalid:focus,.was-validated .input-group .form-control:invalid:focus,.was-validated .input-group .form-select:invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-primary{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-primary:hover{color:#fff;background-color:#0b5ed7;border-color:#0a58ca}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#0b5ed7;border-color:#0a58ca;box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-check:active+.btn-primary,.btn-check:checked+.btn-primary,.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0a58ca;border-color:#0a53be}.btn-check:active+.btn-primary:focus,.btn-check:checked+.btn-primary:focus,.btn-primary.active:focus,.btn-primary:active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5c636a;border-color:#565e64}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#5c636a;border-color:#565e64;box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-check:active+.btn-secondary,.btn-check:checked+.btn-secondary,.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#565e64;border-color:#51585e}.btn-check:active+.btn-secondary:focus,.btn-check:checked+.btn-secondary:focus,.btn-secondary.active:focus,.btn-secondary:active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:active+.btn-success,.btn-check:checked+.btn-success,.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:active+.btn-success:focus,.btn-check:checked+.btn-success:focus,.btn-success.active:focus,.btn-success:active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:active+.btn-info,.btn-check:checked+.btn-info,.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:active+.btn-info:focus,.btn-check:checked+.btn-info:focus,.btn-info.active:focus,.btn-info:active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info.disabled,.btn-info:disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:active+.btn-warning,.btn-check:checked+.btn-warning,.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:active+.btn-warning:focus,.btn-check:checked+.btn-warning:focus,.btn-warning.active:focus,.btn-warning:active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:active+.btn-danger,.btn-check:checked+.btn-danger,.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:active+.btn-danger:focus,.btn-check:checked+.btn-danger:focus,.btn-danger.active:focus,.btn-danger:active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:active+.btn-light,.btn-check:checked+.btn-light,.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:active+.btn-light:focus,.btn-check:checked+.btn-light:focus,.btn-light.active:focus,.btn-light:active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light.disabled,.btn-light:disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:active+.btn-dark,.btn-check:checked+.btn-dark,.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:active+.btn-dark:focus,.btn-check:checked+.btn-dark:focus,.btn-dark.active:focus,.btn-dark:active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-primary{color:#0d6efd;border-color:#0d6efd}.btn-outline-primary:hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-check:active+.btn-outline-primary,.btn-check:checked+.btn-outline-primary,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show,.btn-outline-primary:active{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:active+.btn-outline-primary:focus,.btn-check:checked+.btn-outline-primary:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus,.btn-outline-primary:active:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#0d6efd;background-color:transparent}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-check:active+.btn-outline-secondary,.btn-check:checked+.btn-outline-secondary,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show,.btn-outline-secondary:active{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:active+.btn-outline-secondary:focus,.btn-check:checked+.btn-outline-secondary:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus,.btn-outline-secondary:active:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-success{color:#198754;border-color:#198754}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:active+.btn-outline-success,.btn-check:checked+.btn-outline-success,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show,.btn-outline-success:active{color:#fff;background-color:#198754;border-color:#198754}.btn-check:active+.btn-outline-success:focus,.btn-check:checked+.btn-outline-success:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus,.btn-outline-success:active:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#198754;background-color:transparent}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:active+.btn-outline-info,.btn-check:checked+.btn-outline-info,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show,.btn-outline-info:active{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:active+.btn-outline-info:focus,.btn-check:checked+.btn-outline-info:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus,.btn-outline-info:active:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#0dcaf0;background-color:transparent}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:active+.btn-outline-warning,.btn-check:checked+.btn-outline-warning,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show,.btn-outline-warning:active{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:active+.btn-outline-warning:focus,.btn-check:checked+.btn-outline-warning:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus,.btn-outline-warning:active:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:active+.btn-outline-danger,.btn-check:checked+.btn-outline-danger,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show,.btn-outline-danger:active{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:active+.btn-outline-danger:focus,.btn-check:checked+.btn-outline-danger:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus,.btn-outline-danger:active:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:active+.btn-outline-light,.btn-check:checked+.btn-outline-light,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show,.btn-outline-light:active{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:active+.btn-outline-light:focus,.btn-check:checked+.btn-outline-light:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus,.btn-outline-light:active:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#212529;border-color:#212529}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:active+.btn-outline-dark,.btn-check:checked+.btn-outline-dark,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show,.btn-outline-dark:active{color:#fff;background-color:#212529;border-color:#212529}.btn-check:active+.btn-outline-dark:focus,.btn-check:checked+.btn-outline-dark:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus,.btn-outline-dark:active:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#212529;background-color:transparent}.btn-link{font-weight:400;color:#0d6efd;text-decoration:underline}.btn-link:hover{color:#0a58ca}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:.2rem}.fade{transition:opacity .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 .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropend,.dropstart,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.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:1400px){.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:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.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:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.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:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0d6efd}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:focus,.dropdown-menu-dark .dropdown-item:hover{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#0d6efd}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.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-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#0d6efd;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:#0a58ca}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:0 0;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:0 0;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#0d6efd}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{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{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem;transition:box-shadow .15s ease-in-out}@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 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand-sm .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-sm .offcanvas-bottom,.navbar-expand-sm .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-sm .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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand-md .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-md .offcanvas-bottom,.navbar-expand-md .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-md .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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand-lg .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-lg .offcanvas-bottom,.navbar-expand-lg .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-lg .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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand-xl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xl .offcanvas-bottom,.navbar-expand-xl .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand-xxl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xxl .offcanvas-bottom,.navbar-expand-xxl .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand-xxl .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:.5rem;padding-left:.5rem}.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-header{display:none}.navbar-expand .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;visibility:visible!important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand .offcanvas-bottom,.navbar-expand .offcanvas-top{height:auto;border-top:0;border-bottom:0}.navbar-expand .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.55)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.55);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image: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")}.navbar-light .navbar-text{color:rgba(0,0,0,.55)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.55)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.55);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image: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")}.navbar-dark .navbar-text{color:rgba(255,255,255,.55)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.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:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.5rem;margin-bottom:-.5rem;margin-left:-.5rem;border-bottom:0}.card-header-pills{margin-right:-.5rem;margin-left:-.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@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-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{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-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#212529;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#0c63e4;background-color:#e7f1ff;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%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");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%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");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.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{border-radius:0}.breadcrumb{display:flex;flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#0d6efd;text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#0a58ca;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#0a58ca;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{color:#41464b;background-color:#e2e3e5;border-color:#d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@-webkit-keyframes progress-bar-stripes{0%{background-position-x:1rem}}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#0d6efd;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:1s linear infinite progress-bar-stripes;animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.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:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;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:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .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 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);opacity:1}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.toast-header .btn-close{margin-right:-.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1055;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .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% - 1rem)}.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% - 1rem)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;flex-shrink:0;align-items:center;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-.5rem -.5rem -.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;flex-shrink:0;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-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{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@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{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@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{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@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{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@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{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media (max-width:1399.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{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);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;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[data-popper-placement^=right],.bs-tooltip-end{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[data-popper-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[data-popper-placement^=left],.bs-tooltip-start{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);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;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#212529}.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 .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{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:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.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:.5;transition:opacity .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-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@-webkit-keyframes spinner-border{to{transform:rotate(360deg)}}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:.75s linear infinite spinner-border;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-.125em;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:.75s linear infinite spinner-grow;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1045;display:flex;flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.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:.5}.offcanvas-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-.5rem;margin-right:-.5rem;margin-bottom:-.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentColor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{-webkit-animation:placeholder-glow 2s ease-in-out infinite;animation:placeholder-glow 2s ease-in-out infinite}@-webkit-keyframes placeholder-glow{50%{opacity:.2}}@keyframes placeholder-glow{50%{opacity:.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%;-webkit-animation:placeholder-wave 2s linear infinite;animation:placeholder-wave 2s linear infinite}@-webkit-keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.link-primary{color:#0d6efd}.link-primary:focus,.link-primary:hover{color:#0a58ca}.link-secondary{color:#6c757d}.link-secondary:focus,.link-secondary:hover{color:#565e64}.link-success{color:#198754}.link-success:focus,.link-success:hover{color:#146c43}.link-info{color:#0dcaf0}.link-info:focus,.link-info:hover{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:focus,.link-warning:hover{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:focus,.link-danger:hover{color:#b02a37}.link-light{color:#f8f9fa}.link-light:focus,.link-light:hover{color:#f9fafb}.link-dark{color:#212529}.link-dark:focus,.link-dark:hover{color:#1a1e21}.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:calc(3 / 4 * 100%)}.ratio-16x9{--bs-aspect-ratio:calc(9 / 16 * 100%)}.ratio-21x9{--bs-aspect-ratio:calc(9 / 21 * 100%)}.fixed-top{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{position:-webkit-sticky;position:sticky;top:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top: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:.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:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.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 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(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:-webkit-sticky!important;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:1px solid #dee2e6!important}.border-0{border:0!important}.border-top{border-top:1px solid #dee2e6!important}.border-top-0{border-top:0!important}.border-end{border-right:1px solid #dee2e6!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:1px solid #dee2e6!important}.border-start-0{border-left:0!important}.border-primary{border-color:#0d6efd!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#198754!important}.border-info{border-color:#0dcaf0!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#212529!important}.border-white{border-color:#fff!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.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}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!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:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.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:3rem!important;margin-left:3rem!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:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.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:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.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:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.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:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!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:700!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}.text-break{word-wrap:break-word!important;word-break:break-word!important}.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-body{--bs-text-opacity:1;color:rgba(var(--bs-body-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:#6c757d!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-reset{--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-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-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:.25rem!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:.2rem!important}.rounded-2{border-radius:.25rem!important}.rounded-3{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-end{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-start{border-bottom-left-radius:.25rem!important;border-top-left-radius:.25rem!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}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!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:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.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:3rem!important;margin-left:3rem!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:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.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:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.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:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.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:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!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}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!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:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.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:3rem!important;margin-left:3rem!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:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.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:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.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:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.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:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!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}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!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:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.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:3rem!important;margin-left:3rem!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:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.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:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.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:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.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:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!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}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!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:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.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:3rem!important;margin-left:3rem!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:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.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:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.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:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.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:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!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:1400px){.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}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!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:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.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:3rem!important;margin-left:3rem!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:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.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:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.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:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.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:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!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:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!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}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/Wave/wwwroot/bootstrap/bootstrap.min.css.map b/Wave/wwwroot/bootstrap/bootstrap.min.css.map new file mode 100644 index 0000000000000000000000000000000000000000..afcd9e33e9eae3876cdc0dfaafa5a80e012b1631 GIT binary patch literal 449111 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 F{saGdP*eZ_ literal 0 HcmV?d00001 diff --git a/Wave/wwwroot/favicon.png b/Wave/wwwroot/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8422b59695935d180d11d5dbe99653e711097819 GIT binary patch literal 1148 zcmV-?1cUpDP)9h26h2-Cs%i*@Moc3?#6qJID|D#|3|2Hn7gTIYEkr|%Xjp);YgvFmB&0#2E2b=| zkVr)lMv9=KqwN&%obTp-$<51T%rx*NCwceh-E+=&e(oLO`@Z~7gybJ#U|^tB2Pai} zRN@5%1qsZ1e@R(XC8n~)nU1S0QdzEYlWPdUpH{wJ2Pd4V8kI3BM=)sG^IkUXF2-j{ zrPTYA6sxpQ`Q1c6mtar~gG~#;lt=s^6_OccmRd>o{*=>)KS=lM zZ!)iG|8G0-9s3VLm`bsa6e ze*TlRxAjXtm^F8V`M1%s5d@tYS>&+_ga#xKGb|!oUBx3uc@mj1%=MaH4GR0tPBG_& z9OZE;->dO@`Q)nr<%dHAsEZRKl zedN6+3+uGHejJp;Q==pskSAcRcyh@6mjm2z-uG;s%dM-u0*u##7OxI7wwyCGpS?4U zBFAr(%GBv5j$jS@@t@iI8?ZqE36I^4t+P^J9D^ELbS5KMtZ z{Qn#JnSd$15nJ$ggkF%I4yUQC+BjDF^}AtB7w348EL>7#sAsLWs}ndp8^DsAcOIL9 zTOO!!0!k2`9BLk25)NeZp7ev>I1Mn={cWI3Yhx2Q#DnAo4IphoV~R^c0x&nw*MoIV zPthX?{6{u}sMS(MxD*dmd5rU(YazQE59b|TsB5Tm)I4a!VaN@HYOR)DwH1U5y(E)z zQqQU*B%MwtRQ$%x&;1p%ANmc|PkoFJZ%<-uq%PX&C!c-7ypis=eP+FCeuv+B@h#{4 zGx1m0PjS~FJt}3mdt4c!lel`1;4W|03kcZRG+DzkTy|7-F~eDsV2Tx!73dM0H0CTh zl)F-YUkE1zEzEW(;JXc|KR5{ox%YTh{$%F$a36JP6Nb<0%#NbSh$dMYF-{ z1_x(Vx)}fs?5_|!5xBTWiiIQHG<%)*e=45Fhjw_tlnmlixq;mUdC$R8v#j( zhQ$9YR-o%i5Uc`S?6EC51!bTRK=Xkyb<18FkCKnS2;o*qlij1YA@-nRpq#OMTX&RbL<^2q@0qja!uIvI;j$6>~k@IMwD42=8$$!+R^@5o6HX(*n~