Repository: ardalis/CleanArchitecture Branch: main Commit: cae04fcabc9a Files: 495 Total size: 2.1 MB Directory structure: gitextract_pjis_cnn/ ├── .aspire/ │ └── settings.json ├── .editorconfig ├── .github/ │ ├── CONTRIBUTING.md │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── config.yml │ │ └── feature_request.md │ ├── copilot-instructions.md │ ├── dependabot.yml │ └── workflows/ │ ├── build-ramdisk.yml │ ├── codeql-analysis.yml │ ├── dotnetcore.yml │ ├── publish-templates.yml │ └── publish.yml ├── .gitignore ├── .runsettings ├── .template.config/ │ └── template.json ├── .vscode/ │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Clean.Architecture.slnx ├── CleanArchitecture.nuspec ├── Directory.Build.props ├── Directory.Packages.props ├── LICENSE ├── MinimalClean/ │ ├── .editorconfig │ ├── .gitignore │ ├── .runsettings │ ├── .template.config/ │ │ └── template.json │ ├── Directory.Build.props │ ├── Directory.Packages.props │ ├── MinimalClean.Architecture.slnx │ ├── README.template.md │ ├── global.json │ └── src/ │ ├── MinimalClean.Architecture.AspireHost/ │ │ ├── AppHost.cs │ │ ├── MinimalClean.Architecture.AspireHost.csproj │ │ ├── Properties/ │ │ │ └── launchSettings.json │ │ ├── appsettings.Development.json │ │ └── appsettings.json │ ├── MinimalClean.Architecture.ServiceDefaults/ │ │ ├── Extensions.cs │ │ └── MinimalClean.Architecture.ServiceDefaults.csproj │ └── MinimalClean.Architecture.Web/ │ ├── AssemblyInfo.cs │ ├── CartFeatures/ │ │ ├── AddToCart/ │ │ │ ├── AddToCartEndpoint.cs │ │ │ └── AddToCartHandler.cs │ │ ├── CartDto.cs │ │ ├── CartResponse.cs │ │ ├── Checkout/ │ │ │ ├── CheckoutEndpoint.cs │ │ │ └── CheckoutHandler.cs │ │ └── GetById/ │ │ ├── GetByIdEndpoint.cs │ │ └── GetCartHandler.cs │ ├── Configurations/ │ │ ├── DatabaseOptions.cs │ │ ├── LoggerConfigs.cs │ │ ├── LoggingBehavior.cs │ │ ├── MediatorConfig.cs │ │ ├── MiddlewareConfig.cs │ │ ├── OptionConfigs.cs │ │ └── ServiceConfigs.cs │ ├── Constants.cs │ ├── Domain/ │ │ ├── CartAggregate/ │ │ │ ├── Cart.cs │ │ │ ├── CartId.cs │ │ │ ├── CartItem.cs │ │ │ ├── CartItemId.cs │ │ │ └── Specifications/ │ │ │ └── CartByIdSpec.cs │ │ ├── GuestUserAggregate/ │ │ │ ├── GuestUser.cs │ │ │ ├── GuestUserId.cs │ │ │ └── Specifications/ │ │ │ ├── GuestUserByEmailSpec.cs │ │ │ └── GuestUserByIdSpec.cs │ │ ├── Interfaces/ │ │ │ └── IEmailSender.cs │ │ ├── OrderAggregate/ │ │ │ ├── Order.cs │ │ │ ├── OrderId.cs │ │ │ ├── OrderItem.cs │ │ │ ├── OrderItemId.cs │ │ │ ├── Price.cs │ │ │ └── Quantity.cs │ │ └── ProductAggregate/ │ │ ├── Product.cs │ │ ├── ProductId.cs │ │ └── Specifications/ │ │ └── ProductByIdSpec.cs │ ├── Extensions/ │ │ └── ResultExtensions.cs │ ├── GlobalUsings.cs │ ├── Infrastructure/ │ │ ├── Data/ │ │ │ ├── AppDbContext.cs │ │ │ ├── AppDbContextExtensions.cs │ │ │ ├── AppDbContextFactory.cs │ │ │ ├── Config/ │ │ │ │ ├── CartConfiguration.cs │ │ │ │ ├── CartItemConfiguration.cs │ │ │ │ ├── DataSchemaConstants.cs │ │ │ │ ├── GuestUserConfiguration.cs │ │ │ │ ├── OrderConfiguration.cs │ │ │ │ ├── OrderItemConfiguration.cs │ │ │ │ ├── ProductConfiguration.cs │ │ │ │ ├── VogenEfCoreConverters.cs │ │ │ │ ├── VogenGuidIdValueGenerator.cs │ │ │ │ └── VogenIntIdValueGenerator.cs │ │ │ ├── EfRepository.cs │ │ │ ├── EventDispatcherInterceptor.cs │ │ │ ├── Migrations/ │ │ │ │ ├── 20251020223304_Initial.Designer.cs │ │ │ │ ├── 20251020223304_Initial.cs │ │ │ │ ├── 20251024232246_AddGuestUsersAndOrdersSqlServer.Designer.cs │ │ │ │ ├── 20251024232246_AddGuestUsersAndOrdersSqlServer.cs │ │ │ │ └── AppDbContextModelSnapshot.cs │ │ │ ├── Queries/ │ │ │ │ └── ListProductsQueryService.cs │ │ │ └── SeedData.cs │ │ ├── Email/ │ │ │ ├── FakeEmailSender.cs │ │ │ ├── MailserverConfiguration.cs │ │ │ └── MimeKitEmailSender.cs │ │ └── InfrastructureServiceExtensions.cs │ ├── MinimalClean.Architecture.Web.csproj │ ├── PagedResult.cs │ ├── ProductFeatures/ │ │ ├── Create/ │ │ │ └── CreateEndpoint.cs │ │ ├── GetById/ │ │ │ ├── GetByIdEndpoint.cs │ │ │ └── GetProductHandler.cs │ │ ├── List/ │ │ │ ├── IListProductsQueryService.cs │ │ │ ├── ListEndpoint.cs │ │ │ └── ListProductsHandler.cs │ │ ├── ProductDto.cs │ │ └── ProductRecord.cs │ ├── Program.cs │ ├── Properties/ │ │ └── launchSettings.json │ ├── api.http │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── config.nsdepcop │ └── wwwroot/ │ └── .gitkeep ├── MinimalClean.nuspec ├── PARALLEL_TEST_EXECUTION.md ├── README.md ├── README.template.md ├── TESTCONTAINERS_IMPLEMENTATION.md ├── docs/ │ ├── architecture-decisions/ │ │ ├── README.md │ │ └── adr-001-dotnet-di-adoption.md │ └── minimal-clean-architecture.md ├── global.json ├── nuget.config ├── sample/ │ ├── .editorconfig │ ├── .github/ │ │ └── copilot-instructions.md │ ├── .runsettings │ ├── Directory.Build.props │ ├── Directory.Packages.props │ ├── NimblePros.SampleToDo.slnx │ ├── src/ │ │ ├── NimblePros.SampleToDo.AspireHost/ │ │ │ ├── NimblePros.SampleToDo.AspireHost.csproj │ │ │ ├── Program.cs │ │ │ ├── Properties/ │ │ │ │ └── launchSettings.json │ │ │ ├── appsettings.Development.json │ │ │ └── appsettings.json │ │ ├── NimblePros.SampleToDo.Core/ │ │ │ ├── ContributorAggregate/ │ │ │ │ ├── Contributor.cs │ │ │ │ ├── ContributorId.cs │ │ │ │ ├── ContributorName.cs │ │ │ │ ├── Events/ │ │ │ │ │ ├── ContributorDeletedEvent.cs │ │ │ │ │ └── ContributorNameUpdatedEvent.cs │ │ │ │ ├── Handlers/ │ │ │ │ │ ├── ContributorDeletedHandler.cs │ │ │ │ │ └── ContributorNameUpdatedEventLoggingHandler.cs │ │ │ │ └── Specifications/ │ │ │ │ └── ContributorByIdSpec.cs │ │ │ ├── CoreServiceExtensions.cs │ │ │ ├── GlobalUsings.cs │ │ │ ├── Interfaces/ │ │ │ │ ├── IDeleteContributorService.cs │ │ │ │ ├── IEmailSender.cs │ │ │ │ └── IToDoItemSearchService.cs │ │ │ ├── Localization.cs │ │ │ ├── NimblePros.SampleToDo.Core.csproj │ │ │ ├── ProjectAggregate/ │ │ │ │ ├── Events/ │ │ │ │ │ ├── ContributorAddedToItemEvent.cs │ │ │ │ │ ├── NewItemAddedEvent.cs │ │ │ │ │ └── ToDoItemCompletedEvent.cs │ │ │ │ ├── Handlers/ │ │ │ │ │ ├── ContributorAddedToItemLoggingHandler.cs │ │ │ │ │ ├── ItemCompletedEmailNotificationHandler.cs │ │ │ │ │ └── NewItemAddedLoggingHandler.cs │ │ │ │ ├── Priority.cs │ │ │ │ ├── Project.cs │ │ │ │ ├── ProjectErrorMessages.cs │ │ │ │ ├── ProjectId.cs │ │ │ │ ├── ProjectName.cs │ │ │ │ ├── ProjectStatus.cs │ │ │ │ ├── Specifications/ │ │ │ │ │ ├── IncompleteItemsSearchSpec.cs │ │ │ │ │ ├── IncompleteItemsSpec.cs │ │ │ │ │ ├── ProjectByIdWithItemsSpec.cs │ │ │ │ │ └── ProjectsWithItemsByContributorId.cs │ │ │ │ ├── ToDoItem.cs │ │ │ │ ├── ToDoItemDescription.cs │ │ │ │ ├── ToDoItemId.cs │ │ │ │ └── ToDoItemTitle.cs │ │ │ └── Services/ │ │ │ ├── DeleteContributorService.cs │ │ │ └── ToDoItemSearchService.cs │ │ ├── NimblePros.SampleToDo.Infrastructure/ │ │ │ ├── Data/ │ │ │ │ ├── AppDbContext.cs │ │ │ │ ├── Config/ │ │ │ │ │ ├── ContributorConfiguration.cs │ │ │ │ │ ├── DataSchemaConstants.cs │ │ │ │ │ ├── ProjectConfiguration.cs │ │ │ │ │ ├── ToDoItemConfiguration.cs │ │ │ │ │ ├── VogenEfCoreConverters.cs │ │ │ │ │ └── VogenIdValueGenerator.cs │ │ │ │ ├── EfRepository.cs │ │ │ │ ├── EventDispatchInterceptor.cs │ │ │ │ └── Queries/ │ │ │ │ ├── FakeListContributorsQueryService.cs │ │ │ │ ├── FakeListIncompleteItemsQueryService.cs │ │ │ │ ├── FakeListProjectsShallowQueryService.cs │ │ │ │ ├── ListContributorsQueryService.cs │ │ │ │ ├── ListIncompleteItemsQueryService.cs │ │ │ │ └── ListProjectsShallowQueryService.cs │ │ │ ├── Email/ │ │ │ │ ├── FakeEmailSender.cs │ │ │ │ ├── MailserverConfiguration.cs │ │ │ │ ├── MimeKitEmailSender.cs │ │ │ │ └── SmtpEmailSender.cs │ │ │ ├── GlobalUsings.cs │ │ │ ├── InfrastructureServiceExtensions.cs │ │ │ └── NimblePros.SampleToDo.Infrastructure.csproj │ │ ├── NimblePros.SampleToDo.ServiceDefaults/ │ │ │ ├── Extensions.cs │ │ │ └── NimblePros.SampleToDo.ServiceDefaults.csproj │ │ ├── NimblePros.SampleToDo.UseCases/ │ │ │ ├── Constants.cs │ │ │ ├── Contributors/ │ │ │ │ ├── Commands/ │ │ │ │ │ ├── Create/ │ │ │ │ │ │ ├── CreateContributorCommand.cs │ │ │ │ │ │ └── CreateContributorHandler.cs │ │ │ │ │ ├── Delete/ │ │ │ │ │ │ ├── DeleteContributorCommand.cs │ │ │ │ │ │ └── DeleteContributorHandler.cs │ │ │ │ │ └── Update/ │ │ │ │ │ ├── UpdateContributorCommand.cs │ │ │ │ │ └── UpdateContributorHandler.cs │ │ │ │ ├── ContributorDTO.cs │ │ │ │ └── Queries/ │ │ │ │ ├── Get/ │ │ │ │ │ ├── GetContributorHandler.cs │ │ │ │ │ └── GetContributorQuery.cs │ │ │ │ └── List/ │ │ │ │ ├── IListContributorsQueryService.cs │ │ │ │ ├── ListContributorsHandler.cs │ │ │ │ └── ListContributorsQuery.cs │ │ │ ├── GlobalUsings.cs │ │ │ ├── ICacheable.cs │ │ │ ├── NimblePros.SampleToDo.UseCases.csproj │ │ │ ├── PagedResult.cs │ │ │ ├── Projects/ │ │ │ │ ├── AddToDoItem/ │ │ │ │ │ ├── AddToDoItemCommand.cs │ │ │ │ │ └── AddToDoItemHandler.cs │ │ │ │ ├── Create/ │ │ │ │ │ ├── CreateProjectCommand.cs │ │ │ │ │ └── CreateProjectHandler.cs │ │ │ │ ├── Delete/ │ │ │ │ │ ├── DeleteProjectCommand.cs │ │ │ │ │ └── DeleteProjectHandler.cs │ │ │ │ ├── GetWithAllItems/ │ │ │ │ │ ├── GetProjectWithAllItemsHandler.cs │ │ │ │ │ └── GetProjectWithAllItemsQuery.cs │ │ │ │ ├── ListIncompleteItems/ │ │ │ │ │ ├── IListIncompleteItemsQueryService.cs │ │ │ │ │ ├── ListIncompleteItemsByProjectHandler.cs │ │ │ │ │ └── ListIncompleteItemsByProjectQuery.cs │ │ │ │ ├── ListShallow/ │ │ │ │ │ ├── IListProjectsShallowQueryService.cs │ │ │ │ │ ├── ListProjectsShallowHandler.cs │ │ │ │ │ └── ListProjectsShallowQuery.cs │ │ │ │ ├── MarkToDoItemComplete/ │ │ │ │ │ ├── MarkToDoItemCompleteCommand.cs │ │ │ │ │ └── MarkToDoItemCompleteHandler.cs │ │ │ │ ├── ProjectDTO.cs │ │ │ │ ├── ProjectWithAllItemsDTO.cs │ │ │ │ ├── ToDoItemDTO.cs │ │ │ │ └── Update/ │ │ │ │ ├── UpdateProjectCommand.cs │ │ │ │ └── UpdateProjectHandler.cs │ │ │ └── README.md │ │ └── NimblePros.SampleToDo.Web/ │ │ ├── CachingBehavior.cs │ │ ├── Configurations/ │ │ │ ├── CachingOptions.cs │ │ │ ├── CachingProfile.cs │ │ │ ├── GlobalExceptionHandler.cs │ │ │ ├── LoggerConfig.cs │ │ │ ├── MediatorConfig.cs │ │ │ ├── MiddlewareConfig.cs │ │ │ ├── OptionConfigs.cs │ │ │ └── ServiceConfigs.cs │ │ ├── Contributors/ │ │ │ ├── ContributorRecord.cs │ │ │ ├── Create.cs │ │ │ ├── Delete.DeleteContributorRequest.cs │ │ │ ├── Delete.DeleteContributorValidator.cs │ │ │ ├── Delete.cs │ │ │ ├── GetById.GetContributorByIdMapper.cs │ │ │ ├── GetById.GetContributorByIdRequest.cs │ │ │ ├── GetById.GetContributorValidator.cs │ │ │ ├── GetById.cs │ │ │ ├── List.ContributorListResponse.cs │ │ │ ├── List.cs │ │ │ ├── Update.UpdateContributorRequest.cs │ │ │ ├── Update.UpdateContributorResponse.cs │ │ │ ├── Update.UpdateContributorValidator.cs │ │ │ └── Update.cs │ │ ├── Extensions/ │ │ │ └── ResultExtensions.cs │ │ ├── GlobalUsings.cs │ │ ├── LoggingBehavior.cs │ │ ├── NimblePros.SampleToDo.Web.csproj │ │ ├── Program.cs │ │ ├── Projects/ │ │ │ ├── Create.CreateProjectRequest.cs │ │ │ ├── Create.CreateProjectResponse.cs │ │ │ ├── Create.CreateProjectValidator.cs │ │ │ ├── Create.cs │ │ │ ├── CreateToDoItem.CreateToDoItemRequest.cs │ │ │ ├── CreateToDoItem.CreateToDoItemValidator.cs │ │ │ ├── CreateToDoItem.cs │ │ │ ├── Delete.DeleteProjectRequest.cs │ │ │ ├── Delete.DeleteProjectValidator.cs │ │ │ ├── Delete.cs │ │ │ ├── GetById.GetProjectByIdRequest.cs │ │ │ ├── GetById.GetProjectByIdResponse.cs │ │ │ ├── GetById.GetProjectByIdValidator.cs │ │ │ ├── GetById.cs │ │ │ ├── List.ProjectListResponse.cs │ │ │ ├── List.cs │ │ │ ├── ListIncompleteItems.ListIncompleteItemsRequest.cs │ │ │ ├── ListIncompleteItems.ListIncompleteItemsResponse.cs │ │ │ ├── ListIncompleteItems.cs │ │ │ ├── MarkItemComplete.MarkItemCompleteRequest.cs │ │ │ ├── MarkItemComplete.cs │ │ │ ├── ProjectRecord.cs │ │ │ ├── ToDoItemRecord.cs │ │ │ ├── Update.UpdateProjectRequest.cs │ │ │ ├── Update.UpdateProjectRequestValidator.cs │ │ │ ├── Update.UpdateProjectResponse.cs │ │ │ └── Update.cs │ │ ├── Properties/ │ │ │ └── launchSettings.json │ │ ├── SeedData.cs │ │ ├── api.http │ │ ├── appsettings.json │ │ ├── i18n/ │ │ │ ├── en/ │ │ │ │ └── Project.json │ │ │ ├── fa/ │ │ │ │ └── Project.json │ │ │ └── fr/ │ │ │ └── Project.json │ │ └── wwwroot/ │ │ ├── css/ │ │ │ └── site.css │ │ ├── js/ │ │ │ └── site.js │ │ └── lib/ │ │ ├── bootstrap/ │ │ │ ├── LICENSE │ │ │ └── dist/ │ │ │ ├── css/ │ │ │ │ ├── bootstrap-grid.css │ │ │ │ ├── bootstrap-grid.rtl.css │ │ │ │ ├── bootstrap-reboot.css │ │ │ │ ├── bootstrap-reboot.rtl.css │ │ │ │ ├── bootstrap-utilities.css │ │ │ │ ├── bootstrap-utilities.rtl.css │ │ │ │ ├── bootstrap.css │ │ │ │ └── bootstrap.rtl.css │ │ │ └── js/ │ │ │ ├── bootstrap.bundle.js │ │ │ ├── bootstrap.esm.js │ │ │ └── bootstrap.js │ │ ├── jquery/ │ │ │ ├── LICENSE.txt │ │ │ └── dist/ │ │ │ └── jquery.js │ │ ├── jquery-validation/ │ │ │ ├── LICENSE.md │ │ │ └── dist/ │ │ │ ├── additional-methods.js │ │ │ └── jquery.validate.js │ │ └── jquery-validation-unobtrusive/ │ │ ├── LICENSE.txt │ │ └── jquery.validate.unobtrusive.js │ └── tests/ │ ├── NimblePros.SampleToDo.FunctionalTests/ │ │ ├── Contributors/ │ │ │ ├── ContributorCreate.cs │ │ │ ├── ContributorDelete.cs │ │ │ ├── ContributorGetById.cs │ │ │ ├── ContributorList.cs │ │ │ └── ContributorUpdate.cs │ │ ├── CustomWebApplicationFactory.cs │ │ ├── Fixtures/ │ │ │ └── SmtpServerFixture.cs │ │ ├── GlobalUsings.cs │ │ ├── NimblePros.SampleToDo.FunctionalTests.csproj │ │ ├── Projects/ │ │ │ ├── CreateToDoItemRequestBuilder.cs │ │ │ ├── ProjectAddToDoItem.cs │ │ │ ├── ProjectCreate.cs │ │ │ ├── ProjectGetById.cs │ │ │ ├── ProjectItemMarkComplete.cs │ │ │ └── ProjectList.cs │ │ ├── TestBase.cs │ │ └── xunit.runner.json │ ├── NimblePros.SampleToDo.IntegrationTests/ │ │ ├── Data/ │ │ │ ├── BaseEfRepoTestFixture.cs │ │ │ ├── EfRepositoryAdd.cs │ │ │ ├── EfRepositoryDelete.cs │ │ │ └── EfRepositoryUpdate.cs │ │ ├── GlobalUsings.cs │ │ └── NimblePros.SampleToDo.IntegrationTests.csproj │ └── NimblePros.SampleToDo.UnitTests/ │ ├── Core/ │ │ ├── ContributorAggregate/ │ │ │ ├── ContributorConstructor.cs │ │ │ └── ContributorIdFrom.cs │ │ ├── Handlers/ │ │ │ └── ItemCompletedEmailNotificationHandlerHandle.cs │ │ ├── ProjectAggregate/ │ │ │ ├── ProjectConstructor.cs │ │ │ ├── ProjectNameFrom.cs │ │ │ ├── Project_AddItem.cs │ │ │ ├── ToDoItemConstructor.cs │ │ │ └── ToDoItemMarkComplete.cs │ │ ├── Services/ │ │ │ ├── DeleteContributorSevice_DeleteContributor.cs │ │ │ ├── ToDoItemSearchServiceTests.cs │ │ │ ├── ToDoItemSearchService_GetAllIncompleteItems.cs │ │ │ └── ToDoItemSearchService_GetNextIncompleteItem.cs │ │ └── Specifications/ │ │ └── IncompleteItemSpecificationsConstructor.cs │ ├── GlobalUsings.cs │ ├── NimblePros.SampleToDo.UnitTests.csproj │ ├── NoOpMediator.cs │ ├── ToDoItemBuilder.cs │ ├── UseCases/ │ │ └── Contributors/ │ │ ├── CreateContributorHandlerHandle.cs │ │ ├── GetContributorHandlerHandle.cs │ │ └── UpdateContributorHandlerHandle.cs │ └── xunit.runner.json ├── src/ │ ├── Clean.Architecture.AspireHost/ │ │ ├── AppHost.cs │ │ ├── Clean.Architecture.AspireHost.csproj │ │ ├── GlobalUsings.cs │ │ ├── Properties/ │ │ │ └── launchSettings.json │ │ ├── README.md │ │ ├── appsettings.Development.json │ │ └── appsettings.json │ ├── Clean.Architecture.Core/ │ │ ├── Clean.Architecture.Core.csproj │ │ ├── Clean.Architecture.Core.sln │ │ ├── ContributorAggregate/ │ │ │ ├── Contributor.cs │ │ │ ├── ContributorId.cs │ │ │ ├── ContributorName.cs │ │ │ ├── ContributorStatus.cs │ │ │ ├── Events/ │ │ │ │ ├── ContributorDeletedEvent.cs │ │ │ │ └── ContributorNameUpdatedEvent.cs │ │ │ ├── Handlers/ │ │ │ │ ├── ContributorDeletedHandler.cs │ │ │ │ └── ContributorNameUpdatedEmailNotificationHandler.cs │ │ │ ├── PhoneNumber.cs │ │ │ └── Specifications/ │ │ │ └── ContributorByIdSpec.cs │ │ ├── GlobalUsings.cs │ │ ├── Interfaces/ │ │ │ ├── IDeleteContributorService.cs │ │ │ └── IEmailSender.cs │ │ ├── README.md │ │ └── Services/ │ │ └── DeleteContributorService.cs │ ├── Clean.Architecture.Infrastructure/ │ │ ├── Clean.Architecture.Infrastructure.csproj │ │ ├── Data/ │ │ │ ├── AppDbContext.cs │ │ │ ├── AppDbContextExtensions.cs │ │ │ ├── Config/ │ │ │ │ ├── ContributorConfiguration.cs │ │ │ │ ├── DataSchemaConstants.cs │ │ │ │ ├── VogenEfCoreConverters.cs │ │ │ │ └── VogenIdValueGenerator.cs │ │ │ ├── EfRepository.cs │ │ │ ├── EventDispatcherInterceptor.cs │ │ │ ├── Migrations/ │ │ │ │ ├── 20231218143922_PhoneNumber.Designer.cs │ │ │ │ ├── 20231218143922_PhoneNumber.cs │ │ │ │ ├── 20251113164108_UpdateForNet10.Designer.cs │ │ │ │ ├── 20251113164108_UpdateForNet10.cs │ │ │ │ └── AppDbContextModelSnapshot.cs │ │ │ ├── Queries/ │ │ │ │ ├── FakeListContributorsQueryService.cs │ │ │ │ └── ListContributorsQueryService.cs │ │ │ └── SeedData.cs │ │ ├── Email/ │ │ │ ├── FakeEmailSender.cs │ │ │ ├── MailserverConfiguration.cs │ │ │ └── MimeKitEmailSender.cs │ │ ├── GlobalUsings.cs │ │ ├── InfrastructureServiceExtensions.cs │ │ └── README.md │ ├── Clean.Architecture.ServiceDefaults/ │ │ ├── Clean.Architecture.ServiceDefaults.csproj │ │ └── Extensions.cs │ ├── Clean.Architecture.UseCases/ │ │ ├── Clean.Architecture.UseCases.csproj │ │ ├── Constants.cs │ │ ├── Contributors/ │ │ │ ├── ContributorDTO.cs │ │ │ ├── Create/ │ │ │ │ ├── CreateContributorCommand.cs │ │ │ │ └── CreateContributorHandler.cs │ │ │ ├── Delete/ │ │ │ │ ├── DeleteContributorCommand.cs │ │ │ │ └── DeleteContributorHandler.cs │ │ │ ├── Get/ │ │ │ │ ├── GetContributorHandler.cs │ │ │ │ └── GetContributorQuery.cs │ │ │ ├── List/ │ │ │ │ ├── IListContributorsQueryService.cs │ │ │ │ ├── ListContributorsHandler.cs │ │ │ │ └── ListContributorsQuery.cs │ │ │ └── Update/ │ │ │ ├── UpdateContributorCommand.cs │ │ │ └── UpdateContributorHandler.cs │ │ ├── GlobalUsings.cs │ │ ├── PagedResult.cs │ │ └── README.md │ └── Clean.Architecture.Web/ │ ├── Clean.Architecture.Web.csproj │ ├── Configurations/ │ │ ├── LoggerConfigs.cs │ │ ├── MediatorConfig.cs │ │ ├── MiddlewareConfig.cs │ │ ├── OptionConfigs.cs │ │ └── ServiceConfigs.cs │ ├── Contributors/ │ │ ├── ContributorRecord.cs │ │ ├── Create.cs │ │ ├── Delete.DeleteContributorRequest.cs │ │ ├── Delete.DeleteContributorValidator.cs │ │ ├── Delete.cs │ │ ├── GetById.GetContributorByIdRequest.cs │ │ ├── GetById.GetContributorValidator.cs │ │ ├── GetById.cs │ │ ├── List.cs │ │ ├── Update.UpdateContributorRequest.cs │ │ ├── Update.UpdateContributorResponse.cs │ │ ├── Update.UpdateContributorValidator.cs │ │ └── Update.cs │ ├── Extensions/ │ │ └── ResultExtensions.cs │ ├── GlobalUsings.cs │ ├── Program.cs │ ├── Properties/ │ │ └── launchSettings.json │ ├── api.http │ ├── appsettings.Development.json │ ├── appsettings.Testing.json │ ├── appsettings.json │ └── wwwroot/ │ └── .gitkeep └── tests/ ├── Clean.Architecture.AspireTests/ │ ├── AspireIntegrationTests.cs │ └── Clean.Architecture.AspireTests.csproj ├── Clean.Architecture.FunctionalTests/ │ ├── ApiEndpoints/ │ │ ├── ContributorGetById.cs │ │ └── ContributorList.cs │ ├── Clean.Architecture.FunctionalTests.csproj │ ├── CustomWebApplicationFactory.cs │ ├── DockerAvailabilityTests.cs │ ├── GlobalUsings.cs │ └── xunit.runner.json ├── Clean.Architecture.IntegrationTests/ │ ├── Clean.Architecture.IntegrationTests.csproj │ ├── Data/ │ │ ├── BaseEfRepoTestFixture.cs │ │ ├── EfRepositoryAdd.cs │ │ ├── EfRepositoryDelete.cs │ │ └── EfRepositoryUpdate.cs │ ├── GlobalUsings.cs │ └── xunit.runner.json └── Clean.Architecture.UnitTests/ ├── Clean.Architecture.UnitTests.csproj ├── Core/ │ ├── ContributorAggregate/ │ │ ├── ContributorConstructor.cs │ │ ├── ContributorIdFrom.cs │ │ ├── ContributorNameFrom.cs │ │ └── ContributorUpdateName.cs │ └── Services/ │ ├── DeleteContributorSevice_DeleteContributor.cs │ ├── ToDoItemSearchService_GetAllIncompleteItems.cs │ └── ToDoItemSearchService_GetNextIncompleteItem.cs ├── GlobalUsings.cs ├── NoOpMediator.cs ├── UseCases/ │ └── Contributors/ │ └── CreateContributorHandlerHandle.cs └── xunit.runner.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .aspire/settings.json ================================================ { "appHostPath": "../src/Clean.Architecture.AspireHost/Clean.Architecture.AspireHost.csproj" } ================================================ FILE: .editorconfig ================================================ ############################### # Core EditorConfig Options # ############################### root = true # All files [*] indent_style = space # XML project files [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] indent_size = 2 # XML config files [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] indent_size = 2 # Code files [*.{cs,csx,vb,vbx}] indent_size = 2 insert_final_newline = true charset = utf-8-bom ############################### # .NET Coding Conventions # ############################### [*.{cs,vb}] # Organize usings dotnet_sort_system_directives_first = true # this. preferences dotnet_style_qualification_for_field = false:silent dotnet_style_qualification_for_property = false:silent dotnet_style_qualification_for_method = false:silent dotnet_style_qualification_for_event = false:silent # Language keywords vs BCL types preferences dotnet_style_predefined_type_for_locals_parameters_members = true:silent dotnet_style_predefined_type_for_member_access = true:silent # Parentheses preferences dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent # Modifier preferences dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent dotnet_style_readonly_field = true:suggestion # Expression-level preferences dotnet_style_object_initializer = true:suggestion dotnet_style_collection_initializer = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_coalesce_expression = true:suggestion dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent dotnet_style_prefer_inferred_tuple_names = true:suggestion dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion dotnet_style_prefer_auto_properties = true:silent dotnet_style_prefer_conditional_expression_over_assignment = true:silent dotnet_style_prefer_conditional_expression_over_return = true:silent ############################### # Naming Conventions # ############################### # Style Definitions dotnet_naming_style.pascal_case_style.capitalization = pascal_case # Use PascalCase for constant fields dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style dotnet_naming_symbols.constant_fields.applicable_kinds = field dotnet_naming_symbols.constant_fields.applicable_accessibilities = * dotnet_naming_symbols.constant_fields.required_modifiers = const tab_width= 2 dotnet_naming_rule.private_members_with_underscore.symbols = private_fields dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore dotnet_naming_rule.private_members_with_underscore.severity = suggestion dotnet_naming_symbols.private_fields.applicable_kinds = field dotnet_naming_symbols.private_fields.applicable_accessibilities = private dotnet_naming_style.prefix_underscore.capitalization = camel_case dotnet_naming_style.prefix_underscore.required_prefix = _ dotnet_style_operator_placement_when_wrapping = beginning_of_line end_of_line = crlf ############################### # C# Coding Conventions # ############################### [*.cs] # var preferences csharp_style_var_for_built_in_types = true:silent csharp_style_var_when_type_is_apparent = true:silent csharp_style_var_elsewhere = true:silent # Expression-bodied members csharp_style_expression_bodied_methods = false:silent csharp_style_expression_bodied_constructors = false:silent csharp_style_expression_bodied_operators = false:silent csharp_style_expression_bodied_properties = true:silent csharp_style_expression_bodied_indexers = true:silent csharp_style_expression_bodied_accessors = true:silent # Pattern matching preferences csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion csharp_style_pattern_matching_over_as_with_null_check = true:suggestion # Null-checking preferences csharp_style_throw_expression = true:suggestion csharp_style_conditional_delegate_call = true:suggestion # Modifier preferences csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion # Expression-level preferences csharp_prefer_braces = true:silent csharp_style_deconstructed_variable_declaration = true:suggestion csharp_prefer_simple_default_expression = true:suggestion csharp_style_pattern_local_over_anonymous_function = true:suggestion csharp_style_inlined_variable_declaration = true:suggestion # Namespaces csharp_style_namespace_declarations = file_scoped:warning ############################### # C# Formatting Rules # ############################### # New line preferences csharp_new_line_before_open_brace = all csharp_new_line_before_else = true csharp_new_line_before_catch = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_between_query_expression_clauses = true # Indentation preferences csharp_indent_case_contents = true csharp_indent_switch_labels = true csharp_indent_labels = flush_left # Space preferences csharp_space_after_cast = false csharp_space_after_keywords_in_control_flow_statements = true csharp_space_between_method_call_parameter_list_parentheses = false csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_space_before_colon_in_inheritance_clause = true csharp_space_after_colon_in_inheritance_clause = true csharp_space_around_binary_operators = before_and_after csharp_space_between_method_declaration_empty_parameter_list_parentheses = false csharp_space_between_method_call_name_and_opening_parenthesis = false csharp_space_between_method_call_empty_parameter_list_parentheses = false # Wrapping preferences csharp_preserve_single_line_statements = true csharp_preserve_single_line_blocks = true csharp_using_directive_placement = outside_namespace:suggestion csharp_prefer_simple_using_statement = true:suggestion csharp_style_prefer_method_group_conversion = true:silent csharp_style_prefer_top_level_statements = true:silent csharp_style_prefer_primary_constructors = true:suggestion csharp_style_expression_bodied_lambdas = true:silent csharp_style_expression_bodied_local_functions = false:silent ############################### # VB Coding Conventions # ############################### [*.vb] # Modifier preferences visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion ================================================ FILE: .github/CONTRIBUTING.md ================================================ # Contributing to CleanArchitecture **First:** if you're unsure or afraid of _anything_, just ask or submit the issue or pull request anyways. You won't be yelled at for giving your best effort. The worst that can happen is that you'll be politely asked to change something. We appreciate any sort of contributions, and don't want a wall of rules to get in the way of that. However, for those individuals who want a bit more guidance on the best way to contribute to the project, read on. This document will cover what we're looking for. By addressing all the points we're looking for, it raises the chances we can quickly merge or address your contributions. ## Issues ### Reporting an Issue * Make sure you test against the latest released version. It is possible we already fixed the bug you're experiencing. * If you can, check and see if there is an existing open issue that is already reporting the problem. Feel free to upvote this issue or comment on it to describe your specific scenario (assuming it's the same underlying issue). * Provide a reproducible test case. If a contributor can't reproduce an issue, then it dramatically lowers the chances it'll get fixed. And in some cases, the issue will eventually be closed. * Respond promptly to any questions made by the maintainers about your issue. Stale issues will be closed (eventually). ## Pull Requests * Pull requests are welcome but are most likely to be accepted when they address an existing issue. A common workflow is to create an issue describing the problem your PR would solve, and then volunteer to submit a PR addressing the issue as an initial comment on the issue. * As much as possible, pull requests should follow the existing coding conventions used by the project. This is generally true for any project. The only exception to this would be a pull request whose purpose is to adjust the coding conventions used by the project. * When possible, issues will be marked with a `help wanted` tag if community contributions are particularly welcome for them. This will often be the case for relatively simple fixes that would make good initial contributions. * If your PR addresses an issue, please include "Fixes #NNN" in the summary for the PR so that the issue is linked to the PR (and vice versa) and if/when the PR is merged, the issue is automatically closed. Thank you for reading this and for considering contributing to this project! ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [ardalis] ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve --- - .NET SDK Version: Steps to Reproduce: 1. 2. ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: Question url: https://stackoverflow.com/questions/tagged/ardalis-cleanarchitecture about: Please ask and answer questions on Stack Overflow. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project --- ================================================ FILE: .github/copilot-instructions.md ================================================ # GitHub Copilot Instructions for Clean Architecture Template ## Project Overview This is a **Clean Architecture template** for .NET 9 that demonstrates Domain-Driven Design (DDD) patterns. It's a starter template, not a reference application - delete sample code once you understand the patterns. ## Architecture & Project Structure ### C# Conventions - Use standard Microsoft naming conventions - Use `PascalCase` for types and methods, `camelCase` for parameters and private fields - Use `I` prefix for interfaces (e.g., `IRepository`) - Use `Async` suffix for async methods (e.g., `GetByIdAsync`) - Prefix private fields with `_` (e.g., `_repository`) - Always use {} for blocks except single-line exits (e.g. `return`, `throw`) - Always keep single line blocks on one line (e.g., `if (x) return y;`) - Prefer primary constructors for required dependencies - Never use primary constructor parameters directly - always assign to private fields for clarity and testability ### Core Dependencies Flow - **Core** ← UseCases ← Infrastructure - **Core** ← UseCases ← Web - Never allow Core to depend on outer layers ### Key Projects - **Core**: Domain entities, aggregates, value objects, specifications, interfaces - **UseCases**: Commands/queries (CQRS), Mediator handlers, application logic - **Infrastructure**: EF Core, external services, email, file access - **Web**: FastEndpoints API, REPR pattern, validation ## Development Patterns ### API Endpoints (FastEndpoints + REPR) - One endpoint per file: `Create.cs`, `Update.cs`, `Delete.cs`, `GetById.cs` - Separate request/response/validator files: `Create.CreateRequest.cs`, `Create.CreateValidator.cs` - Use `Endpoint` base class - Example: `src/Clean.Architecture.Web/Contributors/Create.cs` ### Domain Model (Core) - Entities use encapsulation - minimize public setters - Group related entities into Aggregates - Use Value Objects (e.g., `ContributorName.From()`) - Domain Events for cross-aggregate communication - Repository interfaces defined in Core, implemented in Infrastructure ### Use Cases (CQRS) - Commands for mutations, Queries for reads - Queries can bypass repository pattern for performance - Use Mediator (source generator) for command/query handling - Chain of responsibility for cross-cutting concerns (logging, validation) ### Validation Strategy - **API Level**: FluentValidation on request DTOs (FastEndpoints integration) - **Use Case Level**: Validate commands/queries (defensive coding) - **Domain Level**: Business invariants throw exceptions, assume pre-validated input ## Essential Commands ### Build & Test ```bash dotnet build Clean.Architecture.slnx dotnet test Clean.Architecture.slnx ``` ### Entity Framework Migrations ```bash # From Web project directory dotnet ef migrations add MigrationName -c AppDbContext -p ../Clean.Architecture.Infrastructure/Clean.Architecture.Infrastructure.csproj -s Clean.Architecture.Web.csproj -o Data/Migrations dotnet ef database update -c AppDbContext -p ../Clean.Architecture.Infrastructure/Clean.Architecture.Infrastructure.csproj -s Clean.Architecture.Web.csproj ``` ### Template Installation & Usage ```bash dotnet new install Ardalis.CleanArchitecture.Template dotnet new clean-arch -o Your.ProjectName ``` ## Key Dependencies & Patterns ### Primary Libraries - **FastEndpoints**: API endpoints (replaced Controllers/Minimal APIs) - **Mediator**: Command/query handling in UseCases - **EF Core**: Data access (SQLite default, easily changed to SQL Server) - **Ardalis.Specification**: Repository query specifications - **Ardalis.Result**: Error handling pattern - **Serilog**: Structured logging ### Central Package Management - All package versions in `Directory.Packages.props` - Use `` without Version attribute ### Test Organization - **UnitTests**: Core business logic, use cases - **IntegrationTests**: Database, infrastructure components - **FunctionalTests**: API endpoints (subcutaneous testing) - Use `Microsoft.AspNetCore.Mvc.Testing` for API tests ## File Organization Conventions ### Web Project Structure ``` Contributors/ Create.cs # Endpoint Create.CreateRequest.cs # Request DTO Create.CreateResponse.cs # Response DTO Create.CreateValidator.cs # FluentValidation Update.cs, Delete.cs, etc. ``` ### Sample vs Template - `/sample` folder: Complete working example (NimblePros.SampleToDo) - `/src` folder: Clean template ready for your project - Study sample for patterns, use src for new projects ## Common Gotchas - Don't include hyphens in project names (template limitation) - Replace `Ardalis.SharedKernel` with your own shared kernel - Database path in `appsettings.json` for SQLite - Use absolute paths in EF migration commands - FastEndpoints uses different validation approach than Controller-based APIs ## VS Code Tasks Use the predefined tasks: `build`, `publish`, `watch` instead of manual `dotnet` commands when possible. ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: nuget directory: "/" schedule: interval: daily open-pull-requests-limit: 10 ================================================ FILE: .github/workflows/build-ramdisk.yml ================================================ name: Build and Test with Ramdisk on: push: branches: - main pull_request: jobs: build-and-test: runs-on: ubuntu-latest steps: # Step 1: Checkout the repository - name: Checkout Code uses: actions/checkout@v3 # Step 2: Set up .NET environment - name: Setup .NET uses: actions/setup-dotnet@v5 with: dotnet-version: 10.0.x # Step 3: Prepare a directory in /dev/shm - name: Set up Ramdisk Directory run: | mkdir -p /dev/shm/ramdisk/project # Step 4: Copy source code to the ramdisk - name: Copy Code to Ramdisk run: | cp -r $GITHUB_WORKSPACE/* /dev/shm/ramdisk/project # Step 5: Debug Directory Contents - name: Debug Directory run: | ls -R /dev/shm/ramdisk/project # Step 6: Build and Test from the ramdisk - name: Build and Test run: | cd /dev/shm/ramdisk/project dotnet build Clean.Architecture.slnx --configuration Debug dotnet test Clean.Architecture.slnx -- ================================================ FILE: .github/workflows/codeql-analysis.yml ================================================ name: CodeQL Analysis on: push: branches: [ main ] pull_request: schedule: - cron: '0 8 * * *' jobs: analyze: name: CodeQL Analysis runs-on: ubuntu-latest steps: - name: Checkout repository id: checkout_repo uses: actions/checkout@v4 - name: Initialize CodeQL id: init_codeql uses: github/codeql-action/init@v3 with: queries: security-and-quality - name: Autobuild uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis id: analyze_codeql uses: github/codeql-action/analyze@v3 # Built with ❤ by [Pipeline Foundation](https://pipeline.foundation) ================================================ FILE: .github/workflows/dotnetcore.yml ================================================ name: .NET Core on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v5 with: dotnet-version: '10.0.x' - name: Build Full Template run: dotnet build ./Clean.Architecture.slnx -c Release - name: Test Full Template run: dotnet test ./Clean.Architecture.slnx -c Release --no-build --verbosity normal - name: Build MinimalClean Template run: dotnet build ./MinimalClean/MinimalClean.Architecture.slnx -c Release ================================================ FILE: .github/workflows/publish-templates.yml ================================================ name: Publish Templates to NuGet on: workflow_dispatch: inputs: publish-full: description: 'Publish Full Clean Architecture Template' required: true type: boolean default: false publish-minimal: description: 'Publish Minimal Clean Architecture Template' required: true type: boolean default: false push: tags: - 'v*' release: types: [published] env: DOTNET_VERSION: '10.0.x' PACK_OUTPUT: artifacts/packages jobs: build-and-test: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} - name: Build Full Template Solution run: dotnet build ./Clean.Architecture.slnx -c Release - name: Test Full Template run: dotnet test ./Clean.Architecture.slnx -c Release --no-build --verbosity normal - name: Build MinimalClean Template Solution run: dotnet build ./MinimalClean/MinimalClean.Architecture.slnx -c Release - name: Test Template Installations shell: pwsh run: | # Test Full Template # Write-Host "Testing Full Clean Architecture Template..." # dotnet new install . # dotnet new clean-arch -o TestFullTemplate # dotnet build TestFullTemplate/TestFullTemplate.slnx # dotnet new uninstall Ardalis.CleanArchitecture.Template # Remove-Item -Recurse -Force TestFullTemplate # Test Minimal Template # Write-Host "Testing Minimal Clean Architecture Template..." # dotnet new install ./MinimalClean # dotnet new min-clean -o TestMinimalTemplate # dotnet build TestMinimalTemplate/TestMinimalTemplate.slnx # dotnet new uninstall Ardalis.MinimalClean.Template # Remove-Item -Recurse -Force TestMinimalTemplate package: needs: build-and-test runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup NuGet uses: nuget/setup-nuget@v2 with: nuget-version: 'latest' - name: Install Mono run: sudo apt-get update && sudo apt-get install -y mono-complete - name: Create output directory run: mkdir -p ${{ env.PACK_OUTPUT }} - name: Pack Full Template if: ${{ github.event_name == 'release' || github.event.inputs.publish-full == 'true' }} run: nuget pack CleanArchitecture.nuspec -OutputDirectory ${{ env.PACK_OUTPUT }} -NoDefaultExcludes - name: Pack Minimal Template if: ${{ github.event_name == 'release' || github.event.inputs.publish-minimal == 'true' }} run: nuget pack MinimalClean.nuspec -OutputDirectory ${{ env.PACK_OUTPUT }} -NoDefaultExcludes - name: Upload packages as artifacts uses: actions/upload-artifact@v4 with: name: nuget-packages path: ${{ env.PACK_OUTPUT }}/*.nupkg publish: needs: package runs-on: ubuntu-latest #if: ${{ github.event_name == 'release' && github.event.action == 'published' }} permissions: contents: read id-token: write steps: - name: Download packages uses: actions/download-artifact@v4 with: name: nuget-packages path: ${{ env.PACK_OUTPUT }} - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} - name: NuGet login (OIDC) uses: NuGet/login@v1 id: login with: user: ${{ secrets.NUGET_USER }} - name: Push packages to NuGet shell: pwsh run: | Get-ChildItem "${{ env.PACK_OUTPUT }}" -Filter *.nupkg | ForEach-Object { Write-Host "Publishing $($_.Name)..." dotnet nuget push $_.FullName ` --api-key "${{ steps.login.outputs.NUGET_API_KEY }}" ` --source https://api.nuget.org/v3/index.json ` --skip-duplicate } ================================================ FILE: .github/workflows/publish.yml ================================================ name: Publish to Nuget on: workflow_dispatch: push: tags: - 'v*' release: types: [published] env: SOLUTION_FILE: Clean.Architecture.slnx NUSPEC_FILE: CleanArchitecture.nuspec PACK_OUTPUT: artifacts/package/release jobs: build: permissions: contents: read id-token: write runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup dotnet uses: actions/setup-dotnet@v4 with: dotnet-version: 10.0.x - name: Build run: dotnet build "${{ env.SOLUTION_FILE }}" --configuration Release - name: Test run: dotnet test "${{ env.SOLUTION_FILE }}" --configuration Release --no-build --no-restore - uses: nuget/setup-nuget@v2 name: Setup NuGet with: nuget-version: 'latest' - name: Install Mono run: sudo apt-get update && sudo apt-get install -y mono-complete - name: Pack (nuspec) run: nuget pack "${{ env.NUSPEC_FILE }}" -OutputDirectory "${{ env.PACK_OUTPUT }}" -NoDefaultExcludes - name: NuGet login (OIDC -> temp API key) uses: NuGet/login@v1 id: login with: user: ${{ secrets.NUGET_USER }} - name: Push to NuGet #if: ${{ github.event_name == 'release' && github.event.action == 'published' && github.event.release.tag_name != '' }} shell: pwsh run: | Get-ChildItem "${{ env.PACK_OUTPUT }}" -Filter *.nupkg | ForEach-Object { dotnet nuget push $_.FullName ` --api-key "${{ steps.login.outputs.NUGET_API_KEY }}" ` --source https://api.nuget.org/v3/index.json } ================================================ FILE: .gitignore ================================================ ## 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 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 *.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 *.sqlite *.sqlite-shm *.sqlite-wal # Nuget files DeploymentSettings.props Packages.props #Local Log Files log*.txt /sample/src/NimblePros.SampleToDo.Web/appsettings.Development.json ================================================ FILE: .runsettings ================================================ 0 false true true 0 ================================================ FILE: .template.config/template.json ================================================ { "$schema": "http://json.schemastore.org/template", "author": "ardalis (Steve Smith)", "classifications": [ "Web", "ASP.NET", "Clean Architecture" ], "tags": { "language": "C#", "type": "project" }, "identity": "Ardalis.CleanArchitecture.Template", "name": "ASP.NET Clean Architecture Solution", "shortName": "clean-arch", "sourceName": "Clean.Architecture", "templateFileExtensions": [ ".cs", ".csproj", ".slnx" ], "preferNameDirectory": true, "sources": [ { "include": [ "**/*" ], "exclude": [ ".vs/**", ".vscode/**", ".git/**", ".github/**", ".idea/**", ".template.config/**", "docs/**", "sample/**" ], "modifiers": [ { "condition": "true", "copyOnly": [ "*.dll", "*.png", "*.ico", "*.jpg", "*.jpeg", "*.ps1" ] }, { "rename": { "README.template.md": "README.md" } } ] } ] } ================================================ FILE: .vscode/launch.json ================================================ { "version": "0.2.0", "configurations": [ { // Use IntelliSense to find out which attributes exist for C# debugging // Use hover for the description of the existing attributes // For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md. "name": ".NET Core Launch (web)", "type": "coreclr", "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. "program": "${workspaceFolder}/src/Clean.Architecture.Web/bin/Debug/net8.0/Clean.Architecture.Web.dll", "args": [], "cwd": "${workspaceFolder}/src/Clean.Architecture.Web", "stopAtEntry": false, // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser "serverReadyAction": { "action": "openExternally", "pattern": "\\bNow listening on:\\s+(https?://\\S+)" }, "env": { "ASPNETCORE_ENVIRONMENT": "Development" }, "sourceFileMap": { "/Views": "${workspaceFolder}/Views" } }, { "name": ".NET Core Attach", "type": "coreclr", "request": "attach" } ] } ================================================ FILE: .vscode/settings.json ================================================ { "workbench.colorCustomizations": { "activityBar.activeBackground": "#6b9a8e", "activityBar.background": "#6b9a8e", "activityBar.foreground": "#15202b", "activityBar.inactiveForeground": "#15202b99", "activityBarBadge.background": "#684e72", "activityBarBadge.foreground": "#e7e7e7", "commandCenter.border": "#e7e7e799", "sash.hoverBorder": "#6b9a8e", "statusBar.background": "#557d73", "statusBar.foreground": "#e7e7e7", "statusBarItem.hoverBackground": "#6b9a8e", "statusBarItem.remoteBackground": "#557d73", "statusBarItem.remoteForeground": "#e7e7e7", "titleBar.activeBackground": "#557d73", "titleBar.activeForeground": "#e7e7e7", "titleBar.inactiveBackground": "#557d7399", "titleBar.inactiveForeground": "#e7e7e799" }, "peacock.color": "#557d73" } ================================================ FILE: .vscode/tasks.json ================================================ { "version": "2.0.0", "tasks": [ { "label": "build", "command": "dotnet", "type": "process", "args": [ "build", "${workspaceFolder}/Clean.Architecture.slnx", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary;ForceNoAlign" ], "problemMatcher": "$msCompile" }, { "label": "publish", "command": "dotnet", "type": "process", "args": [ "publish", "${workspaceFolder}/Clean.Architecture.slnx", "/property:GenerateFullPaths=true", "/consoleloggerparameters:NoSummary;ForceNoAlign" ], "problemMatcher": "$msCompile" }, { "label": "watch", "command": "dotnet", "type": "process", "args": [ "watch", "run", "--project", "${workspaceFolder}/Clean.Architecture.slnx" ], "problemMatcher": "$msCompile" } ] } ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Code of Conduct This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Ardalis.CleanArchitecture We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's: - Reporting a bug - Discussing the current state of the code - Submitting a fix - Proposing new features ## We Develop with GitHub Obviously... ## We Use Pull Requests Mostly. But pretty much exclusively for non-maintainers. You'll need to fork the repo in order to submit a pull request. Here are the basic steps: 1. Fork the repo and create your branch from `main`. 2. If you've added code that should be tested, add tests. 3. If you've changed APIs, update the documentation. 4. Ensure the test suite passes. 5. Make sure your code lints. 6. Issue that pull request! - [Pull Request Check List](https://ardalis.com/github-pull-request-checklist/) - [Resync your fork with this upstream repo](https://ardalis.com/syncing-a-fork-of-a-github-repository-with-upstream/) ## Ask before adding a pull request You can just add a pull request out of the blue if you want, but it's much better etiquette (and more likely to be accepted) if you open a new issue or comment in an existing issue stating you'd like to make a pull request. ## Getting Started Look for [issues marked with 'help wanted'](https://github.com/ardalis/CleanArchitecture/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) to find good places to start contributing. ## Any contributions you make will be under the MIT Software License In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers this project. ## Report bugs using Github's [issues](https://github.com/ardalis/CleanArchitecture/issues) We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/ardalis/CleanArchitecture/issues/new/choose); it's that easy! ## Sponsor us If you don't have the time or expertise to contribute code, you can still support us by [sponsoring](https://github.com/sponsors/ardalis). ================================================ FILE: Clean.Architecture.slnx ================================================ ================================================ FILE: CleanArchitecture.nuspec ================================================ Ardalis.CleanArchitecture.Template ASP.NET Core Clean Architecture Solution 11.0.1 Steve Smith The Clean Architecture Solution Template popularized by Steve @ardalis Smith. Provides a great starting point for modern and/or DDD solutions built with .NET 10. Features zero tight coupling to database or data access technology. en-US MIT https://github.com/ardalis/CleanArchitecture * Update dependencies. Web ASP.NET "Clean Architecture" ddd domain-driven-design clean-architecture clean architecture ardalis SOLID ./content/icon.png README.md ================================================ FILE: Directory.Build.props ================================================ true true true net10.0 enable enable latest 1591 ================================================ FILE: Directory.Packages.props ================================================ ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2016 Steve Smith Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: MinimalClean/.editorconfig ================================================ ############################### # Core EditorConfig Options # ############################### root = true # All files [*] indent_style = space # XML project files [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] indent_size = 2 # XML config files [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] indent_size = 2 # Code files [*.{cs,csx,vb,vbx}] indent_size = 2 insert_final_newline = true charset = utf-8-bom ############################### # .NET Coding Conventions # ############################### [*.{cs,vb}] # Organize usings dotnet_sort_system_directives_first = true # this. preferences dotnet_style_qualification_for_field = false:silent dotnet_style_qualification_for_property = false:silent dotnet_style_qualification_for_method = false:silent dotnet_style_qualification_for_event = false:silent # Language keywords vs BCL types preferences dotnet_style_predefined_type_for_locals_parameters_members = true:silent dotnet_style_predefined_type_for_member_access = true:silent # Parentheses preferences dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent # Modifier preferences dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent dotnet_style_readonly_field = true:suggestion # Expression-level preferences dotnet_style_object_initializer = true:suggestion dotnet_style_collection_initializer = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_coalesce_expression = true:suggestion dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent dotnet_style_prefer_inferred_tuple_names = true:suggestion dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion dotnet_style_prefer_auto_properties = true:silent dotnet_style_prefer_conditional_expression_over_assignment = true:silent dotnet_style_prefer_conditional_expression_over_return = true:silent ############################### # Naming Conventions # ############################### # Style Definitions dotnet_naming_style.pascal_case_style.capitalization = pascal_case # Use PascalCase for constant fields dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style dotnet_naming_symbols.constant_fields.applicable_kinds = field dotnet_naming_symbols.constant_fields.applicable_accessibilities = * dotnet_naming_symbols.constant_fields.required_modifiers = const tab_width= 2 dotnet_naming_rule.private_members_with_underscore.symbols = private_fields dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore dotnet_naming_rule.private_members_with_underscore.severity = suggestion dotnet_naming_symbols.private_fields.applicable_kinds = field dotnet_naming_symbols.private_fields.applicable_accessibilities = private dotnet_naming_style.prefix_underscore.capitalization = camel_case dotnet_naming_style.prefix_underscore.required_prefix = _ dotnet_style_operator_placement_when_wrapping = beginning_of_line end_of_line = crlf ############################### # C# Coding Conventions # ############################### [*.cs] # var preferences csharp_style_var_for_built_in_types = true:silent csharp_style_var_when_type_is_apparent = true:silent csharp_style_var_elsewhere = true:silent # Expression-bodied members csharp_style_expression_bodied_methods = false:silent csharp_style_expression_bodied_constructors = false:silent csharp_style_expression_bodied_operators = false:silent csharp_style_expression_bodied_properties = true:silent csharp_style_expression_bodied_indexers = true:silent csharp_style_expression_bodied_accessors = true:silent # Pattern matching preferences csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion csharp_style_pattern_matching_over_as_with_null_check = true:suggestion # Null-checking preferences csharp_style_throw_expression = true:suggestion csharp_style_conditional_delegate_call = true:suggestion # Modifier preferences csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion # Expression-level preferences csharp_prefer_braces = true:silent csharp_style_deconstructed_variable_declaration = true:suggestion csharp_prefer_simple_default_expression = true:suggestion csharp_style_pattern_local_over_anonymous_function = true:suggestion csharp_style_inlined_variable_declaration = true:suggestion # Namespaces csharp_style_namespace_declarations = file_scoped:warning ############################### # C# Formatting Rules # ############################### # New line preferences csharp_new_line_before_open_brace = all csharp_new_line_before_else = true csharp_new_line_before_catch = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_between_query_expression_clauses = true # Indentation preferences csharp_indent_case_contents = true csharp_indent_switch_labels = true csharp_indent_labels = flush_left # Space preferences csharp_space_after_cast = false csharp_space_after_keywords_in_control_flow_statements = true csharp_space_between_method_call_parameter_list_parentheses = false csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_space_before_colon_in_inheritance_clause = true csharp_space_after_colon_in_inheritance_clause = true csharp_space_around_binary_operators = before_and_after csharp_space_between_method_declaration_empty_parameter_list_parentheses = false csharp_space_between_method_call_name_and_opening_parenthesis = false csharp_space_between_method_call_empty_parameter_list_parentheses = false # Wrapping preferences csharp_preserve_single_line_statements = true csharp_preserve_single_line_blocks = true csharp_using_directive_placement = outside_namespace:suggestion csharp_prefer_simple_using_statement = true:suggestion csharp_style_prefer_method_group_conversion = true:silent csharp_style_prefer_top_level_statements = true:silent csharp_style_prefer_primary_constructors = true:suggestion csharp_style_expression_bodied_lambdas = true:silent csharp_style_expression_bodied_local_functions = false:silent ############################### # VB Coding Conventions # ############################### [*.vb] # Modifier preferences visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion ================================================ FILE: MinimalClean/.gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.userosscache *.sln.docstates # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ build/ bld/ [Bb]in/ [Oo]bj/ # Visual Studio 2015/2017/2019/2022 cache/options directory .vs/ .vscode/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUnit *.VisualState.xml TestResult.xml nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # .NET Core project.lock.json project.fragment.lock.json artifacts/ # ASP.NET Scaffolding ScaffoldingReadMe.txt # Database files *.db *.db-shm *.db-wal *.sqlite *.sqlite3 # Entity Framework Core migrations (keep migrations folder, ignore db files) **/Migrations/*.db # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Mac desktop service store files .DS_Store # JetBrains Rider .idea/ *.sln.iml # CodeRush .cr/ # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # 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 # 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 orleans.codegen.cs # 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 *.ndf # 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 node_modules/ # Typescript v1 declaration files typings/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # 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/ # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs ================================================ FILE: MinimalClean/.runsettings ================================================ 0 false true true 0 ================================================ FILE: MinimalClean/.template.config/template.json ================================================ { "$schema": "http://json.schemastore.org/template", "author": "ardalis (Steve Smith)", "classifications": [ "Web", "ASP.NET", "Clean Architecture", "Minimal" ], "tags": { "language": "C#", "type": "project" }, "identity": "Ardalis.MinimalClean.Template", "name": "ASP.NET Minimal Clean Architecture Solution", "shortName": "min-clean", "sourceName": "MinimalClean.Architecture", "templateFileExtensions": [ ".cs", ".csproj", ".slnx" ], "preferNameDirectory": true, "sources": [ { "include": [ "**/*" ], "exclude": [ ".vs/**", ".vscode/**", ".git/**", ".github/**", ".idea/**", ".template.config/**", "**/bin/**", "**/obj/**", "**/.vs/**" ], "modifiers": [ { "condition": "true", "copyOnly": [ "*.dll", "*.png", "*.ico", "*.jpg", "*.jpeg", "*.ps1" ] }, { "rename": { "README.template.md": "README.md" } } ] } ] } ================================================ FILE: MinimalClean/Directory.Build.props ================================================ true true net10.0 enable enable latest 1591 ================================================ FILE: MinimalClean/Directory.Packages.props ================================================ ================================================ FILE: MinimalClean/MinimalClean.Architecture.slnx ================================================ ================================================ FILE: MinimalClean/README.template.md ================================================ # MinimalClean.Architecture Welcome to your new project generated with the **Minimal Clean Architecture** template! This is a streamlined, single-project Vertical Slice Architecture (VSA) that follows Clean Architecture principles without the overhead of multiple projects. Perfect for smaller applications, MVPs, or teams that want architectural guidance without complex project boundaries. ## Getting Started ### Build and Run ```powershell # Build the solution dotnet build # Run the application dotnet run --project src/MinimalClean.Architecture.Web # Or run with Aspire (if using) dotnet run --project src/MinimalClean.Architecture.AspireHost ``` ### Database Setup This template uses **SQL Server in a container** managed by Aspire. When you run the Aspire AppHost, it automatically starts a SQL Server container and creates the database. #### Option 1: Run with Aspire (Recommended) ```powershell dotnet run --project src/MinimalClean.Architecture.AspireHost ``` The SQL Server container and database are automatically provisioned and migrations are applied on startup. #### Option 2: Run Web project directly (SQL Server LocalDB) If running the Web project without Aspire, update `appsettings.json` to use LocalDB: ```powershell dotnet ef database update -c AppDbContext -p src/MinimalClean.Architecture.Web -s src/MinimalClean.Architecture.Web dotnet run --project src/MinimalClean.Architecture.Web ``` ## Project Structure This template uses a **single Web project** organized by **vertical slices** (features): ```text src/MinimalClean.Architecture.Web/ ├── Domain/ # Domain entities and aggregates │ ├── CartAggregate/ │ ├── OrderAggregate/ │ └── ProductAggregate/ ├── Infrastructure/ # Data access and external services │ ├── Data/ │ │ ├── AppDbContext.cs │ │ ├── Config/ # EF Core configurations │ │ └── Migrations/ │ └── Email/ # Email services ├── Endpoints/ # API endpoints (FastEndpoints) │ ├── Cart/ │ ├── Order/ │ └── Product/ └── Program.cs # Application startup ``` ### Key Design Decisions ```text Single project vertical slice architecture ``` - **Single Project**: All code in one Web project - simpler dependencies, faster builds - **Vertical Slices**: Organized by feature (Cart, Order, Product) not layer - **Domain-Driven Design**: Entities use proper encapsulation and business logic - **FastEndpoints**: REPR pattern for clean, testable API endpoints - **Entity Framework Core**: Simple data access with SQLite (easily switched to SQL Server) - **Mediator Pattern**: Optional - use for cross-cutting concerns or remove for simplicity ## What's Different from Full Clean Architecture? This minimal template simplifies the full Clean Architecture template: | Full Template | Minimal Template | |--------------|------------------| | 4+ projects (Core, UseCases, Infrastructure, Web) | 1 Web project | | Repository pattern with Specifications | Repository pattern with Specifications if needed | | Extensive use of interfaces and abstractions | Pragmatic abstractions where needed | | Separate Use Cases project with Mediator | Optional Mediator; logic can be in endpoints | | Complex domain patterns (Aggregates, Value Objects, Domain Events) | Pragmatic DDD patterns (Aggregates, Value Objects) | ## When to Use This Template **Use Minimal Clean Architecture when:** - ✓ Building MVPs or smaller applications - ✓ You want architectural guidance without project ceremony - ✓ Team prefers simplicity and fast iteration - ✓ Vertical slice architecture appeals to you - ✓ You may grow into full Clean Architecture later **Use Full Clean Architecture when:** - × Building large, complex enterprise applications - × Multiple teams working on different layers - × Need strict separation of concerns and dependencies - × Domain complexity requires extensive DDD patterns - × Long-term maintenance and evolution expected ## Technology Stack - **.NET 10**: Latest LTS framework - **FastEndpoints**: REPR pattern for API endpoints - **Entity Framework Core**: Data access with migrations - **SQL Server**: Containerized database via Aspire (easily switched to PostgreSQL, SQLite, etc.) - **Aspire**: Cloud-ready orchestration and observability - **Serilog**: Structured logging - **FluentValidation**: Request validation ## Common Tasks ### Adding a New Feature (Vertical Slice) 1. **Create Domain Entity**: Add to `Domain/YourFeatureAggregate/` 2. **Add EF Configuration**: Create config in `Infrastructure/Data/Config/` 3. **Create Migration**: `dotnet ef migrations add AddYourFeature` 4. **Create Endpoints**: Add FastEndpoints in `Endpoints/YourFeature/` ### Switching to SQL Server Update `appsettings.json`: ```json { "ConnectionStrings": { "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=YourDb;Trusted_Connection=true;" } } ``` ### Running Tests ```powershell dotnet test ``` ## Migration Path to Full Clean Architecture As your application grows, you can migrate to the full Clean Architecture template: 1. **Extract Core**: Move Domain entities to separate Core project 2. **Extract UseCases**: Move business logic to UseCases project with Mediator 3. **Extract Infrastructure**: Move data access to Infrastructure project 4. **Update Dependencies**: Set up proper dependency flow (Core ← UseCases ← Infrastructure) Learn more: [Clean Architecture Template](https://github.com/ardalis/CleanArchitecture) ## Resources - [Clean Architecture Template Repository](https://github.com/ardalis/CleanArchitecture) - [Vertical Slice Architecture](https://jimmybogard.com/vertical-slice-architecture/) - [FastEndpoints Documentation](https://fast-endpoints.com/) - [Ardalis on YouTube](https://www.youtube.com/@Ardalis) ## Need Help? - Report issues: [GitHub Issues](https://github.com/ardalis/CleanArchitecture/issues) - Ask questions: [Discussions](https://github.com/ardalis/CleanArchitecture/discussions) - Follow updates: [@ardalis](https://twitter.com/ardalis) --- **Happy Coding!** 🚀 ================================================ FILE: MinimalClean/global.json ================================================ { "sdk": { "version": "10.0.100", "rollForward": "latestMajor", "allowPrerelease": true } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.AspireHost/AppHost.cs ================================================ using System.Net.Sockets; var builder = DistributedApplication.CreateBuilder(args); // Add SQL Server container var sqlServer = builder.AddSqlServer("sqlserver") .WithLifetime(ContainerLifetime.Persistent); // Add the database var appDb = sqlServer.AddDatabase("AppDb"); // Papercut SMTP container for email testing var papercut = builder.AddContainer("papercut", "jijiechen/papercut", "latest") .WithEndpoint("smtp", e => { e.TargetPort = 25; // container port e.Port = 25; // host port e.Protocol = ProtocolType.Tcp; e.UriScheme = "smtp"; }) .WithEndpoint("ui", e => { e.TargetPort = 37408; e.Port = 37408; e.UriScheme = "http"; }); // register the API project and link the DB builder.AddProject("web") .WithEnvironment("ASPNETCORE_ENVIRONMENT", builder.Environment.EnvironmentName) .WithReference(appDb) .WaitFor(papercut) .WaitFor(appDb) .WithUrl("https://localhost:57379"); // Match launchSettings builder.Build().Run(); ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.AspireHost/MinimalClean.Architecture.AspireHost.csproj ================================================  Exe 47f99468-f41d-48b8-ae3f-69682954d973 ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.AspireHost/Properties/launchSettings.json ================================================ { "$schema": "https://json.schemastore.org/launchsettings.json", "profiles": { "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "applicationUrl": "https://localhost:17143;http://localhost:15258", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "DOTNET_ENVIRONMENT": "Development", "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21007", "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22245" } }, "http": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "applicationUrl": "http://localhost:15258", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "DOTNET_ENVIRONMENT": "Development", "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19187", "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20134" } } } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.AspireHost/appsettings.Development.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.AspireHost/appsettings.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning", "Aspire.Hosting.Dcp": "Warning" } } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.ServiceDefaults/Extensions.cs ================================================ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.ServiceDiscovery; using OpenTelemetry; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; namespace Microsoft.Extensions.Hosting; // Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry. // This project should be referenced by each service project in your solution. // To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults public static class Extensions { private const string HealthEndpointPath = "/health"; private const string AlivenessEndpointPath = "/alive"; public static TBuilder AddServiceDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder { builder.ConfigureOpenTelemetry(); builder.AddDefaultHealthChecks(); builder.Services.AddServiceDiscovery(); builder.Services.ConfigureHttpClientDefaults(http => { // Turn on resilience by default http.AddStandardResilienceHandler(); // Turn on service discovery by default http.AddServiceDiscovery(); }); // Uncomment the following to restrict the allowed schemes for service discovery. // builder.Services.Configure(options => // { // options.AllowedSchemes = ["https"]; // }); return builder; } public static TBuilder ConfigureOpenTelemetry(this TBuilder builder) where TBuilder : IHostApplicationBuilder { builder.Logging.AddOpenTelemetry(logging => { logging.IncludeFormattedMessage = true; logging.IncludeScopes = true; }); builder.Services.AddOpenTelemetry() .WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddRuntimeInstrumentation(); }) .WithTracing(tracing => { tracing.AddSource(builder.Environment.ApplicationName) .AddAspNetCoreInstrumentation(tracing => // Exclude health check requests from tracing tracing.Filter = context => !context.Request.Path.StartsWithSegments(HealthEndpointPath) && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath) ) // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) //.AddGrpcClientInstrumentation() .AddHttpClientInstrumentation(); }); builder.AddOpenTelemetryExporters(); return builder; } private static TBuilder AddOpenTelemetryExporters(this TBuilder builder) where TBuilder : IHostApplicationBuilder { var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); if (useOtlpExporter) { builder.Services.AddOpenTelemetry().UseOtlpExporter(); } // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) //{ // builder.Services.AddOpenTelemetry() // .UseAzureMonitor(); //} return builder; } public static TBuilder AddDefaultHealthChecks(this TBuilder builder) where TBuilder : IHostApplicationBuilder { builder.Services.AddHealthChecks() // Add a default liveness check to ensure app is responsive .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); return builder; } public static WebApplication MapDefaultEndpoints(this WebApplication app) { // Adding health checks endpoints to applications in non-development environments has security implications. // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. if (app.Environment.IsDevelopment()) { // All health checks must pass for app to be considered ready to accept traffic after starting app.MapHealthChecks(HealthEndpointPath); // Only health checks tagged with the "live" tag must pass for app to be considered alive app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions { Predicate = r => r.Tags.Contains("live") }); } return app; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.ServiceDefaults/MinimalClean.Architecture.ServiceDefaults.csproj ================================================ true ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/AssemblyInfo.cs ================================================ using Vogen; [assembly: VogenDefaults( staticAbstractsGeneration: StaticAbstractsGeneration.MostCommon | StaticAbstractsGeneration.InstanceMethodsAndProperties)] namespace MinimalClean.Architecture.Web; public class AssemblyInfo { } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/AddToCart/AddToCartEndpoint.cs ================================================ using FluentValidation; using Microsoft.AspNetCore.Http.HttpResults; using MinimalClean.Architecture.Web.Domain.CartAggregate; namespace MinimalClean.Architecture.Web.CartFeatures.AddToCart; public sealed class AddToCartRequest { public const string Route = "/cart"; public Guid? CartId { get; init; } public int ProductId { get; init; } public int Quantity { get; init; } } public class AddToCartEndpoint(IMediator mediator) : FastEndpoints.Endpoint, NotFound, ValidationProblem, ProblemHttpResult>, AddToCartMapper> { public override void Configure() { Post(AddToCartRequest.Route); AllowAnonymous(); Summary(s => { s.Summary = "Add item to cart"; s.Description = "Adds a product to an existing cart or creates a new cart if CartId is not provided. Returns the updated cart with all items."; s.ExampleRequest = new AddToCartRequest { CartId = null, // null creates new cart ProductId = 1, Quantity = 2 }; s.ResponseExamples[200] = new CartResponse( Guid.Empty, new List { new(1, 2, 999.99m, 1999.98m) }, 1999.98m); // Document possible responses s.Responses[200] = "Item added to cart successfully"; s.Responses[404] = "Product or Cart not found"; s.Responses[400] = "Invalid request data"; }); // Add tags for API grouping Tags("Cart"); // Add additional metadata Description(builder => builder .Accepts("application/json") .Produces(200, "application/json") .ProducesProblem(404) .ProducesProblem(400)); } public override async Task, NotFound, ValidationProblem, ProblemHttpResult>> ExecuteAsync(AddToCartRequest request, CancellationToken ct) { var cartId = request.CartId.HasValue ? CartId.From(request.CartId.Value) : (CartId?)null; var command = new AddToCartCommand(cartId, request.ProductId, request.Quantity); var result = await mediator.Send(command, ct); if (result.Status == ResultStatus.NotFound) { return TypedResults.NotFound(); } if (!result.IsSuccess) { return TypedResults.Problem(result.Errors.FirstOrDefault() ?? "An error occurred"); } var response = Map.FromEntity(result.Value); return TypedResults.Ok(response); } } public sealed class AddToCartValidator : FastEndpoints.Validator { public AddToCartValidator() { RuleFor(x => x.ProductId) .GreaterThan(0) .WithMessage("Product ID must be greater than 0"); RuleFor(x => x.Quantity) .GreaterThan(0) .WithMessage("Quantity must be greater than 0"); } } public sealed class AddToCartMapper : FastEndpoints.Mapper { public override CartResponse FromEntity(CartDto e) { var items = e.Items.Select(i => new CartItemResponse( i.ProductId, i.Quantity, i.UnitPrice, i.TotalPrice )).ToList(); return new CartResponse(e.Id.Value, items, e.Total); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/AddToCart/AddToCartHandler.cs ================================================ using MinimalClean.Architecture.Web.Domain.CartAggregate; using MinimalClean.Architecture.Web.Domain.CartAggregate.Specifications; using MinimalClean.Architecture.Web.Domain.ProductAggregate; using MinimalClean.Architecture.Web.Domain.ProductAggregate.Specifications; namespace MinimalClean.Architecture.Web.CartFeatures.AddToCart; public record AddToCartCommand(CartId? CartId, int ProductId, int Quantity) : ICommand>; public class AddToCartHandler( IRepository cartRepository, IReadRepository productRepository) : ICommandHandler> { public async ValueTask> Handle(AddToCartCommand request, CancellationToken cancellationToken) { // Validate product exists var productSpec = new ProductByIdSpec(ProductId.From(request.ProductId)); var product = await productRepository.FirstOrDefaultAsync(productSpec, cancellationToken); if (product == null) { return Result.NotFound("Product not found"); } // Get or create cart Cart cart; if (request.CartId.HasValue) { var cartSpec = new CartByIdSpec(request.CartId.Value); var existingCart = await cartRepository.FirstOrDefaultAsync(cartSpec, cancellationToken); if (existingCart == null) { return Result.NotFound("Cart not found"); } cart = existingCart; } else { // Create new cart - AddAsync saves by default cart = new Cart(); cart = await cartRepository.AddAsync(cart, cancellationToken); } // Add item to cart cart.AddItem(request.ProductId, request.Quantity, product.UnitPrice); // Update the cart with the new items await cartRepository.UpdateAsync(cart, cancellationToken); // Map to DTO var items = cart.Items.Select(i => new CartItemDto( i.ProductId, i.Quantity, i.UnitPrice, i.Quantity * i.UnitPrice )).ToList(); var total = items.Sum(i => i.TotalPrice); return new CartDto(cart.Id, items, total); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/CartDto.cs ================================================ using MinimalClean.Architecture.Web.Domain.CartAggregate; namespace MinimalClean.Architecture.Web.CartFeatures; public record CartDto(CartId Id, IReadOnlyList Items, decimal Total); public record CartItemDto(int ProductId, int Quantity, decimal UnitPrice, decimal TotalPrice); ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/CartResponse.cs ================================================ namespace MinimalClean.Architecture.Web.CartFeatures; public record CartResponse(Guid CartId, IReadOnlyList Items, decimal Total); public record CartItemResponse(int ProductId, int Quantity, decimal UnitPrice, decimal TotalPrice); ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/Checkout/CheckoutEndpoint.cs ================================================ using FastEndpoints; using FluentValidation; using Microsoft.AspNetCore.Http.HttpResults; using MinimalClean.Architecture.Web.Domain.CartAggregate; namespace MinimalClean.Architecture.Web.CartFeatures.Checkout; public sealed class CheckoutRequest { public const string Route = "/cart/{CartId}/checkout"; public Guid CartId { get; init; } public string Email { get; init; } = string.Empty; } public record CheckoutResponse(Guid OrderId); public class CheckoutEndpoint(IMediator mediator) : Endpoint, NotFound, ValidationProblem, ProblemHttpResult>, CheckoutMapper> { public override void Configure() { Post(CheckoutRequest.Route); AllowAnonymous(); Summary(s => { s.Summary = "Checkout cart"; s.Description = "Processes checkout for a cart, creating an order and marking the cart as completed. Requires a guest email address."; s.ExampleRequest = new CheckoutRequest { CartId = Guid.Parse("12345678-1234-1234-1234-123456789012"), Email = "guest@example.com" }; s.ResponseExamples[200] = new CheckoutResponse( Guid.Parse("87654321-4321-4321-4321-210987654321")); // Document possible responses s.Responses[200] = "Checkout completed successfully"; s.Responses[404] = "Cart not found"; s.Responses[400] = "Invalid request data or empty cart"; }); // Add tags for API grouping Tags("Cart"); // Add additional metadata Description(builder => builder .Accepts("application/json") .Produces(200, "application/json") .ProducesProblem(404) .ProducesProblem(400)); } public override async Task, NotFound, ValidationProblem, ProblemHttpResult>> ExecuteAsync(CheckoutRequest request, CancellationToken ct) { var cartId = CartId.From(request.CartId); var command = new CheckoutCommand(cartId, request.Email); var result = await mediator.Send(command, ct); if (result.Status == ResultStatus.NotFound) { return TypedResults.NotFound(); } if (result.Status == ResultStatus.Invalid) { return TypedResults.ValidationProblem(result.ValidationErrors.ToDictionary(e => e.Identifier, e => new[] { e.ErrorMessage })); } if (!result.IsSuccess) { return TypedResults.Problem(result.Errors.FirstOrDefault() ?? "An error occurred during checkout"); } var response = Map.FromEntity(result.Value); return TypedResults.Ok(response); } } public sealed class CheckoutValidator : Validator { public CheckoutValidator() { RuleFor(x => x.CartId) .NotEqual(Guid.Empty) .WithMessage("Cart ID is required"); RuleFor(x => x.Email) .NotEmpty() .WithMessage("Email is required") .EmailAddress() .WithMessage("Email must be a valid email address"); } } public sealed class CheckoutMapper : Mapper { public override CheckoutResponse FromEntity(CheckoutResult e) => new CheckoutResponse(e.OrderId.Value); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/Checkout/CheckoutHandler.cs ================================================ using MinimalClean.Architecture.Web.Domain.CartAggregate; using MinimalClean.Architecture.Web.Domain.CartAggregate.Specifications; using MinimalClean.Architecture.Web.Domain.GuestUserAggregate; using MinimalClean.Architecture.Web.Domain.GuestUserAggregate.Specifications; using MinimalClean.Architecture.Web.Domain.OrderAggregate; using MinimalClean.Architecture.Web.Domain.ProductAggregate; namespace MinimalClean.Architecture.Web.CartFeatures.Checkout; public record CheckoutCommand(CartId CartId, string Email) : ICommand>; public record CheckoutResult(OrderId OrderId); public class CheckoutHandler( IRepository cartRepository, IRepository guestUserRepository, IRepository orderRepository) : ICommandHandler> { public async ValueTask> Handle(CheckoutCommand request, CancellationToken cancellationToken) { // Find the cart with its items var cartSpec = new CartByIdSpec(request.CartId); var cart = await cartRepository.FirstOrDefaultAsync(cartSpec, cancellationToken); if (cart == null) return Result.NotFound("Cart not found"); if (!cart.Items.Any()) return Result.Invalid(new ValidationError("Cart is empty")); // Get or create guest user var guestUserSpec = new GuestUserByEmailSpec(request.Email); var guestUser = await guestUserRepository.FirstOrDefaultAsync(guestUserSpec, cancellationToken); if (guestUser == null) { var guestUserId = GuestUserId.From(Guid.NewGuid()); guestUser = new GuestUser(guestUserId, request.Email); guestUser = await guestUserRepository.AddAsync(guestUser, cancellationToken); } // Create new order var orderId = OrderId.From(Guid.NewGuid()); var order = new Order(orderId, guestUser.Id.Value); // Add items from cart to order foreach (var cartItem in cart.Items) { order.AddItem( ProductId.From(cartItem.ProductId), Quantity.From(cartItem.Quantity), Price.From(cartItem.UnitPrice)); } await orderRepository.AddAsync(order, cancellationToken); cart.MarkAsDeleted(); await cartRepository.UpdateAsync(cart, cancellationToken); return new CheckoutResult(order.Id); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/GetById/GetByIdEndpoint.cs ================================================ using MinimalClean.Architecture.Web.Domain.CartAggregate; using MinimalClean.Architecture.Web.Extensions; using Microsoft.AspNetCore.Http.HttpResults; using FastEndpoints; namespace MinimalClean.Architecture.Web.CartFeatures.GetById; public sealed class GetCartRequest { public const string Route = "/cart/{CartId}"; public Guid CartId { get; init; } } public class GetByIdEndpoint(IMediator mediator) : Endpoint, NotFound, ProblemHttpResult>, GetCartMapper> { public override void Configure() { Get(GetCartRequest.Route); AllowAnonymous(); Summary(s => { s.Summary = "Get cart by ID"; s.Description = "Retrieves a cart and all its items by cart ID."; s.ExampleRequest = new GetCartRequest { CartId = Guid.Parse("12345678-1234-1234-1234-123456789012") }; s.ResponseExamples[200] = new CartResponse( Guid.Parse("12345678-1234-1234-1234-123456789012"), new List { new(1, 2, 999.99m, 1999.98m) }, 1999.98m); // Document possible responses s.Responses[200] = "Cart retrieved successfully"; s.Responses[404] = "Cart not found"; }); // Add tags for API grouping Tags("Cart"); // Add additional metadata Description(builder => builder .Produces(200, "application/json") .ProducesProblem(404)); } public override async Task, NotFound, ProblemHttpResult>> ExecuteAsync(GetCartRequest request, CancellationToken ct) { var cartId = CartId.From(request.CartId); var query = new GetCartQuery(cartId); var result = await mediator.Send(query, ct); return result.ToGetByIdResult(Map.FromEntity); } } public sealed class GetCartMapper : Mapper { public override CartResponse FromEntity(CartDto e) { var items = e.Items.Select(i => new CartItemResponse( i.ProductId, i.Quantity, i.UnitPrice, i.TotalPrice )).ToList(); return new CartResponse(e.Id.Value, items, e.Total); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/CartFeatures/GetById/GetCartHandler.cs ================================================ using MinimalClean.Architecture.Web.Domain.CartAggregate; using MinimalClean.Architecture.Web.Domain.CartAggregate.Specifications; namespace MinimalClean.Architecture.Web.CartFeatures.GetById; public record GetCartQuery(CartId CartId) : IQuery>; public class GetCartHandler(IReadRepository repository) : IQueryHandler> { public async ValueTask> Handle(GetCartQuery request, CancellationToken cancellationToken) { var spec = new CartByIdSpec(request.CartId); var cart = await repository.FirstOrDefaultAsync(spec, cancellationToken); if (cart == null) { return Result.NotFound("Cart not found"); } // Map to DTO var items = cart.Items.Select(i => new CartItemDto( i.ProductId, i.Quantity, i.UnitPrice, i.Quantity * i.UnitPrice )).ToList(); var total = items.Sum(i => i.TotalPrice); return new CartDto(cart.Id, items, total); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/DatabaseOptions.cs ================================================ namespace MinimalClean.Architecture.Web.Configurations; /// /// Configuration options for database management /// public class DatabaseOptions { /// /// If true, drops and recreates the database on startup in Development environment. /// WARNING: This will delete all existing data! /// public bool RecreateOnStartup { get; set; } = false; } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/LoggerConfigs.cs ================================================ using Serilog; namespace MinimalClean.Architecture.Web.Configurations; public static class LoggerConfigs { public static WebApplicationBuilder AddLoggerConfigs(this WebApplicationBuilder builder) { // Add Serilog as an additional logging provider alongside OpenTelemetry // This allows both Serilog (for console/file) and OpenTelemetry (for Aspire) to work together builder.Logging.AddSerilog(new LoggerConfiguration() .ReadFrom.Configuration(builder.Configuration) .Enrich.FromLogContext() .Enrich.WithProperty("Application", builder.Environment.ApplicationName) .WriteTo.Console() .CreateLogger()); return builder; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/LoggingBehavior.cs ================================================ using System.Diagnostics; namespace Nimble.Modulith.Web; public class LoggingBehavior(ILogger> logger) : IPipelineBehavior where TRequest : notnull, IMessage { private readonly ILogger> _logger = logger; public async ValueTask Handle( TRequest request, MessageHandlerDelegate next, CancellationToken cancellationToken) { if (_logger.IsEnabled(LogLevel.Information)) { // Use structured logging with the whole object instead of reflection _logger.LogInformation("Handling {RequestName}: {@Request}", typeof(TRequest).Name, request); } var sw = Stopwatch.StartNew(); var response = await next(request, cancellationToken); _logger.LogInformation( "Handled {RequestName} with {Response} in {Ms} ms", typeof(TRequest).Name, response, sw.ElapsedMilliseconds); sw.Stop(); return response; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/MediatorConfig.cs ================================================ namespace MinimalClean.Architecture.Web.Configurations; public static class MediatorConfig { // Should be called from ServiceConfigs.cs, not Program.cs public static IServiceCollection AddMediatorSourceGen(this IServiceCollection services, ILogger logger) { logger.LogInformation("Registering Mediator SourceGen and Behaviors"); services.AddMediator(options => { // Lifetime: Singleton is fastest per docs; Scoped/Transient also supported. options.ServiceLifetime = ServiceLifetime.Scoped; // Supply any TYPE from each assembly you want scanned (the generator finds the assembly from the type) options.Assemblies = [ typeof(MediatorConfig) // Web ]; // Register AOT pipeline behaviors here (order matters) options.PipelineBehaviors = [ typeof(Nimble.Modulith.Web.LoggingBehavior<,>) ]; // If you have stream behaviors: // options.StreamPipelineBehaviors = [ typeof(YourStreamBehavior<,>) ]; }); return services; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/MiddlewareConfig.cs ================================================ using Ardalis.ListStartupServices; using FastEndpoints; using FastEndpoints.Swagger; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using MinimalClean.Architecture.Web.Infrastructure.Data; using Scalar.AspNetCore; namespace MinimalClean.Architecture.Web.Configurations; public static class MiddlewareConfig { public static async Task UseAppMiddlewareAndSeedDatabase(this WebApplication app) { if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseShowAllServicesMiddleware(); // see https://github.com/ardalis/AspNetCoreStartupServices } else { app.UseDefaultExceptionHandler(); // from FastEndpoints app.UseHsts(); } app.UseFastEndpoints(); if (app.Environment.IsDevelopment()) { app.UseSwaggerGen(options => { options.Path = "/openapi/{documentName}.json"; }); app.MapScalarApiReference(); } app.UseHttpsRedirection(); // Note this will drop Authorization headers await SeedDatabase(app); return app; } static async Task SeedDatabase(WebApplication app) { using var scope = app.Services.CreateScope(); var services = scope.ServiceProvider; var logger = services.GetRequiredService>(); try { var context = services.GetRequiredService(); var dbOptions = services.GetService>()?.Value; // Drop and recreate database in development if configured if (app.Environment.IsDevelopment() && dbOptions?.RecreateOnStartup == true) { logger.LogWarning("DROPPING database for fresh start (DatabaseOptions:RecreateOnStartup = true)..."); await context.Database.EnsureDeletedAsync(); logger.LogInformation("Database dropped."); } // Apply all pending migrations logger.LogInformation("Applying database migrations..."); await context.Database.MigrateAsync(); logger.LogInformation("Database migrations applied successfully."); // Seed data await SeedData.InitializeAsync(context, logger); } catch (Exception ex) { logger.LogError(ex, "An error occurred seeding the DB. {exceptionMessage}", ex.Message); } } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/OptionConfigs.cs ================================================ using Ardalis.ListStartupServices; using MinimalClean.Architecture.Web.Infrastructure.Email; namespace MinimalClean.Architecture.Web.Configurations; public static class OptionConfigs { public static IServiceCollection AddOptionConfigs(this IServiceCollection services, IConfiguration configuration, Microsoft.Extensions.Logging.ILogger logger, WebApplicationBuilder builder) { services.Configure(configuration.GetSection("Mailserver")) .Configure(configuration.GetSection("DatabaseOptions")) // Configure Web Behavior .Configure(options => { options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); if (builder.Environment.IsDevelopment()) { // add list services for diagnostic purposes - see https://github.com/ardalis/AspNetCoreStartupServices services.Configure(config => { config.Services = new List(builder.Services); // optional - default path to view services is /listallservices - recommended to choose your own path config.Path = "/listservices"; }); } logger.LogInformation("{Project} were configured", "Options"); return services; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Configurations/ServiceConfigs.cs ================================================ using MinimalClean.Architecture.Web.Domain.Interfaces; using MinimalClean.Architecture.Web.Infrastructure; using MinimalClean.Architecture.Web.Infrastructure.Email; namespace MinimalClean.Architecture.Web.Configurations; public static class ServiceConfigs { public static IServiceCollection AddServiceConfigs(this IServiceCollection services, Microsoft.Extensions.Logging.ILogger logger, WebApplicationBuilder builder) { services.AddInfrastructureServices(builder.Configuration, logger) .AddMediatorSourceGen(logger); if (builder.Environment.IsDevelopment()) { // Use a local test email server // See: https://ardalis.com/configuring-a-local-test-email-server/ services.AddScoped(); // Otherwise use this: //builder.Services.AddScoped(); } else { services.AddScoped(); } logger.LogInformation("{Project} services registered", "Mediator and Email Sender"); return services; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Constants.cs ================================================ namespace MinimalClean.Architecture.Web; public class Constants { public const int DEFAULT_PAGE_SIZE = 10; public const int MAX_PAGE_SIZE = 100; } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/Cart.cs ================================================ namespace MinimalClean.Architecture.Web.Domain.CartAggregate; public class Cart : EntityBase, IAggregateRoot { private readonly List _items = new(); public DateTime CreatedOn { get; private set; } = DateTime.UtcNow; public bool Deleted { get; private set; } = false; public IReadOnlyList Items => _items.AsReadOnly(); public void AddItem(int productId, int quantity, decimal unitPrice) { var item = new CartItem(productId, quantity, unitPrice); _items.Add(item); } public void MarkAsDeleted() => Deleted = true; } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartId.cs ================================================ using Vogen; namespace MinimalClean.Architecture.Web.Domain.CartAggregate; [ValueObject] public readonly partial struct CartId { private static Validation Validate(Guid value) => value != Guid.Empty ? Validation.Ok : Validation.Invalid("CartId must set to non-default value."); } [ValueObject] public readonly partial struct TestId { } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartItem.cs ================================================ namespace MinimalClean.Architecture.Web.Domain.CartAggregate; public class CartItem : EntityBase { // Private constructor for EF Core private CartItem() { } public CartItem(int productId, int quantity, decimal unitPrice) { ProductId = productId; Quantity = quantity; UnitPrice = unitPrice; } public int ProductId { get; private set; } public int Quantity { get; private set; } public decimal UnitPrice { get; private set; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/CartItemId.cs ================================================ using Vogen; namespace MinimalClean.Architecture.Web.Domain.CartAggregate; [ValueObject] public readonly partial struct CartItemId { private static Validation Validate(Guid value) => value != Guid.Empty ? Validation.Ok : Validation.Invalid("CartItemId must set to non-default value."); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/CartAggregate/Specifications/CartByIdSpec.cs ================================================ namespace MinimalClean.Architecture.Web.Domain.CartAggregate.Specifications; public class CartByIdSpec : Specification { public CartByIdSpec(CartId cartId) => Query .Include(c => c.Items) .Where(cart => cart.Id == cartId && !cart.Deleted); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/GuestUser.cs ================================================ namespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate; public class GuestUser : EntityBase, IAggregateRoot { public GuestUser(GuestUserId id, string email) { Id = id; Email = email; } public string Email { get; private set; } public GuestUser UpdateEmail(string newEmail) { Email = newEmail; return this; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/GuestUserId.cs ================================================ using Vogen; namespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate; [ValueObject] public readonly partial struct GuestUserId { private static Validation Validate(Guid value) => value != Guid.Empty ? Validation.Ok : Validation.Invalid("GuestUserId cannot be empty."); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/Specifications/GuestUserByEmailSpec.cs ================================================ namespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate.Specifications; public class GuestUserByEmailSpec : Specification { public GuestUserByEmailSpec(string email) => Query.Where(g => g.Email == email); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/GuestUserAggregate/Specifications/GuestUserByIdSpec.cs ================================================ namespace MinimalClean.Architecture.Web.Domain.GuestUserAggregate.Specifications; public class GuestUserByIdSpec : Specification { public GuestUserByIdSpec(GuestUserId guestUserId) => Query.Where(g => g.Id == guestUserId); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/Interfaces/IEmailSender.cs ================================================ namespace MinimalClean.Architecture.Web.Domain.Interfaces; public interface IEmailSender { Task SendEmailAsync(string to, string from, string subject, string body); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Order.cs ================================================ using MinimalClean.Architecture.Web.Domain.ProductAggregate; using MinimalClean.Architecture.Web.Infrastructure.Data; namespace MinimalClean.Architecture.Web.Domain.OrderAggregate; public class Order : EntityBase, IAggregateRoot { private readonly List _items = new(); public Order(OrderId id, Guid guestUserId) { Id = id; GuestUserId = guestUserId; } public DateTimeOffset CreatedOn { get; private set; } = DateTimeOffset.UtcNow; public Guid GuestUserId { get; private set; } public DateTimeOffset? DatePaid { get; private set; } public string PaymentReference { get; private set; } = string.Empty; public IReadOnlyList Items => _items.AsReadOnly(); public decimal Total => _items.Sum(i => i.UnitPrice.Value * i.Quantity.Value); public void AddItem(ProductId productId, Quantity quantity, Price unitPrice) { var item = new OrderItem(Id, productId, quantity, unitPrice); if(Items.Any(i => i.ProductId == productId)) { var existingItem = Items.First(i => i.ProductId == productId); existingItem.IncreaseQuantity(quantity); return; } _items.Add(item); } public void ConfirmPayment(DateTimeOffset datePaid, string paymentReference) { DatePaid = datePaid; PaymentReference = paymentReference; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderId.cs ================================================ using Vogen; namespace MinimalClean.Architecture.Web.Domain.OrderAggregate; [ValueObject] public readonly partial struct OrderId { private static Validation Validate(Guid value) => value != Guid.Empty ? Validation.Ok : Validation.Invalid("OrderId cannot be empty."); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderItem.cs ================================================  using MinimalClean.Architecture.Web.Domain.ProductAggregate; namespace MinimalClean.Architecture.Web.Domain.OrderAggregate; public class OrderItem(OrderId orderId, ProductId productId, Quantity quantity, Price unitPrice) : EntityBase { public OrderId OrderId { get; private set; } = orderId; public ProductId ProductId { get; private set; } = productId; public Quantity Quantity { get; private set; } = quantity; public Price UnitPrice { get; private set; } = unitPrice; internal void IncreaseQuantity(Quantity quantity) => Quantity += quantity; } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/OrderItemId.cs ================================================ using Vogen; namespace MinimalClean.Architecture.Web.Domain.OrderAggregate; [ValueObject] public readonly partial struct OrderItemId { private static Validation Validate(Guid value) => value != Guid.Empty ? Validation.Ok : Validation.Invalid("OrderItemId cannot be empty."); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Price.cs ================================================ using Vogen; namespace MinimalClean.Architecture.Web.Domain.OrderAggregate; [ValueObject] public readonly partial struct Price { private static Validation Validate(decimal value) => value > 0 ? Validation.Ok : Validation.Invalid("Price must be greater than zero."); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/OrderAggregate/Quantity.cs ================================================ using Vogen; namespace MinimalClean.Architecture.Web.Domain.OrderAggregate; [ValueObject] public readonly partial struct Quantity { private static Validation Validate(int value) => value > 0 ? Validation.Ok : Validation.Invalid("Quantity must be greater than zero."); public static Quantity operator +(Quantity left, Quantity right) => From(left.Value + right.Value); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/Product.cs ================================================ using Ardalis.GuardClauses; namespace MinimalClean.Architecture.Web.Domain.ProductAggregate; public class Product : EntityBase, IAggregateRoot { // Private constructor for EF Core private Product() { } public Product(ProductId id, string name, decimal unitPrice) { Guard.Against.InvalidInput(id, nameof(id), (id) => id == ProductId.New, "Use Product.Create() to create new products instead of passing ProductId.New to the constructor."); Id = id; Name = name; UnitPrice = unitPrice; } // Factory method for creating new products (before persistence) public static Product Create(string name, decimal unitPrice) => new Product(ProductId.New, name, unitPrice); public string Name { get; private set; } = string.Empty; public decimal UnitPrice { get; private set; } public Product UpdateName(string newName) { Name = newName; return this; } public Product UpdatePrice(decimal newPrice) { UnitPrice = newPrice; return this; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/ProductId.cs ================================================ using Vogen; namespace MinimalClean.Architecture.Web.Domain.ProductAggregate; [ValueObject] public readonly partial struct ProductId { /// /// Represents a new Product that has not yet been persisted to the database. /// EF Core will assign the actual identity value on SaveChanges. /// public static ProductId New => From(0); private static Validation Validate(int value) => value >= 0 ? Validation.Ok : Validation.Invalid("ProductId must be non-negative."); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Domain/ProductAggregate/Specifications/ProductByIdSpec.cs ================================================ namespace MinimalClean.Architecture.Web.Domain.ProductAggregate.Specifications; public class ProductByIdSpec : Specification { public ProductByIdSpec(ProductId productId) => Query .Where(product => product.Id == productId); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Extensions/ResultExtensions.cs ================================================ using Microsoft.AspNetCore.Http.HttpResults; namespace MinimalClean.Architecture.Web.Extensions; public static class ResultExtensions { /// /// Maps Result to TypedResults for endpoints that return Created, ValidationProblem, or ProblemHttpResult /// public static Results, ValidationProblem, ProblemHttpResult> ToCreatedResult( this Result result, Func locationBuilder, Func mapResponse) { return result.Status switch { ResultStatus.Ok => TypedResults.Created(locationBuilder(result.Value), mapResponse(result.Value)), ResultStatus.Invalid => TypedResults.ValidationProblem( result.ValidationErrors .GroupBy(e => e.Identifier ?? string.Empty) .ToDictionary( g => g.Key, g => g.Select(e => e.ErrorMessage).ToArray() ) ), _ => TypedResults.Problem( title: "Create failed", detail: string.Join("; ", result.Errors), statusCode: StatusCodes.Status400BadRequest) }; } /// /// Maps Result to TypedResults for GetById endpoints that return Ok, NotFound, or ProblemHttpResult /// public static Results, NotFound, ProblemHttpResult> ToGetByIdResult( this Result result, Func mapResponse) => ToOkOrNotFoundResult(result, mapResponse, "Get"); /// /// Maps Result to TypedResults for Update endpoints that return Ok, NotFound, or ProblemHttpResult /// public static Results, NotFound, ProblemHttpResult> ToUpdateResult( this Result result, Func mapResponse) => ToOkOrNotFoundResult(result, mapResponse, "Update"); /// /// Maps Result to TypedResults for Delete endpoints that return NoContent, NotFound, or ProblemHttpResult /// public static Results ToDeleteResult( this Result result) => result.Status switch { ResultStatus.Ok => TypedResults.NoContent(), ResultStatus.NotFound => TypedResults.NotFound(), _ => TypedResults.Problem( title: "Delete failed", detail: string.Join("; ", result.Errors), statusCode: StatusCodes.Status400BadRequest) }; /// /// Private helper method for Ok/NotFound result patterns /// private static Results, NotFound, ProblemHttpResult> ToOkOrNotFoundResult( Result result, Func mapResponse, string operationName) => result.Status switch { ResultStatus.Ok => TypedResults.Ok(mapResponse(result.Value)), ResultStatus.NotFound => TypedResults.NotFound(), _ => TypedResults.Problem( title: $"{operationName} failed", detail: string.Join("; ", result.Errors), statusCode: StatusCodes.Status400BadRequest) }; /// /// Maps Result to TypedResults for endpoints that return Ok only (like List endpoints) /// public static Ok ToOkOnlyResult( this Result result, Func mapResponse) => TypedResults.Ok(mapResponse(result.Value)); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/GlobalUsings.cs ================================================ global using Mediator; global using Ardalis.Result; global using Ardalis.Specification; global using Ardalis.SharedKernel; ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContext.cs ================================================ using System.Reflection; using Microsoft.EntityFrameworkCore; using MinimalClean.Architecture.Web.Domain.CartAggregate; using MinimalClean.Architecture.Web.Domain.GuestUserAggregate; using MinimalClean.Architecture.Web.Domain.OrderAggregate; using MinimalClean.Architecture.Web.Domain.ProductAggregate; namespace MinimalClean.Architecture.Web.Infrastructure.Data; public class AppDbContext(DbContextOptions options) : DbContext(options) { public DbSet Products => Set(); public DbSet Carts => Set(); public DbSet CartItems => Set(); public DbSet GuestUsers => Set(); public DbSet Orders => Set(); public DbSet OrderItems => Set(); protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); } public override int SaveChanges() => SaveChangesAsync().GetAwaiter().GetResult(); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContextExtensions.cs ================================================ using Microsoft.EntityFrameworkCore; namespace MinimalClean.Architecture.Web.Infrastructure.Data; public static class AppDbContextExtensions { public static void AddApplicationDbContext(this IServiceCollection services, string connectionString) => services.AddDbContext(options => options.UseSqlServer(connectionString)); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/AppDbContextFactory.cs ================================================ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Design; namespace MinimalClean.Architecture.Web.Infrastructure.Data; /// /// Design-time factory for creating DbContext instances for EF Core tools. /// This is ONLY used when CREATING migrations (e.g., 'dotnet ef migrations add'). /// It is NOT used at runtime - Aspire handles the runtime connection. /// /// Migrations are automatically APPLIED at runtime via MigrateAsync() in MiddlewareConfig.cs. /// /// To create migrations with SQL Server, set an environment variable: /// PowerShell: $env:ConnectionStrings__AppDb = "Server=localhost,1433;Database=AppDb;User ID=sa;Password=YourPassword;TrustServerCertificate=true" /// Bash: export ConnectionStrings__AppDb="Server=localhost,1433;Database=AppDb;User ID=sa;Password=YourPassword;TrustServerCertificate=true" /// /// Always uses SQL Server for migrations. /// public class AppDbContextFactory : IDesignTimeDbContextFactory { public AppDbContext CreateDbContext(string[] args) { var optionsBuilder = new DbContextOptionsBuilder(); // Try to get connection string from environment variable (ASP.NET Core format) var connectionString = Environment.GetEnvironmentVariable("ConnectionStrings__AppDb") ?? "Server=localhost,1433;Database=AppDb_Design;User ID=sa;Password=Your$tr0ngP@ss!;TrustServerCertificate=true"; // Default SQL Server connection for design-time optionsBuilder.UseSqlServer(connectionString); return new AppDbContext(optionsBuilder.Options); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/CartConfiguration.cs ================================================ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using MinimalClean.Architecture.Web.Domain.CartAggregate; namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config; public class CartConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.Property(entity => entity.Id) .HasValueGenerator>() .HasVogenConversion() .IsRequired(); builder.Property(entity => entity.CreatedOn) .IsRequired(); builder.Property(entity => entity.Deleted) .IsRequired(); // CartItems relationship builder.HasMany(c => c.Items); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/CartItemConfiguration.cs ================================================ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using MinimalClean.Architecture.Web.Domain.CartAggregate; namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config; public class CartItemConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.ToTable("CartItems"); builder.Property(entity => entity.Id) .HasValueGenerator>() .HasVogenConversion() .IsRequired(); builder.Property(ci => ci.ProductId) .IsRequired(); builder.Property(ci => ci.Quantity) .IsRequired(); builder.Property(ci => ci.UnitPrice) .HasPrecision(18, 2) .IsRequired(); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/DataSchemaConstants.cs ================================================ namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config; public static class DataSchemaConstants { public const int DEFAULT_NAME_LENGTH = 100; } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/GuestUserConfiguration.cs ================================================ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using MinimalClean.Architecture.Web.Domain.GuestUserAggregate; namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config; public class GuestUserConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.Property(entity => entity.Id) .HasValueGenerator>() .HasVogenConversion() .IsRequired(); builder.Property(entity => entity.Email) .HasMaxLength(DataSchemaConstants.DEFAULT_NAME_LENGTH) .IsRequired(); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/OrderConfiguration.cs ================================================ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using MinimalClean.Architecture.Web.Domain.OrderAggregate; namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config; public class OrderConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.Property(entity => entity.Id) .HasValueGenerator>() .HasVogenConversion() .IsRequired(); builder.Property(entity => entity.CreatedOn) .IsRequired(); builder.Property(entity => entity.GuestUserId) .IsRequired(); builder.Property(entity => entity.DatePaid) .IsRequired(false); builder.Property(entity => entity.PaymentReference) .HasMaxLength(DataSchemaConstants.DEFAULT_NAME_LENGTH) .IsRequired(false); // OrderItems relationship builder.HasMany(o => o.Items); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/OrderItemConfiguration.cs ================================================ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using MinimalClean.Architecture.Web.Domain.OrderAggregate; using MinimalClean.Architecture.Web.Domain.ProductAggregate; namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config; public class OrderItemConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { ArgumentNullException.ThrowIfNull(builder); builder.ToTable("OrderItems"); builder.Property(entity => entity.Id) .HasValueGenerator>() .HasVogenConversion() .IsRequired(); builder.Property(oi => oi.OrderId) .HasVogenConversion() .IsRequired(); builder.Property(oi => oi.ProductId) .HasVogenConversion() .IsRequired(); builder.Property(oi => oi.Quantity) .HasVogenConversion() .IsRequired(); builder.Property(oi => oi.UnitPrice) .HasVogenConversion() .HasPrecision(18, 2) .IsRequired(); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/ProductConfiguration.cs ================================================ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using MinimalClean.Architecture.Web.Domain.ProductAggregate; namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config; public class ProductConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.Property(entity => entity.Id) .HasValueGenerator>() .HasVogenConversion() .IsRequired(); builder.Property(entity => entity.Name) .HasMaxLength(100) .IsRequired(); builder.Property(entity => entity.UnitPrice) .HasPrecision(18, 2) .IsRequired(); builder.HasData( new Product( ProductId.From(1), "Coffee Mug", 9.99m), new Product( ProductId.From(2), "T-Shirt", 19.99m), new Product( ProductId.From(3), "Sticker Pack", 3.99m) ); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/VogenEfCoreConverters.cs ================================================ using MinimalClean.Architecture.Web.Domain.CartAggregate; using MinimalClean.Architecture.Web.Domain.GuestUserAggregate; using MinimalClean.Architecture.Web.Domain.OrderAggregate; using MinimalClean.Architecture.Web.Domain.ProductAggregate; using Vogen; namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config; [EfCoreConverter] [EfCoreConverter] [EfCoreConverter] [EfCoreConverter] [EfCoreConverter] [EfCoreConverter] [EfCoreConverter] [EfCoreConverter] internal partial class VogenEfCoreConverters; ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/VogenGuidIdValueGenerator.cs ================================================ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.ValueGeneration; namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config; internal class VogenGuidIdValueGenerator : ValueGenerator where TContext : DbContext where TEntityBase : EntityBase where TId : struct { public override TId Next(EntityEntry entry) { // Use reflection to call the static From method on the value object var fromMethod = typeof(TId).GetMethod("From", new[] { typeof(Guid) }); if (fromMethod == null) { throw new InvalidOperationException($"Type {typeof(TId).Name} does not have a From(Guid) method"); } return (TId)fromMethod.Invoke(null, new object[] { Guid.NewGuid() })!; } public override bool GeneratesTemporaryValues => false; } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Config/VogenIntIdValueGenerator.cs ================================================ using System.Reflection; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.ValueGeneration; using Vogen; namespace MinimalClean.Architecture.Web.Infrastructure.Data.Config; internal class VogenIntIdValueGenerator : ValueGenerator where TContext : DbContext where TEntityBase : EntityBase where TId : IVogen { private readonly PropertyInfo _matchPropertyGetter; public VogenIntIdValueGenerator() { var matchingProperties = typeof(TContext).GetProperties() .Where(p => p.GetGetMethod()!.IsPublic && p.PropertyType == typeof(DbSet)) .ToList(); if (matchingProperties.Count == 0) { throw new InvalidOperationException($"No properties found in the EFCore context for a DBSet of {nameof(TEntityBase)}"); } if (matchingProperties.Count > 1) { throw new InvalidOperationException($"Multiple properties found in the EFCore context for a DBSet of {nameof(TEntityBase)}"); } _matchPropertyGetter = matchingProperties[0]; } public override TId Next(EntityEntry entry) { TContext ctx = (TContext)entry.Context; DbSet entities = (DbSet)_matchPropertyGetter.GetValue(ctx)!; var next = Math.Max( MaxFrom(entities.Local), MaxFrom(entities)) + 1; return TId.From(next); } private static int MaxFrom(IEnumerable es) { if (!es.Any()) return 0; return es.Max(e => e.Id.Value); } public override bool GeneratesTemporaryValues => false; } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/EfRepository.cs ================================================ using Ardalis.Specification.EntityFrameworkCore; namespace MinimalClean.Architecture.Web.Infrastructure.Data; // inherit from Ardalis.Specification type public class EfRepository(AppDbContext dbContext) : RepositoryBase(dbContext), IReadRepository, IRepository where T : class, IAggregateRoot { } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/EventDispatcherInterceptor.cs ================================================ using Microsoft.EntityFrameworkCore.Diagnostics; namespace MinimalClean.Architecture.Web.Infrastructure.Data; // Intercepts SaveChanges to dispatch domain events after changes are successfully saved public class EventDispatchInterceptor(IDomainEventDispatcher domainEventDispatcher) : SaveChangesInterceptor { private readonly IDomainEventDispatcher _domainEventDispatcher = domainEventDispatcher; // Called after SaveChangesAsync has completed successfully public override async ValueTask SavedChangesAsync(SaveChangesCompletedEventData eventData, int result, CancellationToken cancellationToken = new CancellationToken()) { var context = eventData.Context; if (context is not AppDbContext appDbContext) { return await base.SavedChangesAsync(eventData, result, cancellationToken).ConfigureAwait(false); } // Retrieve all tracked entities that have domain events var entitiesWithEvents = appDbContext.ChangeTracker.Entries() .Select(e => e.Entity) .Where(e => e.DomainEvents.Any()) .ToArray(); // Dispatch and clear domain events await _domainEventDispatcher.DispatchAndClearEvents(entitiesWithEvents); return await base.SavedChangesAsync(eventData, result, cancellationToken); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251020223304_Initial.Designer.cs ================================================ // using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using MinimalClean.Architecture.Web.Infrastructure.Data; #nullable disable namespace MinimalClean.Architecture.Web.Infrastructure.Data.Migrations { [DbContext(typeof(AppDbContext))] [Migration("20251020223304_Initial")] partial class Initial { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "9.0.10") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("CreatedOn") .HasColumnType("datetime2"); b.Property("Deleted") .HasColumnType("bit"); b.HasKey("Id"); b.ToTable("Carts"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("CartId") .HasColumnType("uniqueidentifier"); b.Property("ProductId") .HasColumnType("int"); b.Property("Quantity") .HasColumnType("int"); b.Property("UnitPrice") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); b.HasKey("Id"); b.HasIndex("CartId"); b.ToTable("CartItems", (string)null); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.ProductAggregate.Product", b => { b.Property("Id") .HasColumnType("int"); b.Property("Name") .IsRequired() .HasMaxLength(100) .HasColumnType("nvarchar(100)"); b.Property("UnitPrice") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); b.HasKey("Id"); b.ToTable("Products"); b.HasData( new { Id = 1, Name = "Laptop", UnitPrice = 999.99m }, new { Id = 2, Name = "Smartphone", UnitPrice = 499.99m }, new { Id = 3, Name = "Tablet", UnitPrice = 299.99m }); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b => { b.HasOne("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", null) .WithMany("Items") .HasForeignKey("CartId"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b => { b.Navigation("Items"); }); #pragma warning restore 612, 618 } } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251020223304_Initial.cs ================================================ using System; using Microsoft.EntityFrameworkCore.Migrations; #nullable disable #pragma warning disable CA1814 // Prefer jagged arrays over multidimensional namespace MinimalClean.Architecture.Web.Infrastructure.Data.Migrations { /// public partial class Initial : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "Carts", columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), CreatedOn = table.Column(type: "datetime2", nullable: false), Deleted = table.Column(type: "bit", nullable: false) }, constraints: table => { table.PrimaryKey("PK_Carts", x => x.Id); }); migrationBuilder.CreateTable( name: "Products", columns: table => new { Id = table.Column(type: "int", nullable: false), Name = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), UnitPrice = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false) }, constraints: table => { table.PrimaryKey("PK_Products", x => x.Id); }); migrationBuilder.CreateTable( name: "CartItems", columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), ProductId = table.Column(type: "int", nullable: false), Quantity = table.Column(type: "int", nullable: false), UnitPrice = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), CartId = table.Column(type: "uniqueidentifier", nullable: true) }, constraints: table => { table.PrimaryKey("PK_CartItems", x => x.Id); table.ForeignKey( name: "FK_CartItems_Carts_CartId", column: x => x.CartId, principalTable: "Carts", principalColumn: "Id"); }); migrationBuilder.InsertData( table: "Products", columns: new[] { "Id", "Name", "UnitPrice" }, values: new object[,] { { 1, "Laptop", 999.99m }, { 2, "Smartphone", 499.99m }, { 3, "Tablet", 299.99m } }); migrationBuilder.CreateIndex( name: "IX_CartItems_CartId", table: "CartItems", column: "CartId"); } /// protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "CartItems"); migrationBuilder.DropTable( name: "Products"); migrationBuilder.DropTable( name: "Carts"); } } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251024232246_AddGuestUsersAndOrdersSqlServer.Designer.cs ================================================ // using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using MinimalClean.Architecture.Web.Infrastructure.Data; #nullable disable namespace MinimalClean.Architecture.Web.Infrastructure.Data.Migrations { [DbContext(typeof(AppDbContext))] [Migration("20251024232246_AddGuestUsersAndOrdersSqlServer")] partial class AddGuestUsersAndOrdersSqlServer { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "9.0.10") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("CreatedOn") .HasColumnType("datetime2"); b.Property("Deleted") .HasColumnType("bit"); b.HasKey("Id"); b.ToTable("Carts"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("CartId") .HasColumnType("uniqueidentifier"); b.Property("ProductId") .HasColumnType("int"); b.Property("Quantity") .HasColumnType("int"); b.Property("UnitPrice") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); b.HasKey("Id"); b.HasIndex("CartId"); b.ToTable("CartItems", (string)null); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.GuestUserAggregate.GuestUser", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("Email") .IsRequired() .HasMaxLength(100) .HasColumnType("nvarchar(100)"); b.HasKey("Id"); b.ToTable("GuestUsers"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("CreatedOn") .HasColumnType("datetimeoffset"); b.Property("DatePaid") .HasColumnType("datetimeoffset"); b.Property("GuestUserId") .HasColumnType("uniqueidentifier"); b.Property("PaymentReference") .HasMaxLength(100) .HasColumnType("nvarchar(100)"); b.HasKey("Id"); b.ToTable("Orders"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.OrderItem", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("OrderId") .HasColumnType("uniqueidentifier"); b.Property("ProductId") .HasColumnType("int"); b.Property("Quantity") .HasColumnType("int"); b.Property("UnitPrice") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); b.HasKey("Id"); b.HasIndex("OrderId"); b.ToTable("OrderItems", (string)null); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.ProductAggregate.Product", b => { b.Property("Id") .HasColumnType("int"); b.Property("Name") .IsRequired() .HasMaxLength(100) .HasColumnType("nvarchar(100)"); b.Property("UnitPrice") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); b.HasKey("Id"); b.ToTable("Products"); b.HasData( new { Id = 1, Name = "Coffee Mug", UnitPrice = 9.99m }, new { Id = 2, Name = "T-Shirt", UnitPrice = 19.99m }, new { Id = 3, Name = "Sticker Pack", UnitPrice = 3.99m }); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b => { b.HasOne("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", null) .WithMany("Items") .HasForeignKey("CartId"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.OrderItem", b => { b.HasOne("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", null) .WithMany("Items") .HasForeignKey("OrderId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b => { b.Navigation("Items"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", b => { b.Navigation("Items"); }); #pragma warning restore 612, 618 } } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/20251024232246_AddGuestUsersAndOrdersSqlServer.cs ================================================ using System; using Microsoft.EntityFrameworkCore.Migrations; #nullable disable namespace MinimalClean.Architecture.Web.Infrastructure.Data.Migrations { /// public partial class AddGuestUsersAndOrdersSqlServer : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "GuestUsers", columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), Email = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false) }, constraints: table => { table.PrimaryKey("PK_GuestUsers", x => x.Id); }); migrationBuilder.CreateTable( name: "Orders", columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), CreatedOn = table.Column(type: "datetimeoffset", nullable: false), GuestUserId = table.Column(type: "uniqueidentifier", nullable: false), DatePaid = table.Column(type: "datetimeoffset", nullable: true), PaymentReference = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: true) }, constraints: table => { table.PrimaryKey("PK_Orders", x => x.Id); }); migrationBuilder.CreateTable( name: "OrderItems", columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), OrderId = table.Column(type: "uniqueidentifier", nullable: false), ProductId = table.Column(type: "int", nullable: false), Quantity = table.Column(type: "int", nullable: false), UnitPrice = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false) }, constraints: table => { table.PrimaryKey("PK_OrderItems", x => x.Id); table.ForeignKey( name: "FK_OrderItems_Orders_OrderId", column: x => x.OrderId, principalTable: "Orders", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); migrationBuilder.UpdateData( table: "Products", keyColumn: "Id", keyValue: 1, columns: new[] { "Name", "UnitPrice" }, values: new object[] { "Coffee Mug", 9.99m }); migrationBuilder.UpdateData( table: "Products", keyColumn: "Id", keyValue: 2, columns: new[] { "Name", "UnitPrice" }, values: new object[] { "T-Shirt", 19.99m }); migrationBuilder.UpdateData( table: "Products", keyColumn: "Id", keyValue: 3, columns: new[] { "Name", "UnitPrice" }, values: new object[] { "Sticker Pack", 3.99m }); migrationBuilder.CreateIndex( name: "IX_OrderItems_OrderId", table: "OrderItems", column: "OrderId"); } /// protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "GuestUsers"); migrationBuilder.DropTable( name: "OrderItems"); migrationBuilder.DropTable( name: "Orders"); migrationBuilder.UpdateData( table: "Products", keyColumn: "Id", keyValue: 1, columns: new[] { "Name", "UnitPrice" }, values: new object[] { "Laptop", 999.99m }); migrationBuilder.UpdateData( table: "Products", keyColumn: "Id", keyValue: 2, columns: new[] { "Name", "UnitPrice" }, values: new object[] { "Smartphone", 499.99m }); migrationBuilder.UpdateData( table: "Products", keyColumn: "Id", keyValue: 3, columns: new[] { "Name", "UnitPrice" }, values: new object[] { "Tablet", 299.99m }); } } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Migrations/AppDbContextModelSnapshot.cs ================================================ // using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using MinimalClean.Architecture.Web.Infrastructure.Data; #nullable disable namespace MinimalClean.Architecture.Web.Infrastructure.Data.Migrations { [DbContext(typeof(AppDbContext))] partial class AppDbContextModelSnapshot : ModelSnapshot { protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder .HasAnnotation("ProductVersion", "9.0.10") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("CreatedOn") .HasColumnType("datetime2"); b.Property("Deleted") .HasColumnType("bit"); b.HasKey("Id"); b.ToTable("Carts"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("CartId") .HasColumnType("uniqueidentifier"); b.Property("ProductId") .HasColumnType("int"); b.Property("Quantity") .HasColumnType("int"); b.Property("UnitPrice") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); b.HasKey("Id"); b.HasIndex("CartId"); b.ToTable("CartItems", (string)null); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.GuestUserAggregate.GuestUser", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("Email") .IsRequired() .HasMaxLength(100) .HasColumnType("nvarchar(100)"); b.HasKey("Id"); b.ToTable("GuestUsers"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("CreatedOn") .HasColumnType("datetimeoffset"); b.Property("DatePaid") .HasColumnType("datetimeoffset"); b.Property("GuestUserId") .HasColumnType("uniqueidentifier"); b.Property("PaymentReference") .HasMaxLength(100) .HasColumnType("nvarchar(100)"); b.HasKey("Id"); b.ToTable("Orders"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.OrderItem", b => { b.Property("Id") .HasColumnType("uniqueidentifier"); b.Property("OrderId") .HasColumnType("uniqueidentifier"); b.Property("ProductId") .HasColumnType("int"); b.Property("Quantity") .HasColumnType("int"); b.Property("UnitPrice") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); b.HasKey("Id"); b.HasIndex("OrderId"); b.ToTable("OrderItems", (string)null); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.ProductAggregate.Product", b => { b.Property("Id") .HasColumnType("int"); b.Property("Name") .IsRequired() .HasMaxLength(100) .HasColumnType("nvarchar(100)"); b.Property("UnitPrice") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); b.HasKey("Id"); b.ToTable("Products"); b.HasData( new { Id = 1, Name = "Coffee Mug", UnitPrice = 9.99m }, new { Id = 2, Name = "T-Shirt", UnitPrice = 19.99m }, new { Id = 3, Name = "Sticker Pack", UnitPrice = 3.99m }); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.CartItem", b => { b.HasOne("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", null) .WithMany("Items") .HasForeignKey("CartId"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.OrderItem", b => { b.HasOne("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", null) .WithMany("Items") .HasForeignKey("OrderId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.CartAggregate.Cart", b => { b.Navigation("Items"); }); modelBuilder.Entity("MinimalClean.Architecture.Web.Domain.OrderAggregate.Order", b => { b.Navigation("Items"); }); #pragma warning restore 612, 618 } } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/Queries/ListProductsQueryService.cs ================================================ using Microsoft.EntityFrameworkCore; using MinimalClean.Architecture.Web.ProductFeatures; using MinimalClean.Architecture.Web.ProductFeatures.List; namespace MinimalClean.Architecture.Web.Infrastructure.Data.Queries; public class ListProductsQueryService(AppDbContext db) : IListProductsQueryService { private readonly AppDbContext _db = db; public async Task> ListAsync(int page, int perPage) { var items = await _db.Products .OrderBy(p => p.Id) .Skip((page - 1) * perPage) .Take(perPage) .Select(p => new ProductDto(p.Id, p.Name, p.UnitPrice)) .AsNoTracking() .ToListAsync(); int totalCount = await _db.Products.CountAsync(); int totalPages = (int)Math.Ceiling(totalCount / (double)perPage); var result = new PagedResult(items, page, perPage, totalCount, totalPages); return result; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Data/SeedData.cs ================================================ using Microsoft.EntityFrameworkCore; using MinimalClean.Architecture.Web.Domain.ProductAggregate; using Microsoft.Extensions.Logging; namespace MinimalClean.Architecture.Web.Infrastructure.Data; public static class SeedData { public const int NUMBER_OF_PRODUCTS = 10; public static async Task InitializeAsync(AppDbContext dbContext, ILogger logger) { if (await dbContext.Products.AnyAsync()) { logger.LogInformation("DB has data - seeding not required."); return; // DB has been seeded } await PopulateTestDataAsync(dbContext, logger); } public static async Task PopulateTestDataAsync(AppDbContext dbContext, ILogger logger) { logger.LogInformation("Seeding database with sample data."); // add more products to support demonstrating paging for (int i = 1; i <= NUMBER_OF_PRODUCTS; i++) { dbContext.Products.Add(new Product(ProductId.From(i), $"Product {i}", 10m + i)); } await dbContext.SaveChangesAsync(); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/FakeEmailSender.cs ================================================ using MinimalClean.Architecture.Web.Domain.Interfaces; namespace MinimalClean.Architecture.Web.Infrastructure.Email; public class FakeEmailSender(ILogger logger) : IEmailSender { private readonly ILogger _logger = logger; public Task SendEmailAsync(string to, string from, string subject, string body) { _logger.LogInformation("Not actually sending an email to {to} from {from} with subject {subject}", to, from, subject); return Task.CompletedTask; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/MailserverConfiguration.cs ================================================ namespace MinimalClean.Architecture.Web.Infrastructure.Email; public class MailserverConfiguration() { public string Hostname { get; set; } = "localhost"; public int Port { get; set; } = 25; } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/Email/MimeKitEmailSender.cs ================================================ using Microsoft.Extensions.Options; using MimeKit; using MinimalClean.Architecture.Web.Domain.Interfaces; namespace MinimalClean.Architecture.Web.Infrastructure.Email; public class MimeKitEmailSender(ILogger logger, IOptions mailserverOptions) : IEmailSender { private readonly ILogger _logger = logger; private readonly MailserverConfiguration _mailserverConfiguration = mailserverOptions.Value!; public async Task SendEmailAsync(string to, string from, string subject, string body) { _logger.LogWarning("Sending email to {to} from {from} with subject {subject} using {type}.", to, from, subject, this.ToString()); using var client = new MailKit.Net.Smtp.SmtpClient(); await client.ConnectAsync(_mailserverConfiguration.Hostname, _mailserverConfiguration.Port, false); var message = new MimeMessage(); message.From.Add(new MailboxAddress(from, from)); message.To.Add(new MailboxAddress(to, to)); message.Subject = subject; message.Body = new TextPart("plain") { Text = body }; await client.SendAsync(message); await client.DisconnectAsync(true, new CancellationToken(canceled: true)); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Infrastructure/InfrastructureServiceExtensions.cs ================================================ using Ardalis.GuardClauses; using MinimalClean.Architecture.Web.Infrastructure.Data; using MinimalClean.Architecture.Web.Infrastructure.Data.Queries; using MinimalClean.Architecture.Web.ProductFeatures.List; using Microsoft.EntityFrameworkCore; namespace MinimalClean.Architecture.Web.Infrastructure; public static class InfrastructureServiceExtensions { public static IServiceCollection AddInfrastructureServices( this IServiceCollection services, ConfigurationManager config, ILogger logger) { // Always use SQL Server from Aspire string? connectionString = config.GetConnectionString("AppDb"); Guard.Against.Null(connectionString, "AppDb connection string is required. Make sure the application is running with Aspire."); services.AddScoped(); services.AddScoped(); services.AddDbContext((provider, options) => { var eventDispatchInterceptor = provider.GetRequiredService(); options.UseSqlServer(connectionString); options.AddInterceptors(eventDispatchInterceptor); }); services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)) .AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>)) .AddScoped(); logger.LogInformation("{Project} services registered", "Infrastructure"); return services; } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/MinimalClean.Architecture.Web.csproj ================================================  true Exe true True MinimalClean.Architecture.Web NSDEPCOP01 all runtime; build; native; contentfiles; analyzers; buildtransitive compile; runtime; build; native; contentfiles; analyzers; buildtransitive runtime; build; native; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/PagedResult.cs ================================================ namespace MinimalClean.Architecture.Web; public record PagedResult( IReadOnlyList Items, int Page, int PerPage, int TotalCount, int TotalPages); ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/Create/CreateEndpoint.cs ================================================ using FastEndpoints; using FluentValidation; using Microsoft.AspNetCore.Http.HttpResults; using MinimalClean.Architecture.Web.Domain.ProductAggregate; using MinimalClean.Architecture.Web.ProductFeatures; namespace MinimalClean.Architecture.Web.ProductFeatures.Create; public sealed class CreateProductRequest { public string Name { get; init; } = string.Empty; public decimal UnitPrice { get; init; } } public class CreateEndpoint(IRepository repository) : Endpoint, ValidationProblem, ProblemHttpResult>> { private readonly IRepository _repository = repository; public override void Configure() { Post("/Products"); AllowAnonymous(); Summary(s => { s.Summary = "Create a new product"; s.Description = "Creates a new product with the specified name and unit price."; s.ExampleRequest = new CreateProductRequest { Name = "Sample Product", UnitPrice = 19.99m }; s.ResponseExamples[201] = new ProductRecord(1, "Sample Product", 19.99m); s.Responses[201] = "Product created successfully"; s.Responses[400] = "Invalid request data"; }); Tags("Products"); Description(builder => builder .Accepts() .Produces(201, "application/json") .ProducesProblem(400)); } public override async Task, ValidationProblem, ProblemHttpResult>> ExecuteAsync(CreateProductRequest request, CancellationToken cancellationToken) { var product = Product.Create(request.Name, request.UnitPrice); await _repository.AddAsync(product, cancellationToken); await _repository.SaveChangesAsync(cancellationToken); var response = new ProductRecord(product.Id.Value, product.Name, product.UnitPrice); return TypedResults.Created($"/Products/{product.Id.Value}", response); } } public sealed class CreateProductValidator : Validator { public CreateProductValidator() { RuleFor(x => x.Name) .NotEmpty() .WithMessage("Product name is required") .MaximumLength(200) .WithMessage("Product name must not exceed 200 characters"); RuleFor(x => x.UnitPrice) .GreaterThan(0) .WithMessage("Unit price must be greater than zero"); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/GetById/GetByIdEndpoint.cs ================================================ using FastEndpoints; using FluentValidation; using Microsoft.AspNetCore.Http.HttpResults; using MinimalClean.Architecture.Web.Domain.ProductAggregate; using MinimalClean.Architecture.Web.Extensions; namespace MinimalClean.Architecture.Web.ProductFeatures.GetById; public sealed class GetProductByIdRequest { public const string Route = "/Products/{ProductId}"; public int ProductId { get; init; } } public class GetByIdEndpoint(IMediator mediator) : Endpoint, NotFound, ProblemHttpResult>, GetProductByIdMapper> { public override void Configure() { Get(GetProductByIdRequest.Route); AllowAnonymous(); Summary(s => { s.Summary = "Get a product by ID"; s.Description = "Retrieves a specific product by its unique identifier. Returns detailed product information including ID, name, and unit price."; s.ExampleRequest = new GetProductByIdRequest { ProductId = 1 }; s.ResponseExamples[200] = new ProductRecord(1, "Laptop", 999.99m); // Document possible responses s.Responses[200] = "Product found and returned successfully"; s.Responses[404] = "Product with specified ID not found"; }); // Add tags for API grouping Tags("Products"); // Add additional metadata Description(builder => builder .Accepts() .Produces(200, "application/json") .ProducesProblem(404)); } public override async Task, NotFound, ProblemHttpResult>> ExecuteAsync(GetProductByIdRequest request, CancellationToken ct) { var result = await mediator.Send(new GetProductQuery(ProductId.From(request.ProductId)), ct); return result.ToGetByIdResult(Map.FromEntity); } } public sealed class GetProductByIdValidator : Validator { public GetProductByIdValidator() { RuleFor(x => x.ProductId) .GreaterThan(0) .WithMessage("Product ID must be greater than 0"); } } public sealed class GetProductByIdMapper : Mapper { public override ProductRecord FromEntity(ProductDto e) => new(e.Id.Value, e.Name, e.UnitPrice); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/GetById/GetProductHandler.cs ================================================ using MinimalClean.Architecture.Web.Domain.ProductAggregate; using MinimalClean.Architecture.Web.Domain.ProductAggregate.Specifications; namespace MinimalClean.Architecture.Web.ProductFeatures.GetById; public record GetProductQuery(ProductId ProductId) : IQuery>; public class GetProductHandler(IReadRepository _repository) : IQueryHandler> { public async ValueTask> Handle(GetProductQuery request, CancellationToken cancellationToken) { var spec = new ProductByIdSpec(request.ProductId); var entity = await _repository.FirstOrDefaultAsync(spec, cancellationToken); if (entity == null) return Result.NotFound(); return new ProductDto(entity.Id, entity.Name, entity.UnitPrice); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/IListProductsQueryService.cs ================================================ namespace MinimalClean.Architecture.Web.ProductFeatures.List; /// /// Represents a service that will actually fetch the necessary data /// Typically implemented in Infrastructure /// public interface IListProductsQueryService { Task> ListAsync(int page, int perPage); } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/ListEndpoint.cs ================================================ using FastEndpoints; using FluentValidation; using MinimalClean.Architecture.Web.ProductFeatures; namespace MinimalClean.Architecture.Web.ProductFeatures.List; public sealed class ListProductsRequest { [BindFrom("page")] public int Page { get; init; } = 1; [BindFrom("per_page")] public int PerPage { get; init; } = Constants.DEFAULT_PAGE_SIZE; } public record ProductListResponse : PagedResult { public ProductListResponse(IReadOnlyList Items, int Page, int PerPage, int TotalCount, int TotalPages) : base(Items, Page, PerPage, TotalCount, TotalPages) { } } public class ListEndpoint(IMediator mediator) : Endpoint { private readonly IMediator _mediator = mediator; public override void Configure() { Get("/Products"); AllowAnonymous(); Summary(s => { s.Summary = "List products with pagination"; s.Description = "Retrieves a paginated list of all products. Supports GitHub-style pagination with 1-based page indexing and configurable page size."; s.ExampleRequest = new ListProductsRequest { Page = 1, PerPage = 10 }; s.ResponseExamples[200] = new ProductListResponse( new List { new(1, "Sample Product 1", 9.99m), new(2, "Sample Product 2", 19.99m) }, 1, 10, 2, 1); s.Params["page"] = "1-based page index (default 1)"; s.Params["per_page"] = $"Page size 1–{Constants.MAX_PAGE_SIZE} (default {Constants.DEFAULT_PAGE_SIZE})"; s.Responses[200] = "Paginated list of products returned successfully"; s.Responses[400] = "Invalid pagination parameters"; }); Tags("Products"); Description(builder => builder .Accepts() .Produces(200, "application/json") .ProducesProblem(400)); } public override async Task HandleAsync(ListProductsRequest request, CancellationToken cancellationToken) { var result = await _mediator.Send(new ListProductsQuery(request.Page, request.PerPage)); if (!result.IsSuccess) { await Send.ErrorsAsync(statusCode: 400, cancellationToken); return; } var pagedResult = result.Value; AddLinkHeader(pagedResult.Page, pagedResult.PerPage, pagedResult.TotalPages); var response = Map.FromEntity(pagedResult); await Send.OkAsync(response, cancellationToken); } private void AddLinkHeader(int page, int perPage, int totalPages) { var baseUrl = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}{HttpContext.Request.Path}"; string Link(string rel, int p) => $"<{baseUrl}?page={p}&per_page={perPage}>; rel=\"{rel}\""; var parts = new List(); if (page > 1) { parts.Add(Link("first", 1)); parts.Add(Link("prev", page - 1)); } if (page < totalPages) { parts.Add(Link("next", page + 1)); parts.Add(Link("last", totalPages)); } if (parts.Count > 0) HttpContext.Response.Headers["Link"] = string.Join(", ", parts); } } public sealed class ListProductsValidator : Validator { public ListProductsValidator() { RuleFor(x => x.Page) .GreaterThanOrEqualTo(1) .WithMessage("page must be >= 1"); RuleFor(x => x.PerPage) .InclusiveBetween(1, Constants.MAX_PAGE_SIZE) .WithMessage($"per_page must be between 1 and {Constants.MAX_PAGE_SIZE}"); } } public sealed class ListProductsMapper : Mapper> { public override ProductListResponse FromEntity(PagedResult e) { var items = e.Items .Select(p => new ProductRecord(p.Id.Value, p.Name, p.UnitPrice)) .ToList(); return new ProductListResponse(items, e.Page, e.PerPage, e.TotalCount, e.TotalPages); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/List/ListProductsHandler.cs ================================================ namespace MinimalClean.Architecture.Web.ProductFeatures.List; public record ListProductsQuery(int? Page = 1, int? PerPage = Constants.DEFAULT_PAGE_SIZE) : IQuery>>; public class ListProductsHandler(IListProductsQueryService query) : IQueryHandler>> { private readonly IListProductsQueryService _query = query; public async ValueTask>> Handle(ListProductsQuery request, CancellationToken cancellationToken) { var result = await _query.ListAsync(request.Page ?? 1, request.PerPage ?? Constants.DEFAULT_PAGE_SIZE); return Result.Success(result); } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/ProductDto.cs ================================================ using MinimalClean.Architecture.Web.Domain.ProductAggregate; namespace MinimalClean.Architecture.Web.ProductFeatures; public record ProductDto(ProductId Id, string Name, decimal UnitPrice); ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/ProductFeatures/ProductRecord.cs ================================================ namespace MinimalClean.Architecture.Web.ProductFeatures; public record ProductRecord(int Id, string Name, decimal UnitPrice); ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Program.cs ================================================ using FastEndpoints; using FastEndpoints.Swagger; using MinimalClean.Architecture.Web.Configurations; using Serilog; var builder = WebApplication.CreateBuilder(args); builder.AddServiceDefaults() // This sets up OpenTelemetry logging .AddLoggerConfigs(); // This adds Serilog for console formatting using var loggerFactory = LoggerFactory.Create(config => config.AddConsole()); var startupLogger = loggerFactory.CreateLogger(); startupLogger.LogInformation("Starting web host"); builder.Services.AddOptionConfigs(builder.Configuration, startupLogger, builder); builder.Services.AddServiceConfigs(startupLogger, builder); builder.Services.AddFastEndpoints() .SwaggerDocument(o => { o.ShortSchemaNames = true; }); var app = builder.Build(); await app.UseAppMiddlewareAndSeedDatabase(); app.MapDefaultEndpoints(); // Aspire health checks and metrics app.Run(); // Make the implicit Program.cs class public, so integration tests can reference the correct assembly for host building public partial class Program { } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/Properties/launchSettings.json ================================================ { "profiles": { "https": { "commandName": "Project", "dotnetRunMessages": true, "launchUrl": "scalar", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "applicationUrl": "https://localhost:57379/" } } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/api.http ================================================ @MinimalClean_HostAddress = https://localhost:57379 @MinimalClean_CartId = 68fe4cfd-84bb-4b8a-bb4e-528c26325c72 ### List Products GET {{MinimalClean_HostAddress}}/products Accept: application/json ### Get Product By ID GET {{MinimalClean_HostAddress}}/products/1 Accept: application/json ### Create Product POST {{MinimalClean_HostAddress}}/products Content-Type: application/json { "name": "New Product", "unitPrice": 29.99 } ### Add to Cart (Anonymous User - creates cart) POST {{MinimalClean_HostAddress}}/cart Content-Type: application/json { "productId": 1, "quantity": 2 } ### Add to Cart (Anonymous User - existing cart) POST {{MinimalClean_HostAddress}}/cart Content-Type: application/json { "cartId": "{{MinimalClean_CartId}}", "productId": 2, "quantity": 3 } ### View Cart GET {{MinimalClean_HostAddress}}/cart/{{MinimalClean_CartId}} Accept: application/json ### Checkout POST {{MinimalClean_HostAddress}}/cart/{{MinimalClean_CartId}}/checkout Content-Type: application/json { "email": "guest@example.com" } ### Note: Get order ID from response for future use ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/appsettings.Development.json ================================================ { "DatabaseOptions": { "RecreateOnStartup": true }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning", "Microsoft.EntityFrameworkCore": "Information" } } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/appsettings.json ================================================ { "ConnectionStrings": { "AppDb": "Server=(localdb)\\mssqllocaldb;Database=MinimalCleanArchitecture;Trusted_Connection=True;MultipleActiveResultSets=true" }, "Serilog": { "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information", "Microsoft.AspNetCore": "Warning", "System": "Warning" } }, "Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"], "WriteTo": [ { "Name": "Console", "Args": { "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}" } } ] }, "Mailserver": { "Server": "localhost", "Port": 25 } } ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/config.nsdepcop ================================================  ================================================ FILE: MinimalClean/src/MinimalClean.Architecture.Web/wwwroot/.gitkeep ================================================ ================================================ FILE: MinimalClean.nuspec ================================================ Ardalis.MinimalClean.Template ASP.NET Minimal Clean Architecture Solution 1.0.1 Steve Smith A simplified Clean Architecture template using vertical slice architecture in a single project. Perfect for MVPs, smaller applications, or teams wanting architectural guidance without multi-project complexity. Features Domain-Driven Design patterns, FastEndpoints, Entity Framework Core, and optional Aspire support. Built with .NET 10 and C#. en-US MIT https://github.com/ardalis/CleanArchitecture * Initial release of Minimal Clean Architecture template * Single-project vertical slice architecture * Built with .NET 10 and C#. * FastEndpoints for REPR pattern * Pragmatic DDD with simplified patterns * Aspire support * 1.0.1 fixes a minor bug Web ASP.NET "Clean Architecture" "Vertical Slice" minimal ddd domain-driven-design clean-architecture ardalis FastEndpoints ./content/icon.png README.md ================================================ FILE: PARALLEL_TEST_EXECUTION.md ================================================ # Parallel Test Execution Configuration This workspace is configured to run all three test projects in parallel in Visual Studio Test Explorer. ## Configuration Files ### `.runsettings` (Solution Root) - Enables parallel test execution at the assembly level - `MaxCpuCount=0` uses all available processors to run test assemblies in parallel - `DisableParallelization=false` ensures parallelization is enabled ### `xunit.runner.json` (In Each Test Project) Each test project contains an `xunit.runner.json` file with: - `parallelizeAssembly: true` - Allows tests from this assembly to run in parallel with other assemblies - `parallelizeTestCollections: true` - Runs test collections within the assembly in parallel - `maxParallelThreads: 0` - Uses xUnit's default algorithm (processors 2) ## How to Use in Visual Studio ### Option 1: Configure via Test Explorer Settings 1. Open **Test Explorer** (Test ? Test Explorer) 2. Click the settings icon (??) in the toolbar 3. Select **Configure Run Settings** ? **Select Solution Wide runsettings File** 4. Browse to and select the `.runsettings` file at the solution root ### Option 2: Configure via Visual Studio Settings 1. Go to **Tools** ? **Options** 2. Navigate to **Test** ? **General** 3. Under **Run Settings File**, browse and select the `.runsettings` file ### Option 3: Automatic Detection Visual Studio will automatically detect and use `.runsettings` in the solution root in most cases. ## Verification After configuration, when you run all tests: - The three test projects (UnitTests, IntegrationTests, FunctionalTests) will run in parallel - Within each project, test collections will also run in parallel - You should see multiple tests running simultaneously in Test Explorer ## Performance Considerations **Recommended for:** - Fast unit tests (UnitTests project) - Independent integration tests that don't share state **Use with caution for:** - Tests using shared resources (databases, files, ports) - Tests with Testcontainers - these may need collection fixtures to control parallelization If you encounter issues with FunctionalTests (which use Testcontainers), you may need to: 1. Disable parallelization for that specific project by setting `parallelizeAssembly: false` in its `xunit.runner.json` 2. Use xUnit Collection Fixtures to control which tests can run in parallel 3. Configure Testcontainers to use unique ports/databases per test class ## Disabling Parallel Execution To disable parallel execution for a specific test project, update its `xunit.runner.json`: ```json { "shadowCopy": false, "parallelizeAssembly": false, "parallelizeTestCollections": false } ``` ## Command Line Usage To use the .runsettings file when running tests from the command line: ```bash dotnet test --settings .runsettings ``` ## Related Documentation - [xUnit Parallel Test Execution](https://xunit.net/docs/running-tests-in-parallel) - [Visual Studio Run Settings](https://learn.microsoft.com/en-us/visualstudio/test/configure-unit-tests-by-using-a-dot-runsettings-file) ================================================ FILE: README.md ================================================ [![.NET Core](https://github.com/ardalis/CleanArchitecture/workflows/.NET%20Core/badge.svg)](https://github.com/ardalis/CleanArchitecture/actions) [![publish Ardalis.CleanArchitecture Template to nuget](https://github.com/ardalis/CleanArchitecture/actions/workflows/publish.yml/badge.svg)](https://github.com/ardalis/CleanArchitecture/actions/workflows/publish.yml) [![Ardalis.CleanArchitecture.Template on NuGet](https://img.shields.io/nuget/v/Ardalis.CleanArchitecture.Template?label=Ardalis.CleanArchitecture.Template)](https://www.nuget.org/packages/Ardalis.CleanArchitecture.Template/) Follow @ardalis   Follow @nimblepros

![Alt](https://repobeats.axiom.co/api/embed/be5094dd306ba53b8f4fc0b43c9de5d8ca23a608.svg "Repobeats analytics image")

# Clean Architecture A starting point for Clean Architecture with ASP.NET Core. [Clean Architecture](https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html) is just the latest in a series of names for the same loosely-coupled, dependency-inverted architecture. You will also find it named [hexagonal](https://alistair.cockburn.us/hexagonal-architecture), [ports-and-adapters](http://www.dossier-andreas.net/software_architecture/ports_and_adapters.html), or [onion architecture](http://jeffreypalermo.com/blog/the-onion-architecture-part-1/). Learn more about Clean Architecture and this template in [NimblePros' Introducing Clean Architecture course](https://academy.nimblepros.com/p/learn-clean-architecture). Use code ARDALIS to save 20%. This architecture is used in the [DDD Fundamentals course](https://www.pluralsight.com/courses/fundamentals-domain-driven-design) by [Steve Smith](https://ardalis.com) and [Julie Lerman](https://thedatafarm.com/). :school: Contact Steve's company, [NimblePros](https://nimblepros.com/), for Clean Architecture or DDD training and/or implementation assistance for your team. ## Take the Course! [Learn about how to implement Clean Architecture](https://academy.nimblepros.com/p/intro-to-clean-architecture) from [NimblePros](https://nimblepros.com) trainers [Sarah "sadukie" Dutkiewicz](https://blog.nimblepros.com/author/sadukie/) and [Steve "ardalis" Smith](https://blog.nimblepros.com/author/ardalis/). ## Table Of Contents - [Clean Architecture](#clean-architecture) - [Take the Course!](#take-the-course) - [Table Of Contents](#table-of-contents) - [Give a Star! :star:](#give-a-star-star) - [Sponsors](#sponsors) - [Troubleshooting Chrome Errors](#troubleshooting-chrome-errors) - [Versions](#versions) - [Learn More](#learn-more) - [Getting Started](#getting-started) - [Template Installation](#template-installation) - [Using the dotnet CLI template](#using-the-dotnet-cli-template) - [Full Clean Architecture (`clean-arch`)](#full-clean-architecture-clean-arch) - [Minimal Clean Architecture (`min-clean`)](#minimal-clean-architecture-min-clean) - [Template Comparison](#template-comparison) - [Which Template Should I Use?](#which-template-should-i-use) - [What about Controllers and Razor Pages?](#what-about-controllers-and-razor-pages) - [Add Ardalis.ApiEndpoints](#add-ardalisapiendpoints) - [Add Controllers](#add-controllers) - [Add Razor Pages](#add-razor-pages) - [Using the GitHub Repository](#using-the-github-repository) - [Running Migrations](#running-migrations) - [Goals](#goals) - [History and Shameless Plug Section](#history-and-shameless-plug-section) - [Design Decisions and Dependencies](#design-decisions-and-dependencies) - [Where To Validate](#where-to-validate) - [The Core Project](#the-core-project) - [The Use Cases Project](#the-use-cases-project) - [The Infrastructure Project](#the-infrastructure-project) - [The Web Project](#the-web-project) - [The SharedKernel Package](#the-sharedkernel-package) - [The Test Projects](#the-test-projects) - [Patterns Used](#patterns-used) - [Domain Events](#domain-events) - [Related Projects](#related-projects) - [Presentations and Videos on Clean Architecture](#presentations-and-videos-on-clean-architecture) ## Give a Star! :star: If you like or are using this project to learn or start your solution, please give it a star. Thanks! Or if you're feeling really generous, we now support GitHub sponsorships - see the button above. ## Sponsors I'm please to announce that [Amazon AWS's FOSS fund](https://github.com/aws/dotnet-foss) has chosen to award a 12-month sponsorship to this project. Thank you, and thanks to all of my other past and current sponsors! ## Troubleshooting Chrome Errors By default the site uses HTTPS and expects you to have a self-signed developer certificate for localhost use. If you get an error with Chrome [see this answer](https://stackoverflow.com/a/31900210/13729) for mitigation instructions. ## Versions The main branch is now using **.NET 9**. This corresponds with NuGet package version 10.x. Previous versions are available - see our [Releases](https://github.com/ardalis/CleanArchitecture/releases). ## Learn More - [Live Stream Recordings Working on Clean Architecture](https://www.youtube.com/c/Ardalis/search?query=clean%20architecture) - [DotNetRocks Podcast Discussion with Steve "ardalis" Smith](https://player.fm/series/net-rocks/clean-architecture-with-steve-smith) - [Fritz and Friends Streaming Discussion with Steve "ardalis" Smith](https://www.youtube.com/watch?v=k8cZUW4MS3I) # Getting Started To use this template, there are **two template options**: 1. **Full Clean Architecture** (`clean-arch`) - Complete multi-project solution with Core, UseCases, Infrastructure, and Web 2. **Minimal Clean Architecture** (`min-clean`) - Simplified single-project vertical slice architecture Choose based on your project's complexity and team preferences. See [Template Comparison](#template-comparison) below. ## Template Installation Install the templates from NuGet: ```powershell # Full Clean Architecture template dotnet new install Ardalis.CleanArchitecture.Template # Minimal Clean Architecture template dotnet new install Ardalis.MinimalClean.Template ``` ## Using the dotnet CLI template ### Full Clean Architecture (`clean-arch`) First, install the template from [NuGet (https://www.nuget.org/packages/Ardalis.CleanArchitecture.Template/)](https://www.nuget.org/packages/Ardalis.CleanArchitecture.Template/): ```powershell dotnet new install Ardalis.CleanArchitecture.Template ``` You can see available options by running the command with the `-?` option: ```powershell dotnet new clean-arch -? ASP.NET Clean Architecture Solution (C#) Author: Steve Smith @ardalis, Erik Dahl Usage: dotnet new clean-arch [options] [template options] Options: -n, --name The name for the output being created. If no name is specified, the name of the output directory is used. -o, --output Location to place the generated output. --dry-run Displays a summary of what would happen if the given command line were run if it would result in a template creation. --force Forces content to be generated even if it would change existing files. --no-update-check Disables checking for the template package updates when instantiating a template. --project The project that should be used for context evaluation. -lang, --language Specifies the template language to instantiate. --type Specifies the template type to instantiate. Template options: -as, --aspire Include .NET Aspire. Type: bool Default: false ``` You should see the template in the list of templates from `dotnet new list` after this installs successfully. Look for "ASP.NET Clean Architecture Solution" with Short Name of "clean-arch". Navigate to the parent directory in which you'd like the solution's folder to be created. Run this command to create the solution structure in a subfolder name `Your.ProjectName`: ```powershell dotnet new clean-arch -o Your.ProjectName ``` The `Your.ProjectName` directory and solution file will be created, and inside that will be all of your new solution contents, properly namespaced and ready to run/test! Example: ![powershell screenshot showing steps](https://user-images.githubusercontent.com/782127/101661723-9fd28e80-3a16-11eb-8be4-f9195d825ad6.png) Thanks [@dahlsailrunner](https://github.com/dahlsailrunner) for your help getting this working! **Known Issues**: - Don't include hyphens in the name. See [#201](https://github.com/ardalis/CleanArchitecture/issues/201). - Don't use 'Ardalis' as your namespace (conflicts with dependencies). ### Minimal Clean Architecture (`min-clean`) For a simpler, single-project vertical slice architecture, use the Minimal Clean Architecture template: ```powershell dotnet new install Ardalis.MinimalClean.Template dotnet new min-clean -o Your.ProjectName ``` This template provides: - **Single Web project** with all code organized by vertical slices (features) - **Simplified architecture** - no separate Core, UseCases, or Infrastructure projects - **Domain-Driven Design patterns** - entities, aggregates, but pragmatic - **FastEndpoints** for clean API endpoints - **Entity Framework Core** with migrations - **Aspire** support for cloud-ready development (optional) Perfect for MVPs, smaller applications, or teams that want architectural guidance without multi-project complexity. ## Template Comparison | Feature | Full Clean Architecture | Minimal Clean Architecture | |---------|------------------------|----------------------------| | **Command** | `clean-arch` | `min-clean` | | **Projects** | 4+ (Core, UseCases, Infrastructure, Web) | 1 (Web only) | | **Organization** | By layer (horizontal) | By feature (vertical slices) | | **DDD Patterns** | Extensive (Aggregates, Value Objects, Domain Events, Specifications) | Pragmatic (simplified domain model) | | **Repository Pattern** | Yes, with Specifications | Optional (direct DbContext or simple repos) | | **Mediator/CQRS** | Yes (separate UseCases project) | Optional (can be in endpoints) | | **Complexity** | Higher - more abstractions | Lower - simpler structure | | **Best For** | Large enterprise apps, long-term maintenance | MVPs, smaller apps, rapid iteration | | **Team Size** | Multiple teams, strict boundaries | Small teams, collaborative | | **Learning Curve** | Steeper - more patterns to learn | Gentler - focused essentials | | **Migration Path** | Can simplify to minimal | Can grow into full template | ### Which Template Should I Use? **Choose Full Clean Architecture if:** - Building large, complex enterprise applications - Multiple teams working on different layers - Long-term maintenance and evolution expected - Need strict separation of concerns and testability - Domain complexity requires extensive DDD patterns **Choose Minimal Clean Architecture if:** - Building MVPs or smaller applications - Want architectural guidance without project overhead - Prefer vertical slice architecture - Team values simplicity and fast iteration - May grow into full Clean Architecture later **Not sure?** Start with Minimal Clean and migrate to Full Clean Architecture if your application grows in complexity. ## What about Controllers and Razor Pages? As of version 9, this solution template only includes support for API Endpoints using the FastEndpoints library. If you want to use my ApiEndpoints library, Razor Pages, and/or Controllers you can use the last template that included them, [version 7.1](https://www.nuget.org/packages/Ardalis.CleanArchitecture.Template/7.1.0). Alternately, they're easily added to this template after installation. ### Add Ardalis.ApiEndpoints To use [Ardalis.ApiEndpoints](https://www.nuget.org/packages/Ardalis.ApiEndpoints) instead of (or in addition to) [FastEndpoints](https://fast-endpoints.com/), just add the reference and use the base classes from the documentation. ```powershell dotnet add package Ardalis.ApiEndpoints ``` ### Add Controllers You'll need to add support for controllers to the Program.cs file. You need: ```csharp builder.Services.AddControllers(); // ControllersWithView if you need Views // and app.MapControllers(); ``` Once these are in place, you should be able to create a Controllers folder and (optionally) a Views folder and everything should work as expected. Personally I find Razor Pages to be much better than Controllers and Views so if you haven't fully investigated Razor Pages you might want to do so right about now before you choose Views. ### Add Razor Pages You'll need to add support for Razor Pages to the Program.cs file. You need: ```csharp builder.Services.AddRazorPages(); // and app.MapRazorPages(); ``` Then you just add a Pages folder in the root of the project and go from there. ## Using the GitHub Repository To get started based on this repository, you need to get a copy locally. You have three options: fork, clone, or download. Most of the time, you probably just want to download. You should **download the repository**, unblock the zip file, and extract it to a new folder if you just want to play with the project or you wish to use it as the starting point for an application. You should **fork this repository** only if you plan on submitting a pull request. Or if you'd like to keep a copy of a snapshot of the repository in your own GitHub account. You should **clone this repository** if you're one of the contributors and you have commit access to it. Otherwise you probably want one of the other options. ## Running Migrations You shouldn't need to do this to use this template, but if you want migrations set up properly in the Infrastructure project, you need to specify that project name when you run the migrations command. In Visual Studio, open the Package Manager Console, and run `Add-Migration InitialMigrationName -StartupProject Your.ProjectName.Web -Context AppDbContext -Project Your.ProjectName.Infrastructure`. In a terminal with the CLI, the command is similar. Run this from the Web project directory: ```powershell dotnet ef migrations add MIGRATIONNAME -c AppDbContext -p ../Your.ProjectName.Infrastructure/Your.ProjectName.Infrastructure.csproj -s Your.ProjectName.Web.csproj -o Data/Migrations ``` To use SqlServer, change `options.UseSqlite(connectionString));` to `options.UseSqlServer(connectionString));` in the `Your.ProjectName.Infrastructure.StartupSetup` file. Also remember to replace the `SqliteConnection` with `DefaultConnection` in the `Your.ProjectName.Web.Program` file, which points to your Database Server. To update the database use this command from the Web project folder (replace `Clean.Architecture` with your project's name): ```powershell dotnet ef database update -c AppDbContext -p ../Clean.Architecture.Infrastructure/Clean.Architecture.Infrastructure.csproj -s Clean.Architecture.Web.csproj ``` # Goals The goal of this repository is to provide a basic solution structure that can be used to build Domain-Driven Design (DDD)-based or simply well-factored, SOLID applications using .NET Core. Learn more about these topics here: - [SOLID Principles for C# Developers](https://www.pluralsight.com/courses/csharp-solid-principles) - [Domain-Driven Design Fundamentals](https://www.pluralsight.com/courses/fundamentals-domain-driven-design) - [Refactoring to SOLID C# Code](https://www.pluralsight.com/courses/refactoring-solid-c-sharp-code) If you're used to building applications as single-project or as a set of projects that follow the traditional UI -> Business Layer -> Data Access Layer "N-Tier" architecture, I recommend you check out these two courses (ideally before DDD Fundamentals): - [Creating N-Tier Applications in C#, Part 1](https://www.pluralsight.com/courses/n-tier-apps-part1) - [Creating N-Tier Applications in C#, Part 2](https://www.pluralsight.com/courses/n-tier-csharp-part2) Steve Smith also maintains Microsoft's reference application, eShopOnWeb, and its associated free eBook. Check them out here: - [eShopOnWeb on GitHub](https://github.com/nimblepros/eShopOnWeb) (now supported by [NimblePros](https://nimblepros.com)) - [Architecting Modern Web Applications with ASP.NET Core and Microsoft Azure](https://aka.ms/webappebook) (eBook) Note that the goal of this project and repository is **not** to provide a sample or reference application. It's meant to just be a template, but with enough pieces in place to show you where things belong as you set up your actual solution. Instead of useless "Class1.cs" there are a few real classes in place. Delete them as soon as you understand why they're there and where you should put your own, similar files. There *is* a sample application in the `/sample` folder, if you're looking for that. ## History and Shameless Plug Section I've used this starter kit to teach the basics of ASP.NET Core using Domain-Driven Design concepts and patterns for some time now (starting when ASP.NET Core was still in pre-release). Typically I teach a one- or two-day hands-on workshop ahead of events like DevIntersection, or private on-site workshops for companies looking to bring their teams up to speed with the latest development technologies and techniques. Feel free to [contact me](https://nimblepros.com/) if you'd like information about upcoming workshops. # Design Decisions and Dependencies The goal of this solution template is to provide a fairly bare-bones starter kit for new projects. It does not include every possible framework, tool, or feature that a particular enterprise application might benefit from. Its choices of technology for things like data access are rooted in what is the most common, accessible technology for most business software developers using Microsoft's technology stack. It doesn't (currently) include extensive support for things like logging, monitoring, or analytics, though these can all be added easily. Below is a list of the technology dependencies it includes, and why they were chosen. Most of these can easily be swapped out for your technology of choice, since the nature of this architecture is to support modularity and encapsulation. ## Where To Validate Validation of user input is a requirement of all software applications. The question is, where does it make sense to implement it in a concise and elegant manner? This solution template includes 4 separate projects, each of which might be responsible for performing validation as well as enforcing business invariants (which, given validation should already have occurred, are usually modeled as exceptions). - [When to Validate and When to Throw Exceptions](https://www.youtube.com/watch?v=dpPcnAT7n7M) The domain model itself should generally rely on object-oriented design to ensure it is always in a consistent state. It leverages encapsulation and limits public state mutation access to achieve this, and it assumes that any arguments passed to it have already been validated, so null or other improper values yield exceptions, not validation results, in most cases. The use cases / application project includes the set of all commands and queries the system supports. It's frequently responsible for validating its own command and query objects. This is most easily done using a [chain of responsibility pattern](https://deviq.com/design-patterns/chain-of-responsibility-pattern) via Mediator behaviors or some other pipeline. The Web project includes all API endpoints, which include their own request and response types, following the [REPR pattern](https://deviq.com/design-patterns/repr-design-pattern). The FastEndpoints library includes built-in support for validation using FluentValidation on the request types. This is a natural place to perform input validation as well. Having validation occur both within the API endpoints and then again at the use case level may be considered redundant. There are tradeoffs to adding essentially the same validation in two places, one for API requests and another for messages sent to Use Case handlers. Following defensive coding, it often makes sense to add validation in both places, as the overhead is minimal and the peace of mind of mind and greater application robustness is often worth it. ## The Core Project The Core project is the center of the Clean Architecture design, and all other project dependencies should point toward it. As such, it has very few external dependencies. The Core project should include the Domain Model including things like: - Entities - Aggregates - Value Objects - Domain Events - Domain Event Handlers - Domain Services - Specifications - Interfaces - DTOs (sometimes) You can learn more about these patterns and how to apply them here: - [DDD Fundamentals](https://www.pluralsight.com/courses/fundamentals-domain-driven-design) - [DDD Concepts](https://deviq.com/domain-driven-design/ddd-overview) ## The Use Cases Project An optional project, I've included it because many folks were demanding it and it's easier to remove than to add later. This is also often referred to as the *Application* or *Application Services* layer. The Use Cases project is organized following CQRS into Commands and Queries (I considered having folders for `Commands` and `Queries` but felt it added little - the folders per actual *command* or *query* is sufficient without extra nesting). Commands mutate the domain model and thus should always use Repository abstractions for their data access (Repositories are how one fetches and persists domain model types). Queries are readonly, and thus **do not need to use the repository pattern**, but instead can use whatever query service or approach is most convenient. Since the Use Cases project is set up to depend on Core and does not depend on Infrastructure, there will still need to be abstractions defined for its data access. And it *can* use things like specifications, which can sometimes help encapsulate query logic as well as result type mapping. But it doesn't *have* to use repository/specification - it can just issue a SQL query or call a stored procedure if that's the most efficient way to get the data. Although this is an optional project to include (without it, your API endpoints would just work directly with the domain model or query services), it does provide a nice UI-ignorant place to add automated tests, and lends itself toward applying policies for cross-cutting concerns using a Chain of Responsibility pattern around the message handlers (for things like validation, caching, auth, logging, timing, etc.). The template includes an example of this for logging, which is located in the [SharedKernel NuGet package](https://github.com/ardalis/Ardalis.SharedKernel/blob/main/src/Ardalis.SharedKernel/LoggingBehavior.cs). ## The Infrastructure Project Most of your application's dependencies on external resources should be implemented in classes defined in the Infrastructure project. These classes should implement interfaces defined in Core. If you have a very large project with many dependencies, it may make sense to have multiple Infrastructure projects (e.g. Infrastructure.Data), but for most projects one Infrastructure project with folders works fine. The template includes data access and domain event implementations, but you would also add things like email providers, file access, web api clients, etc. to this project so they're not adding coupling to your Core or UI projects. ## The Web Project The entry point of the application is the ASP.NET Core web project (or possibly the AspireHost project, which in turn loads the Web project). This is actually a console application, with a `public static void Main` method in `Program.cs`. It leverages FastEndpoints and the REPR pattern to organize its API endpoints. ## The SharedKernel Package A [Shared Kernel](https://deviq.com/domain-driven-design/shared-kernel) is used to share common elements between bounded contexts. It's a DDD term but many organizations leverage "common" projects or packages for things that are useful to share between several applications. I recommend creating a separate SharedKernel project and solution if you will require sharing code between multiple [bounded contexts](https://ardalis.com/encapsulation-boundaries-large-and-small/) (see [DDD Fundamentals](https://www.pluralsight.com/courses/domain-driven-design-fundamentals)). I further recommend this be published as a NuGet package (most likely privately within your organization) and referenced as a NuGet dependency by those projects that require it. Previously a project for SharedKernel was included in this project. However, for the above reasons I've made it a separate package, [Ardalis.SharedKernel](https://github.com/ardalis/Ardalis.SharedKernel), which **you should replace with your own when you use this template**. If you want to see another [example of a SharedKernel package, the one I use in my updated Pluralsight DDD course is on NuGet here](https://www.nuget.org/packages/PluralsightDdd.SharedKernel/). ## The Test Projects Test projects could be organized based on the kind of test (unit, functional, integration, performance, etc.) or by the project they are testing (Core, Infrastructure, Web), or both. For this simple starter kit, the test projects are organized based on the kind of test, with unit, functional and integration test projects existing in this solution. Functional tests are a special kind of [integration test](https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-8.0) that perform [subcutaneous testing](https://martinfowler.com/bliki/SubcutaneousTest.html) of the APIs of the Web project, without actually hosting a real website or going over the network. I've created a bunch of [test helpers](https://github.com/ardalis/HttpClientTestExtensions) to make these kinds of tests shorter and easier to maintain. # Patterns Used This solution template has code built in to support a few common patterns, especially Domain-Driven Design patterns. Here is a brief overview of how a few of them work. ## Domain Events Domain events are a great pattern for decoupling a trigger for an operation from its implementation. This is especially useful from within domain entities since the handlers of the events can have dependencies while the entities themselves typically do not. In the sample, you can see this in action with the `ToDoItem.MarkComplete()` method. The following sequence diagram demonstrates how the event and its handler are used when an item is marked complete through a web API endpoint. ![Domain Event Sequence Diagram](https://user-images.githubusercontent.com/782127/75702680-216ce300-5c73-11ea-9187-ec656192ad3b.png) ## Related Projects - [ApiEndpoints](https://github.com/ardalis/apiendpoints) - [GuardClauses](https://github.com/ardalis/guardclauses) - [HttpClientTestExtensions](https://github.com/ardalis/HttpClientTestExtensions) - [Result](https://github.com/ardalis/result) - [SharedKernel](https://github.com/ardalis/Ardalis.SharedKernel) - [SmartEnum](https://github.com/ardalis/SmartEnum) - [Specification](https://github.com/ardalis/specification) - [FastEndpoints](https://fast-endpoints.com/) ## Presentations and Videos on Clean Architecture - [What's New in Clean Architecture Template 9.1](https://www.youtube.com/watch?v=EJIgjL41em4) - [The REPR Pattern and Clean Architecture](https://www.youtube.com/watch?v=-AJcEJPwagQ) - [Clean Architecture with ASP.NET Core 8](https://www.youtube.com/watch?v=yF9SwL0p0Y0) - [Getting Started with Clean Architecture and .NET 8 (webinar)](https://www.youtube.com/watch?v=IsmyqNrfQQw) ================================================ FILE: README.template.md ================================================ # ${name} Welcome to your new project generated with the Clean Architecture template! ## Getting Started - Build the solution: ```sh dotnet build ``` - Run the application: ```sh dotnet run --project src/Your.ProjectName.Web ``` - Update the database (if using EF Core): ```sh dotnet ef database update -c AppDbContext -p src/Your.ProjectName.Infrastructure/Your.ProjectName.Infrastructure.csproj -s src/Your.ProjectName.Web/Your.ProjectName.Web.csproj ``` ## Solution Structure - **Core**: Domain entities, value objects, interfaces - **UseCases**: Application logic, CQRS handlers - **Infrastructure**: Data access, external services - **Web**: API endpoints (FastEndpoints) For more details, see the documentation or visit the [Clean Architecture Template repository](https://github.com/ardalis/CleanArchitecture). ================================================ FILE: TESTCONTAINERS_IMPLEMENTATION.md ================================================ # Testcontainers Implementation for Functional Tests ## Summary Successfully migrated functional tests from in-memory database to **Testcontainers** with SQL Server 2022. This provides a more realistic testing environment that matches production database behavior. ## Changes Made ### 1. Package References **Added to `Directory.Packages.props`:** ```xml ``` **Updated `tests\Clean.Architecture.FunctionalTests\Clean.Architecture.FunctionalTests.csproj`:** - Removed: `Microsoft.EntityFrameworkCore.InMemory` - Added: `Testcontainers` and `Testcontainers.MsSql` ### 2. CustomWebApplicationFactory **File:** `tests\Clean.Architecture.FunctionalTests\CustomWebApplicationFactory.cs` Key changes: - Implements `IAsyncLifetime` for proper async initialization/cleanup - Creates a SQL Server container using `MsSqlBuilder` - Uses SQL Server 2022 image: `mcr.microsoft.com/mssql/server:2022-latest` - Applies EF Core migrations instead of `EnsureCreated()` - Each test run gets a fresh containerized SQL Server instance ```csharp private readonly MsSqlContainer _dbContainer = new MsSqlBuilder() .WithImage("mcr.microsoft.com/mssql/server:2022-latest") .WithPassword("Your_password123!") .Build(); ``` ### 3. Test Configuration Tests now: - Use real SQL Server running in Docker containers - Apply actual EF Core migrations (matches production) - Run against isolated database instances (parallel test safety) - Clean up containers automatically after tests complete ## Benefits ? **Realistic Testing**: Tests run against actual SQL Server, not in-memory provider ? **Migration Testing**: Validates that migrations work correctly ? **Production Parity**: Database behavior matches production environment ? **Isolation**: Each test class gets its own containerized database ? **Automatic Cleanup**: Containers are disposed after tests complete ## Requirements - **Docker Desktop** must be running on the development machine - Tests take slightly longer (~10-13 seconds vs instant with in-memory) - First run downloads SQL Server 2022 Docker image (~1.5 GB) ## Test Results All 18 tests passing: - ? Unit Tests: 15 tests - ? Functional Tests: 3 tests - ? Total Duration: ~12 seconds ## Usage Run tests normally: ```bash dotnet test ``` Or specifically for functional tests: ```bash dotnet test tests\Clean.Architecture.FunctionalTests\Clean.Architecture.FunctionalTests.csproj ``` ## Notes - Tests use the "Testing" environment configuration - SQL Server password: `Your_password123!` (only for test containers) - Container lifecycle managed by xUnit's `IAsyncLifetime` - Containers are automatically cleaned up even if tests fail ================================================ FILE: docs/architecture-decisions/README.md ================================================ # Architecture Decision Records (ADR) ## What is an Architecture Decision Record (ADR)? An Architecture Decision Record (ADR) documents significant architecture decisions made throughout a project, capturing the context, rationale, and consequences of each decision. This promotes transparency and provides a historical reference for future design considerations. ## Purpose of ADRs - **Knowledge Management**: Consolidates architectural knowledge and decisions. - **Collaboration**: Enhances team communication by documenting discussions and outcomes. - **Clarity**: Provides clear reasoning behind design choices, making it easier for new team members to understand past decisions. ## Best Practices for Writing ADRs 1. **Be Specific**: Each ADR should address a single architectural decision. Avoid conflating multiple decisions into one record. 2. **Document Context**: Clearly explain the project’s context and relevant considerations that influenced the decision. Include team dynamics and priorities. 3. **Rationale and Consequences**: Describe the reasons for the decision, including pros and cons, and outline the implications of the decision for the project and future architecture. 4. **Immutable Records**: Once an ADR is created, avoid altering it. Instead, create a new ADR to reflect any changes or updates. 5. **Timestamp Entries**: Include timestamps to track when each decision was made, especially for aspects that may evolve over time (e.g., costs, schedules). 6. **Use Templates**: Utilize established templates for consistency and completeness in documenting ADRs. ## Versioning ADRs - **Track Changes**: Each time an ADR is updated or a new version is created, increment the version number (e.g., `v1.0`, `v1.1`, etc.) to reflect changes clearly. - **Document Changes**: Include a "Changelog" section in the ADR to summarize what has changed in each version. This can include updates to the rationale, context, or decision consequences. - **Maintain Clarity**: Ensure the latest version is easily accessible while keeping older versions for reference. You might consider using a version control system (e.g., Git) to manage this effectively. ## How to Start Using ADRs 1. **Identify Decisions**: Collaborate with your team to identify significant architecture decisions that need documentation. 2. **Select a Tool**: Choose a tool for documenting ADRs (e.g., markdown files in a Git repository, Google Docs, project management tools). 3. **Create ADRs**: For each decision, create an ADR file in the `adr` directory, following naming conventions (e.g., `choose-database.md`). ## File Name Conventions - Use a present tense imperative verb phrase. - Separate words with lowercase letters and dashes. - Use `.md` extension for markdown formatting. ## Templates Refer to the following templates for structuring your ADRs: - [Decision record template by Michael Nygard](https://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions) - [Decision record template by Jeff Tyree and Art Akerman](https://github.com/adr/adr) - [MADR project templates](https://adr.github.io/madr/) ## Teamwork Advice for ADRs - Foster a culture of collaborative decision-making and ensure ADRs are seen as valuable tools rather than bureaucratic requirements. - Consider using the term "decisions" instead of "ADRs" to encourage engagement. - Maintain living documents by updating existing ADRs with new information rather than rewriting them. ## For More Information - [Architectural Decision Wikipedia](https://en.wikipedia.org/wiki/Architectural_decision) - [Markdown Architectural Decision Records](https://adr.github.io/) - [Tools for working with ADRs](https://github.com/adr/adr) By following these guidelines, your team can effectively leverage ADRs to enhance architectural decision-making and project transparency while keeping a clear version history of all architectural decisions. ================================================ FILE: docs/architecture-decisions/adr-001-dotnet-di-adoption.md ================================================ # ADR 001: Replace Autofac with .NET Core Dependency Injection ## Status Accepted ## Context Initially, this repository employed Autofac for dependency injection. At the time of adoption, Autofac was preferred due to its robust feature set, including: - Support for advanced scenarios such as decorators and modules, which could be placed close to their corresponding implementations. - A well-established history of stability and maturity, having been used in various projects before .NET Core's built-in DI was fully featured. As the .NET ecosystem evolved, the built-in DI container began to meet the needs of our project without introducing the added complexity associated with Autofac. The .NET DI framework has matured significantly, offering sufficient functionality for typical use cases, including: - Improved support for configuration through extension methods. - A simpler learning curve for new contributors familiar with .NET conventions. ## Decision Based on community feedback and a review of our project's requirements, we have decided to remove Autofac from this template and transition to using .NET's built-in dependency injection infrastructure. This decision aligns with the goal of simplifying the codebase and reducing external dependencies. ## Consequences - **Simplified Codebase**: Removing Autofac results in a cleaner, more maintainable codebase that adheres to .NET standards. - **Reduced Complexity**: The transition eliminates the need for additional files and configurations specific to Autofac, making the project easier to understand for new contributors. - **Standardization**: Adopting .NET's built-in DI promotes consistency with other .NET projects, making it easier for developers familiar with the framework to contribute effectively. ## References - [Issue #649: Why is this repo using Autofac instead of .NET's own DI infrastructure?](https://github.com/ardalis/CleanArchitecture/issues/649) - Discussion that led to this decision. - [Getting Started with Architecture Decision Records](https://ardalis.com/getting-started-with-architecture-decision-records/) - Resource on ADR best practices. ================================================ FILE: docs/minimal-clean-architecture.md ================================================ # Minimal Clean Architecture ## Overview The **Minimal Clean Architecture** template provides a simplified, pragmatic approach to Clean Architecture for ASP.NET Core applications. It maintains the core principles of Clean Architecture—separation of concerns, dependency inversion, and testability—while reducing complexity through a single-project Vertical Slice Architecture (VSA). ## Philosophy ### Core Principles 1. **Simplicity First**: Minimize unnecessary abstractions and project boundaries 2. **Vertical Slices**: Organize by feature rather than technical layer 3. **Pragmatic DDD**: Use domain patterns where they add value, not everywhere 4. **Progressive Enhancement**: Start simple, add complexity only when needed ### Clean Architecture Principles Maintained - ✅ **Dependency Inversion**: Domain doesn't depend on infrastructure - ✅ **Testability**: Business logic can be tested in isolation - ✅ **Separation of Concerns**: Clear boundaries between domain, infrastructure, and presentation - ✅ **Framework Independence**: Domain logic isn't coupled to ASP.NET Core ### Simplifications from Full Template - **Single Project**: All code in one Web project instead of 4+ projects - **Simplified DDD**: Essential patterns only (entities, aggregates) without extensive value objects, specifications - **Optional CQRS**: Mediator is optional; logic can live in endpoints - **Direct Data Access**: Can use DbContext directly or simple repositories instead of complex repository pattern - **Vertical Organization**: Group by feature (Cart, Order, Product) instead of by layer ## Architecture ### Project Structure ```text MinimalClean.Architecture.Web/ ├── Domain/ # Domain Layer │ ├── CartAggregate/ │ │ ├── Cart.cs # Aggregate root │ │ ├── CartItem.cs # Entity │ │ └── Events/ # Domain events (optional) │ ├── OrderAggregate/ │ └── ProductAggregate/ ├── Infrastructure/ # Infrastructure Layer │ ├── Data/ │ │ ├── AppDbContext.cs # EF Core DbContext │ │ ├── Config/ # EF configurations │ │ │ ├── CartConfiguration.cs │ │ │ └── OrderConfiguration.cs │ │ └── Migrations/ # EF migrations │ ├── Email/ # External services │ └── Services/ # Infrastructure services ├── Endpoints/ # Presentation Layer │ ├── Cart/ │ │ ├── Create.cs # Create cart endpoint │ │ ├── AddItem.cs # Add item to cart │ │ └── List.cs # List carts │ ├── Order/ │ └── Product/ └── Program.cs # Application startup ``` ### Vertical Slice Organization Each feature (Cart, Order, Product) contains: - **Domain**: Entities and business logic - **Infrastructure**: Data configurations for that feature - **Endpoints**: API endpoints for that feature This keeps related code together, making it easier to understand and modify features independently. ### Dependency Flow ```text Endpoints ──→ Domain ↓ Infrastructure ──→ Domain ``` - Endpoints can use Domain and Infrastructure - Infrastructure depends on Domain (for entity configurations) - Domain has no dependencies on other layers ## Design Decisions ### ADR-001: Single Project Architecture **Status**: Accepted **Context**: Need to balance architectural guidance with simplicity for smaller applications. **Decision**: Use a single Web project with clear folder structure instead of multiple projects. **Consequences**: - ✅ Simpler to navigate and understand - ✅ Faster builds (no project-to-project references) - ✅ Easier to refactor (no project boundary concerns) - ✅ Lower initial complexity - ⚠️ Developers must respect folder boundaries (not enforced by compiler) - ⚠️ Harder to enforce strict layer separation **Migration Path**: Can be extracted into multiple projects later if needed. ### ADR-002: Vertical Slice Organization **Status**: Accepted **Context**: Need to organize code in a way that's easy to understand and modify. **Decision**: Organize by feature (vertical slices) rather than by layer (horizontal). **Consequences**: - ✅ Related code is colocated (easier to find) - ✅ Features can be modified independently - ✅ Natural fit for microservices extraction - ✅ Aligns with business capabilities - ⚠️ May have some code duplication across features - ⚠️ Shared concerns need careful consideration ### ADR-003: Pragmatic DDD **Status**: Accepted **Context**: Full DDD patterns can be overkill for simpler domains. **Decision**: Use essential DDD patterns (entities, aggregates) but keep it simple. **Patterns Included**: - ✅ Entities with encapsulation - ✅ Aggregate roots - ✅ Domain events (optional) **Patterns Simplified/Optional**: - ⚠️ Value Objects (use when valuable, not everywhere) - ⚠️ Specifications (use LINQ, add if needed) - ⚠️ Domain Services (add only when needed) **Consequences**: - ✅ Easier to learn and apply - ✅ Less boilerplate code - ✅ Faster development - ⚠️ May need to add patterns as domain complexity grows ### ADR-004: Optional Mediator/CQRS **Status**: Accepted **Context**: CQRS with Mediator adds valuable patterns but also complexity. **Decision**: Make Mediator optional; allow business logic in endpoints for simple cases. Trade-off is no ability to use custom pipeline for cross-cutting concerns. **Usage Guidelines**: - Simple CRUD: Can put logic directly in endpoints - Complex workflows: Use Mediator commands/queries - Cross-cutting concerns: Use Mediator pipeline behaviors **Consequences**: - ✅ Lower initial complexity - ✅ Developers choose appropriate level of abstraction - ⚠️ Inconsistent patterns across codebase possible - ⚠️ Need clear team guidelines on when to use Mediator ### ADR-005: FastEndpoints for APIs **Status**: Accepted **Context**: Need clean, testable API endpoints. **Decision**: Use FastEndpoints with REPR pattern. **Consequences**: - ✅ One file per endpoint (easy to find) - ✅ Built-in validation support - ✅ Clear request/response types - ✅ Testable without HTTP layer - ⚠️ Different from standard ASP.NET Core patterns - ⚠️ Learning curve for team ## When to Use This Template ### Ideal Scenarios 1. **MVPs and Prototypes** - Need to validate ideas quickly - Want architectural guidance without overhead - May grow into larger application 2. **Small to Medium Applications** - 5-50 endpoints - 5-20 domain entities - 1-5 developers - Simple to moderate domain complexity 3. **Learning Clean Architecture** - Want to understand principles without complexity - Stepping stone to full Clean Architecture - Teaching tool for teams 4. **Vertical Slice Architecture Preference** - Team prefers feature-based organization - Planning to extract microservices later - Value cohesion over layer separation ### Not Recommended For 1. **Large Enterprise Applications** - Complex domain requiring extensive DDD patterns - Multiple teams needing strict boundaries - Long-term evolution expected - → Use Full Clean Architecture instead 2. **Microservices from Start** - If you know you'll split into services - → Consider separate services with minimal template each 3. **Regulatory/Compliance Heavy** - Strict audit requirements - Need enforced layer boundaries - → Use Full Clean Architecture instead ## Migration Paths ### From Minimal to Full Clean Architecture As your application grows, you can migrate to the full template: #### Step 1: Extract Core Project ```powershell # Create new Core project dotnet new classlib -n YourProject.Core # Move domain entities mv Domain/* ../YourProject.Core/ # Update namespaces # Update project references ``` #### Step 2: Extract Infrastructure Project ```powershell # Create Infrastructure project dotnet new classlib -n YourProject.Infrastructure # Move infrastructure code mv Infrastructure/* ../YourProject.Infrastructure/ # Add reference to Core dotnet add YourProject.Infrastructure reference YourProject.Core ``` #### Step 3: Extract UseCases (Optional) ```powershell # Create UseCases project dotnet new classlib -n YourProject.UseCases # Move business logic from endpoints to use cases # Add Mediator (if not already using) # Create command/query handlers # Leverage Mediator Behaviors for cross-cutting concerns ``` #### Step 4: Clean Up Web Project - Update project references - Keep only endpoints and startup code - Reference UseCases or Infrastructure as needed ### From Full Clean Architecture to Minimal If you find the full template too complex: #### Step 1: Merge Projects ```powershell # Copy all code into Web project # Organize by vertical slices ``` #### Step 2: Simplify Patterns - Replace Specifications with LINQ - Simplify Value Objects to primitives where beneficial - Remove unnecessary abstractions #### Step 3: Organize Vertically - Group by feature instead of layer - Colocate related code ## Best Practices ### Domain Layer ```csharp // Good: Encapsulated entity public class Cart { private readonly List _items = new(); public IReadOnlyCollection Items => _items.AsReadOnly(); public void AddItem(Product product, int quantity) { // Business logic here var existingItem = _items.FirstOrDefault(i => i.ProductId == product.Id); if (existingItem != null) { existingItem.IncreaseQuantity(quantity); } else { _items.Add(new CartItem(product, quantity)); } } } // Avoid: Anemic domain model public class Cart { public List Items { get; set; } = new(); } ``` ### Endpoint Layer ```csharp // Good: Clear, focused endpoint public class CreateCart : EndpointWithoutRequest { private readonly AppDbContext _db; public CreateCart(AppDbContext db) => _db = db; public override void Configure() { Post("/carts"); AllowAnonymous(); } public override async Task HandleAsync(CancellationToken ct) { var cart = new Cart(guestUserId: Guid.NewGuid()); _db.Carts.Add(cart); await _db.SaveChangesAsync(ct); await Send.Async(new CartResponse(cart.Id, cart.Items.Count), cancellation: ct); } } ``` ### Infrastructure Layer ```csharp // Good: Focused EF configuration public class CartConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.HasKey(c => c.Id); builder.HasMany(c => c.Items) .WithOne() .HasForeignKey("CartId"); } } ``` ## Testing Strategy ### Unit Tests Focus on domain logic: ```csharp public class CartTests { [Fact] public void AddItem_NewProduct_AddsToCart() { // Arrange var cart = new Cart(guestUserId: Guid.NewGuid()); var product = new Product("Test", 10m); // Act cart.AddItem(product, 2); // Assert Assert.Single(cart.Items); Assert.Equal(2, cart.Items.First().Quantity); } } ``` ### Functional Tests Test endpoints end-to-end: ```csharp public class CartEndpointsTests : IClassFixture> { [Fact] public async Task CreateCart_ReturnsNewCart() { // Arrange var client = _factory.CreateClient(); // Act var response = await client.PostAsync("/carts", null); // Assert response.EnsureSuccessStatusCode(); var cart = await response.Content.ReadFromJsonAsync(); Assert.NotNull(cart); } } ``` ## Resources - [Main Clean Architecture Template](https://github.com/ardalis/CleanArchitecture) - [Vertical Slice Architecture](https://jimmybogard.com/vertical-slice-architecture/) - [FastEndpoints Documentation](https://fast-endpoints.com/) - [Domain-Driven Design Fundamentals](https://www.pluralsight.com/courses/fundamentals-domain-driven-design) - [Clean Architecture Course](https://academy.nimblepros.com/p/intro-to-clean-architecture) ## Contributing Contributions are welcome! Please see the main [Contributing Guide](../CONTRIBUTING.md). ## License MIT - see [LICENSE](../LICENSE) ================================================ FILE: global.json ================================================ { "sdk": { "version": "10.0.100", "rollForward": "latestMajor", "allowPrerelease": true } } ================================================ FILE: nuget.config ================================================  ================================================ FILE: sample/.editorconfig ================================================ ############################### # Core EditorConfig Options # ############################### root = true # All files [*] indent_style = space # XML project files [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] indent_size = 2 # XML config files [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] indent_size = 2 # Code files [*.{cs,csx,vb,vbx}] indent_size =2 insert_final_newline = true charset = utf-8-bom ############################### # .NET Coding Conventions # ############################### [*.{cs,vb}] # Organize usings dotnet_sort_system_directives_first = true # this. preferences dotnet_style_qualification_for_field = false:silent dotnet_style_qualification_for_property = false:silent dotnet_style_qualification_for_method = false:silent dotnet_style_qualification_for_event = false:silent # Language keywords vs BCL types preferences dotnet_style_predefined_type_for_locals_parameters_members = true:silent dotnet_style_predefined_type_for_member_access = true:silent # Parentheses preferences dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent # Modifier preferences dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent dotnet_style_readonly_field = true:suggestion # Expression-level preferences dotnet_style_object_initializer = true:suggestion dotnet_style_collection_initializer = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_coalesce_expression = true:suggestion dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent dotnet_style_prefer_inferred_tuple_names = true:suggestion dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion dotnet_style_prefer_auto_properties = true:silent dotnet_style_prefer_conditional_expression_over_assignment = true:silent dotnet_style_prefer_conditional_expression_over_return = true:silent ############################### # Naming Conventions # ############################### # Style Definitions dotnet_naming_style.pascal_case_style.capitalization = pascal_case # Use PascalCase for constant fields dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style dotnet_naming_symbols.constant_fields.applicable_kinds = field dotnet_naming_symbols.constant_fields.applicable_accessibilities = * dotnet_naming_symbols.constant_fields.required_modifiers = const tab_width=2 dotnet_naming_rule.private_members_with_underscore.symbols = private_fields dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore dotnet_naming_rule.private_members_with_underscore.severity = suggestion dotnet_naming_symbols.private_fields.applicable_kinds = field dotnet_naming_symbols.private_fields.applicable_accessibilities = private dotnet_naming_style.prefix_underscore.capitalization = camel_case dotnet_naming_style.prefix_underscore.required_prefix = _ ############################### # C# Coding Conventions # ############################### [*.cs] # var preferences csharp_style_var_for_built_in_types = true:silent csharp_style_var_when_type_is_apparent = true:silent csharp_style_var_elsewhere = true:silent # Expression-bodied members csharp_style_expression_bodied_methods = false:silent csharp_style_expression_bodied_constructors = false:silent csharp_style_expression_bodied_operators = false:silent csharp_style_expression_bodied_properties = true:silent csharp_style_expression_bodied_indexers = true:silent csharp_style_expression_bodied_accessors = true:silent # Pattern matching preferences csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion csharp_style_pattern_matching_over_as_with_null_check = true:suggestion # Null-checking preferences csharp_style_throw_expression = true:suggestion csharp_style_conditional_delegate_call = true:suggestion # Modifier preferences csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion # Expression-level preferences csharp_prefer_braces = true:silent csharp_style_deconstructed_variable_declaration = true:suggestion csharp_prefer_simple_default_expression = true:suggestion csharp_style_pattern_local_over_anonymous_function = true:suggestion csharp_style_inlined_variable_declaration = true:suggestion # Namespaces csharp_style_namespace_declarations = file_scoped:warning ############################### # C# Formatting Rules # ############################### # New line preferences csharp_new_line_before_open_brace = all csharp_new_line_before_else = true csharp_new_line_before_catch = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_between_query_expression_clauses = true # Indentation preferences csharp_indent_case_contents = true csharp_indent_switch_labels = true csharp_indent_labels = flush_left # Space preferences csharp_space_after_cast = false csharp_space_after_keywords_in_control_flow_statements = true csharp_space_between_method_call_parameter_list_parentheses = false csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_space_before_colon_in_inheritance_clause = true csharp_space_after_colon_in_inheritance_clause = true csharp_space_around_binary_operators = before_and_after csharp_space_between_method_declaration_empty_parameter_list_parentheses = false csharp_space_between_method_call_name_and_opening_parenthesis = false csharp_space_between_method_call_empty_parameter_list_parentheses = false # Wrapping preferences csharp_preserve_single_line_statements = true csharp_preserve_single_line_blocks = true ############################### # VB Coding Conventions # ############################### [*.vb] # Modifier preferences visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion ================================================ FILE: sample/.github/copilot-instructions.md ================================================ # Solution Development Practices & Conventions This document provides guidance for contributing to this solution, which is based on the Clean Architecture template for .NET 9. Follow these practices to ensure consistency, maintainability, and adherence to architectural principles. --- ## Table of Contents - [Architecture Overview](#architecture-overview) - [Project Structure](#project-structure) - [Development Patterns](#development-patterns) - [Use Case Guidelines](#use-case-guidelines) - [API Endpoint Conventions](#api-endpoint-conventions) - [Validation Strategy](#validation-strategy) - [Testing](#testing) - [File & Naming Conventions](#file--naming-conventions) - [Common Gotchas](#common-gotchas) - [Essential Commands](#essential-commands) --- ## Architecture Overview - Follows Clean Architecture and Domain-Driven Design (DDD) principles. - **Core** project contains domain models, value objects, and repository interfaces. - **UseCases** project contains application logic, commands, queries, and handlers. - **Infrastructure** project implements data access and external services. - **Web** project exposes API endpoints using FastEndpoints. **Dependency Flow:** `Core` ← `UseCases` ← `Infrastructure` `Core` ← `UseCases` ← `Web` _Core must never depend on outer layers._ --- ## Project Structure - **Core**: Domain entities, aggregates, value objects, domain events, repository interfaces. - **UseCases**: CQRS handlers (commands/queries), Mediator, application logic. - **Infrastructure**: EF Core, external services, repository implementations. - **Web**: FastEndpoints API, request/response/validator classes, REPR pattern. --- ## Development Patterns - **CQRS**: Use commands for mutations and queries for reads. - **Mediator**: All use case handlers implement Mediator interfaces. - **Repository Pattern**: Use repository interfaces from Core, implemented in Infrastructure. - **Value Objects**: Use for domain concepts (e.g., `ProjectName`, `ContributorId`). - **Domain Events**: Use for cross-aggregate communication. --- ## Use Case Guidelines - **Inputs/Outputs**: Use Value Objects (`ProjectName`, `ContributorId`) for use case command/query parameters and return types. Use value objects internally within the domain. Translate from primitives in the endpoints. - **Validation**: Validate at API and use case boundaries; enforce business invariants in the domain. - **Error Handling**: Use `Ardalis.Result` for use case results and error propagation. - **Defensive Coding**: Validate commands/queries in handlers; assume pre-validated input in domain. Use `Ardalis.GuardClauses` to defend against invalid states in the domain. --- ## API Endpoint Conventions - One endpoint per file (e.g., `Create.cs`, `Update.cs`). - Separate files for request, response, and validator (e.g., `Create.CreateRequest.cs`, `Create.CreateResponse.cs`, `Create.CreateValidator.cs`). - Endpoints inherit from `Endpoint`. - Use REPR (Request/Endpoint/Processor/Response) pattern. --- ## Validation Strategy - **API Level**: Use FluentValidation for request DTOs. - **Use Case Level**: Validate commands/queries in handlers or behaviors. - **Domain Level**: Throw exceptions for business rule violations using guard clauses (e.g., `Ardalis.GuardClauses`).) --- ## Testing - **UnitTests**: Test domain logic and use cases. - **IntegrationTests**: Test infrastructure and database interactions. - **FunctionalTests**: Test API endpoints using subcutaneous testing. --- ## File & Naming Conventions - Use PascalCase for files, classes, and methods. - Organize files by feature (e.g., `Contributors/Create.cs`, `Projects/Create.cs`). - Place request, response, and validator files alongside their endpoint. - Do not use hyphens in project or file names. - Test classes are named for the class and method being tested. Examples: `ProjectAddItem` or `CreateContributorHandlerHandle`. - Test methods are named such that the class name and method name form a sentence describing the test. (e.g. `ReturnsItemGivenValidInputs()` or `ThrowsExceptionGivenNegativeInput()`) --- ## Common Gotchas - Do not allow Core to reference UseCases, Infrastructure, or Web. - Use absolute paths for EF Core migration commands. ================================================ FILE: sample/.runsettings ================================================ 0 ================================================ FILE: sample/Directory.Build.props ================================================ true true net10.0 enable enable 1591 ================================================ FILE: sample/Directory.Packages.props ================================================ ================================================ FILE: sample/NimblePros.SampleToDo.slnx ================================================ ================================================ FILE: sample/src/NimblePros.SampleToDo.AspireHost/NimblePros.SampleToDo.AspireHost.csproj ================================================ Exe true c540eeb6-e06b-4456-a539-be58dd8b88c7 ================================================ FILE: sample/src/NimblePros.SampleToDo.AspireHost/Program.cs ================================================ using System.Net.Sockets; var builder = DistributedApplication.CreateBuilder(args); // Papercut container var papercut = builder.AddContainer("papercut", "jijiechen/papercut", "latest") .WithEndpoint("smtp", e => { e.TargetPort = 25; // container port e.Port = 25; // host port (optional—omit to auto-assign) e.Protocol = ProtocolType.Tcp; e.UriScheme = "smtp"; // makes the resolved value look like smtp://host:port }) .WithEndpoint("ui", e => { e.TargetPort = 37408; e.Port = 37408; // optional – Aspire can allocate e.UriScheme = "http"; }); // Your web project var web = builder.AddProject("web") .WithHttpHealthCheck("/health") // Pass the endpoints to the app via env vars (EndpointReference resolves to a URL at run time) .WithEnvironment("Papercut__Smtp__Url", papercut.GetEndpoint("smtp")) .WithEnvironment("Papercut__Ui__Url", papercut.GetEndpoint("ui")); // (optionally) if your app wants separate host/port values, you can parse the URL at startup, // or expose two env vars and parse them from the URL inside the app. builder.Build().Run(); ================================================ FILE: sample/src/NimblePros.SampleToDo.AspireHost/Properties/launchSettings.json ================================================ { "$schema": "https://json.schemastore.org/launchsettings.json", "profiles": { "https": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "applicationUrl": "https://localhost:17143;http://localhost:15258", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "DOTNET_ENVIRONMENT": "Development", "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21007", "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22245" } }, "http": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "applicationUrl": "http://localhost:15258", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "DOTNET_ENVIRONMENT": "Development", "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19187", "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20134" } } } } ================================================ FILE: sample/src/NimblePros.SampleToDo.AspireHost/appsettings.Development.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } } } ================================================ FILE: sample/src/NimblePros.SampleToDo.AspireHost/appsettings.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning", "Aspire.Hosting.Dcp": "Warning" } } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Contributor.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate.Events; namespace NimblePros.SampleToDo.Core.ContributorAggregate; public sealed class Contributor : EntityBase, IAggregateRoot { public ContributorName Name { get; private set; } public Contributor(ContributorName name) { Name = name; } public Contributor UpdateName(ContributorName newName) { if (Name.Equals(newName)) return this; Name = newName; this.RegisterDomainEvent(new ContributorNameUpdatedEvent(this)); return this; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/ContributorId.cs ================================================ using Vogen; namespace NimblePros.SampleToDo.Core.ContributorAggregate; [ValueObject] public partial struct ContributorId { private static Validation Validate(int value) => value > 0 ? Validation.Ok : Validation.Invalid("ContributorId must be positive."); } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/ContributorName.cs ================================================ using Vogen; namespace NimblePros.SampleToDo.Core.ContributorAggregate; [ValueObject(conversions: Conversions.SystemTextJson)] public partial struct ContributorName { public const int MaxLength = 100; private static Validation Validate(in string name) => string.IsNullOrEmpty(name) ? Validation.Invalid("Name cannot be empty") : name.Length > MaxLength ? Validation.Invalid($"Name cannot be longer than {MaxLength} characters") : Validation.Ok; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Events/ContributorDeletedEvent.cs ================================================ namespace NimblePros.SampleToDo.Core.ContributorAggregate.Events; /// /// A domain event that is dispatched whenever a contributor is deleted. /// The DeleteContributorService is used to dispatch this event. /// public sealed class ContributorDeletedEvent(ContributorId contributorId) : DomainEventBase { public ContributorId ContributorId { get; private set; } = contributorId; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Events/ContributorNameUpdatedEvent.cs ================================================ namespace NimblePros.SampleToDo.Core.ContributorAggregate.Events; public sealed class ContributorNameUpdatedEvent(Contributor contributor) : DomainEventBase { public Contributor Contributor { get; private set; } = contributor; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Handlers/ContributorDeletedHandler.cs ================================================ using Microsoft.Extensions.Logging; using NimblePros.SampleToDo.Core.ContributorAggregate.Events; using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate.Specifications; namespace NimblePros.SampleToDo.Core.ContributorAggregate.Handlers; public class ContributorDeletedHandler : INotificationHandler { private readonly IRepository _repository; private readonly ILogger _logger; public ContributorDeletedHandler(IRepository repository, ILogger logger) { _repository = repository; _logger = logger; } public async ValueTask Handle(ContributorDeletedEvent domainEvent, CancellationToken cancellationToken) { _logger.LogInformation("Removing deleted contributor {contributorId} from all projects...", domainEvent.ContributorId); // Perform eventual consistency removal of contributors from projects when one is deleted var projectSpec = new ProjectsWithItemsByContributorIdSpec(domainEvent.ContributorId); var projects = await _repository.ListAsync(projectSpec, cancellationToken); foreach (var project in projects) { project.Items .Where(item => item.ContributorId == domainEvent.ContributorId) .ToList() .ForEach(item => item.RemoveContributor()); await _repository.UpdateAsync(project, cancellationToken); } } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Handlers/ContributorNameUpdatedEventLoggingHandler.cs ================================================ using Microsoft.Extensions.Logging; using NimblePros.SampleToDo.Core.ContributorAggregate.Events; namespace NimblePros.SampleToDo.Core.ContributorAggregate.Handlers; public class ContributorNameUpdatedEventLoggingHandler(ILogger logger) : INotificationHandler { private readonly ILogger _logger = logger; public ValueTask Handle(ContributorNameUpdatedEvent notification, CancellationToken cancellationToken) { var contributorId = notification.Contributor.Id; string newName = notification.Contributor.Name.Value; _logger.LogInformation("Contributor {contributorId}'s name was updated to {newName}", contributorId, newName); return ValueTask.CompletedTask; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Specifications/ContributorByIdSpec.cs ================================================ namespace NimblePros.SampleToDo.Core.ContributorAggregate.Specifications; public class ContributorByIdSpec : Specification, ISingleResultSpecification { public ContributorByIdSpec(ContributorId contributorId) { Query .Where(contributor => contributor.Id == contributorId); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/CoreServiceExtensions.cs ================================================ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using NimblePros.SampleToDo.Core.Interfaces; using NimblePros.SampleToDo.Core.Services; namespace NimblePros.SampleToDo.Core; public static class CoreServiceExtensions { public static IServiceCollection AddCoreServices(this IServiceCollection services, ILogger logger) { services.AddScoped(); services.AddScoped(); logger.LogInformation("{Project} services registered", "Core"); return services; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/GlobalUsings.cs ================================================ global using Ardalis.GuardClauses; global using Ardalis.Result; global using Ardalis.SmartEnum; global using Ardalis.Specification; global using Mediator; global using NimblePros.SharedKernel; ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/Interfaces/IDeleteContributorService.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; namespace NimblePros.SampleToDo.Core.Interfaces; public interface IDeleteContributorService { // This service and method exist to provide a place in which to fire domain events // when deleting this aggregate root entity public Task DeleteContributor(ContributorId contributorId); } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/Interfaces/IEmailSender.cs ================================================ namespace NimblePros.SampleToDo.Core.Interfaces; public interface IEmailSender { Task SendEmailAsync(string to, string from, string subject, string body); } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/Interfaces/IToDoItemSearchService.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.Core.Interfaces; public interface IToDoItemSearchService { Task> GetNextIncompleteItemAsync(ProjectId projectId); Task>> GetAllIncompleteItemsAsync(ProjectId projectId, string searchString); } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/Localization.cs ================================================ using Microsoft.Extensions.Localization; /// /// Exposes the current to static code /// (Vogen Validate, domain events, etc.) without pulling the whole /// DI container into Core. /// public static class Localization { /// /// Set by Program.cs during app startup. /// public static ILocalizationContext? Current { get; set; } public sealed class LocalizationContext : ILocalizationContext { public IStringLocalizer Localizer { get; } public LocalizationContext(IStringLocalizer localizer) => Localizer = localizer; } } public interface ILocalizationContext { IStringLocalizer Localizer { get; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/NimblePros.SampleToDo.Core.csproj ================================================  ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Events/ContributorAddedToItemEvent.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; namespace NimblePros.SampleToDo.Core.ProjectAggregate.Events; public sealed class ContributorAddedToItemEvent(ToDoItem item, ContributorId contributorId) : DomainEventBase { public ContributorId ContributorId { get; set; } = contributorId; public ToDoItem Item { get; set; } = item; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Events/NewItemAddedEvent.cs ================================================ namespace NimblePros.SampleToDo.Core.ProjectAggregate.Events; public sealed class NewItemAddedEvent(Project project, ToDoItem newItem) : DomainEventBase { public Project Project { get; private set; } = project; public ToDoItem NewItem { get; private set; } = newItem; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Events/ToDoItemCompletedEvent.cs ================================================ namespace NimblePros.SampleToDo.Core.ProjectAggregate.Events; public sealed class ToDoItemCompletedEvent(ToDoItem completedItem) : DomainEventBase { public ToDoItem CompletedItem { get; private set; } = completedItem; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Handlers/ContributorAddedToItemLoggingHandler.cs ================================================ using Microsoft.Extensions.Logging; using NimblePros.SampleToDo.Core.ProjectAggregate.Events; namespace NimblePros.SampleToDo.Core.ProjectAggregate.Handlers; public class ContributorAddedToItemLoggingHandler(ILogger logger) : INotificationHandler { private readonly ILogger _logger = logger; public ValueTask Handle(ContributorAddedToItemEvent notification, CancellationToken cancellationToken) { _logger.LogInformation("Contributor {ContributorId} assigned to ToDo item {Item}", notification.ContributorId, notification.Item); return default; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Handlers/ItemCompletedEmailNotificationHandler.cs ================================================ using NimblePros.SampleToDo.Core.Interfaces; using NimblePros.SampleToDo.Core.ProjectAggregate.Events; namespace NimblePros.SampleToDo.Core.ProjectAggregate.Handlers; public class ItemCompletedEmailNotificationHandler : Mediator.INotificationHandler { private readonly IEmailSender _emailSender; // In a REAL app you might want to use the Outbox pattern and a command/queue here... public ItemCompletedEmailNotificationHandler(IEmailSender emailSender) { _emailSender = emailSender; } // configure a test email server to demo this works // https://ardalis.com/configuring-a-local-test-email-server public async ValueTask Handle(ToDoItemCompletedEvent domainEvent, CancellationToken cancellationToken) { Guard.Against.Null(domainEvent, nameof(domainEvent)); await _emailSender.SendEmailAsync("test@test.com", "test@test.com", $"{domainEvent.CompletedItem.Title} was completed.", domainEvent.CompletedItem.ToString()); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Handlers/NewItemAddedLoggingHandler.cs ================================================ using Microsoft.Extensions.Logging; using NimblePros.SampleToDo.Core.ProjectAggregate.Events; namespace NimblePros.SampleToDo.Core.ProjectAggregate.Handlers; public class NewItemAddedLoggingHandler(ILogger logger) : INotificationHandler { private readonly ILogger _logger = logger; public ValueTask Handle(NewItemAddedEvent notification, CancellationToken cancellationToken) { _logger.LogInformation("New Item {Item} added to Project {Project}", notification.NewItem, notification.Project); return default; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Priority.cs ================================================ namespace NimblePros.SampleToDo.Core.ProjectAggregate; public class Priority : SmartEnum { public static readonly Priority Backlog = new(nameof(Backlog), 0); public static readonly Priority Critical = new(nameof(Critical), 1); protected Priority(string name, int value) : base(name, value) { } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Project.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate.Events; using NimblePros.SampleToDo.Core.ProjectAggregate.Events; namespace NimblePros.SampleToDo.Core.ProjectAggregate; public class Project : EntityBase, IAggregateRoot { public ProjectName Name { get; private set; } private readonly List _items = []; public IEnumerable Items => _items.AsReadOnly(); public ProjectStatus Status => _items.All(i => i.IsDone) ? ProjectStatus.Complete : ProjectStatus.InProgress; public Project(ProjectName name) { Name = name; } public Project AddItem(ToDoItem newItem) { Guard.Against.Null(newItem); _items.Add(newItem); var newItemAddedEvent = new NewItemAddedEvent(this, newItem); base.RegisterDomainEvent(newItemAddedEvent); return this; } public Project UpdateName(ProjectName newName) { if (Name.Equals(newName)) return this; Name = newName; return this; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ProjectErrorMessages.cs ================================================ // Core/ProjectAggregate/ProjectMessages.cs namespace NimblePros.SampleToDo.Core.ProjectAggregate; /// /// Strongly-typed, localisable message accessors for the Project aggregate. /// The implementation is deliberately **static** so it can be called from Vogen’s /// static Validate method. /// public static class ProjectErrorMessages { // ----------------------------------------------------------------- // 1. Public entry points – these are what you call from the domain // ----------------------------------------------------------------- public static string CoreProjectNameEmpty => Get(nameof(CoreProjectNameEmpty)); public static string CoreProjectNameTooLong(int maxLength) => Get(nameof(CoreProjectNameTooLong), maxLength); public static string CoreToDoItemDescriptionEmpty => Get(nameof(CoreToDoItemDescriptionEmpty)); public static string CoreToDoItemDescriptionTooLong(int maxLength) => Get(nameof(CoreToDoItemDescriptionTooLong), maxLength); public static string CoreToDoItemTitleEmpty => Get(nameof(CoreToDoItemTitleEmpty)); public static string CoreToDoItemTitleTooLong(int maxLength) => Get(nameof(CoreToDoItemTitleTooLong), maxLength); // ----------------------------------------------------------------- // 2. Private helper that forwards to the current localizer // ----------------------------------------------------------------- private static string Get(string key, params object[] args) { // The static holder is set once in Program.cs (Web project) var localizer = Localization.Current?.Localizer; if (localizer is not null) { // Uses the standard {0}, {1}… placeholders defined in JSON/RESX var localized = localizer[key, args]; return localized.ResourceNotFound ? Fallback(key, args) : localized; } // No DI container available (e.g. unit-tests) → fallback to English return Fallback(key, args); } // ----------------------------------------------------------------- // 3. Hard-coded English fallback (never throws, always returns a string) // ----------------------------------------------------------------- private static string Fallback(string key, object[] args) => key switch { nameof(CoreProjectNameEmpty) => "Name cannot be empty", nameof(CoreProjectNameTooLong) => FormattableString.Invariant($"Name cannot be longer than {args[0]} characters"), nameof(CoreToDoItemDescriptionEmpty) => "Description cannot be empty", nameof(CoreToDoItemDescriptionTooLong) => FormattableString.Invariant($"Description cannot be longer than {args[0]} characters"), nameof(CoreToDoItemTitleEmpty) => "Title cannot be empty", nameof(CoreToDoItemTitleTooLong) => FormattableString.Invariant($"Title cannot be longer than {args[0]} characters"), _ => $"[{key}]" }; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ProjectId.cs ================================================ using Vogen; namespace NimblePros.SampleToDo.Core.ProjectAggregate; [ValueObject] public partial struct ProjectId; ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ProjectName.cs ================================================ using Vogen; [assembly: VogenDefaults( staticAbstractsGeneration: StaticAbstractsGeneration.MostCommon | StaticAbstractsGeneration.InstanceMethodsAndProperties)] namespace NimblePros.SampleToDo.Core.ProjectAggregate; // NOTE: Structs do not require conversion to work with EF Core [ValueObject(conversions: Conversions.SystemTextJson)] public partial struct ProjectName { public const int MaxLength = 100; private static Validation Validate(in string name) => string.IsNullOrEmpty(name) ? Validation.Invalid(ProjectErrorMessages.CoreProjectNameEmpty) : name.Length > MaxLength ? Validation.Invalid(ProjectErrorMessages.CoreProjectNameTooLong(MaxLength)) : Validation.Ok; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ProjectStatus.cs ================================================ namespace NimblePros.SampleToDo.Core.ProjectAggregate; public enum ProjectStatus { InProgress, // NOTE: Better to use a SmartEnum if you want spaces in your strings e.g. "In Progress" Complete } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/IncompleteItemsSearchSpec.cs ================================================ namespace NimblePros.SampleToDo.Core.ProjectAggregate.Specifications; public class IncompleteItemsSearchSpec : Specification { public IncompleteItemsSearchSpec(string searchString) { Query .Where(item => !item.IsDone && (item.Title.Value.Contains(searchString) || item.Description.Value.Contains(searchString))); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/IncompleteItemsSpec.cs ================================================ namespace NimblePros.SampleToDo.Core.ProjectAggregate.Specifications; public class IncompleteItemsSpec : Specification { public IncompleteItemsSpec() { Query.Where(item => !item.IsDone); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/ProjectByIdWithItemsSpec.cs ================================================ namespace NimblePros.SampleToDo.Core.ProjectAggregate.Specifications; public class ProjectByIdWithItemsSpec : Specification { public ProjectByIdWithItemsSpec(ProjectId projectId) { Query .Where(project => project.Id == projectId) .Include(project => project.Items); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Specifications/ProjectsWithItemsByContributorId.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; namespace NimblePros.SampleToDo.Core.ProjectAggregate.Specifications; public class ProjectsWithItemsByContributorIdSpec : Specification { public ProjectsWithItemsByContributorIdSpec(ContributorId contributorId) { Query .Where(project => project.Items.Any(item => item.ContributorId == contributorId)) .Include(project => project.Items); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItem.cs ================================================ using System.Xml.Linq; using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate.Events; namespace NimblePros.SampleToDo.Core.ProjectAggregate; public class ToDoItem : EntityBase { public ToDoItem() : this(Priority.Backlog) { } public ToDoItem(ToDoItemTitle title, ToDoItemDescription description) : this(Priority.Backlog) { Title = title; Description = description; } public ToDoItem(Priority priority) { Priority = priority; } public ToDoItemTitle Title { get; private set; } public ToDoItemDescription Description { get; private set; } public ContributorId? ContributorId { get; private set; } // tasks don't have anyone assigned when first created public bool IsDone { get; private set; } public Priority Priority { get; private set; } public ToDoItem MarkComplete() { if (!IsDone) { IsDone = true; RegisterDomainEvent(new ToDoItemCompletedEvent(this)); } return this; } public ToDoItem AddContributor(ContributorId contributorId) { Guard.Against.Null(contributorId); ContributorId = contributorId; var contributorAddedToItem = new ContributorAddedToItemEvent(this, contributorId); base.RegisterDomainEvent(contributorAddedToItem); return this; } public ToDoItem RemoveContributor() { ContributorId = null; return this; } public ToDoItem UpdateTitle(ToDoItemTitle newTitle) { if (Title.Equals(newTitle)) return this; Title = newTitle; return this; } public ToDoItem UpdateDescription(ToDoItemDescription newDescription) { if (Description.Equals(newDescription)) return this; Description = newDescription; return this; } public override string ToString() { string status = IsDone ? "Done!" : "Not done."; return $"{Id}: Status: {status} - {Title.Value} - Priority: {Priority}"; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItemDescription.cs ================================================ using Vogen; namespace NimblePros.SampleToDo.Core.ProjectAggregate; [ValueObject(conversions: Conversions.SystemTextJson)] public partial struct ToDoItemDescription { public const int MaxLength = 200; private static Validation Validate(in string description) => string.IsNullOrEmpty(description) ? Validation.Invalid(ProjectErrorMessages.CoreToDoItemDescriptionEmpty) : description.Length > MaxLength ? Validation.Invalid(ProjectErrorMessages.CoreToDoItemDescriptionTooLong(MaxLength)) : Validation.Ok; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItemId.cs ================================================ using Vogen; namespace NimblePros.SampleToDo.Core.ProjectAggregate; [ValueObject] public partial struct ToDoItemId; ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/ToDoItemTitle.cs ================================================ using Vogen; namespace NimblePros.SampleToDo.Core.ProjectAggregate; [ValueObject(conversions: Conversions.SystemTextJson)] public partial struct ToDoItemTitle { public const int MaxLength = 100; private static Validation Validate(in string title) => string.IsNullOrEmpty(title) ? Validation.Invalid(ProjectErrorMessages.CoreToDoItemTitleEmpty) : title.Length > MaxLength ? Validation.Invalid(ProjectErrorMessages.CoreToDoItemTitleTooLong(MaxLength)) : Validation.Ok; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/Services/DeleteContributorService.cs ================================================ using Microsoft.Extensions.Logging; using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Core.ContributorAggregate.Events; using NimblePros.SampleToDo.Core.Interfaces; namespace NimblePros.SampleToDo.Core.Services; public class DeleteContributorService : IDeleteContributorService { private readonly IRepository _repository; private readonly IMediator _mediator; private readonly ILogger _logger; public DeleteContributorService(IRepository repository, IMediator mediator, ILogger logger) { _repository = repository; _mediator = mediator; _logger = logger; } public async Task DeleteContributor(ContributorId contributorId) { _logger.LogInformation("Deleting Contributor {contributorId}", contributorId); var aggregateToDelete = await _repository.GetByIdAsync(contributorId); if (aggregateToDelete == null) return Result.NotFound(); await _repository.DeleteAsync(aggregateToDelete); var domainEvent = new ContributorDeletedEvent(contributorId); await _mediator.Publish(domainEvent); return Result.Success(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Core/Services/ToDoItemSearchService.cs ================================================ using NimblePros.SampleToDo.Core.Interfaces; using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate.Specifications; namespace NimblePros.SampleToDo.Core.Services; public class ToDoItemSearchService : IToDoItemSearchService { private readonly IRepository _repository; public ToDoItemSearchService(IRepository repository) { _repository = repository; } public async Task>> GetAllIncompleteItemsAsync(ProjectId projectId, string searchString) { if (string.IsNullOrEmpty(searchString)) { var errors = new List { new() { Identifier = nameof(searchString), ErrorMessage = $"{nameof(searchString)} is required." } }; return Result>.Invalid(errors); } var projectSpec = new ProjectByIdWithItemsSpec(projectId); var project = await _repository.FirstOrDefaultAsync(projectSpec); // TODO: Optionally use Ardalis.GuardClauses Guard.Against.NotFound and catch if (project == null) { return Result>.NotFound(); } var incompleteSpec = new IncompleteItemsSearchSpec(searchString); try { var items = incompleteSpec.Evaluate(project.Items).ToList(); return new Result>(items); } catch (Exception ex) { // TODO: Log details here return Result>.Error( ex.Message ); } } public async Task> GetNextIncompleteItemAsync(ProjectId projectId) { var projectSpec = new ProjectByIdWithItemsSpec(projectId); var project = await _repository.FirstOrDefaultAsync(projectSpec); if (project == null) { return Result.NotFound(); } var incompleteSpec = new IncompleteItemsSpec(); var items = incompleteSpec.Evaluate(project.Items).ToList(); if (!items.Any()) { return Result.NotFound(); } return new Result(items.First()); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/AppDbContext.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.Infrastructure.Data; public class AppDbContext : DbContext { public AppDbContext(DbContextOptions options) : base(options) {} public DbSet ToDoItems => Set(); public DbSet Projects => Set(); public DbSet Contributors => Set(); protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); } protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { base.ConfigureConventions(configurationBuilder); //configurationBuilder.RegisterAllInVogenEfCoreConverters(); } public override int SaveChanges() { return SaveChangesAsync().GetAwaiter().GetResult(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/ContributorConfiguration.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; namespace NimblePros.SampleToDo.Infrastructure.Data.Config; public class ContributorConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.Property(entity => entity.Id) .HasValueGenerator>() .HasVogenConversion() .IsRequired(); builder.Property(entity => entity.Name) .HasVogenConversion() .HasMaxLength(ContributorName.MaxLength) .IsRequired(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/DataSchemaConstants.cs ================================================ namespace NimblePros.SampleToDo.Infrastructure.Data.Config; public static class DataSchemaConstants { public const int DEFAULT_NAME_LENGTH = 100; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/ProjectConfiguration.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.Infrastructure.Data.Config; public class ProjectConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.Property(p => p.Id) .HasValueGenerator>() .HasVogenConversion() .IsRequired(); builder.Property(p => p.Name) .HasVogenConversion() .HasMaxLength(ProjectName.MaxLength) .IsRequired(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/ToDoItemConfiguration.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.Infrastructure.Data.Config; public class ToDoItemConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { builder.Property(p => p.Id) .HasValueGenerator>() .HasVogenConversion() .IsRequired(); builder.Property(p => p.Title) .HasVogenConversion() .HasMaxLength(ToDoItemTitle.MaxLength) .IsRequired(); builder.Property(p => p.Description) .HasVogenConversion() .HasMaxLength(ToDoItemDescription.MaxLength) .IsRequired(); builder.Property(t => t.ContributorId) .HasConversion( v => v.HasValue ? v.Value.Value : (int?)null, // to db v => v.HasValue ? ContributorId.From(v.Value) : (ContributorId?)null // from db ) .IsRequired(false); builder.Property(t => t.Priority) .HasConversion( p => p.Value, p => Priority.FromValue(p)); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/VogenEfCoreConverters.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate; using Vogen; namespace NimblePros.SampleToDo.Infrastructure.Data.Config; [EfCoreConverter] [EfCoreConverter] [EfCoreConverter] [EfCoreConverter] [EfCoreConverter] [EfCoreConverter] [EfCoreConverter] internal partial class VogenEfCoreConverters; ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config/VogenIdValueGenerator.cs ================================================ using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.ValueGeneration; using NimblePros.SharedKernel; namespace NimblePros.SampleToDo.Infrastructure.Data.Config; internal class VogenIdValueGenerator : ValueGenerator where TContext : DbContext where TEntityBase : EntityBase where TId : IVogen { private readonly PropertyInfo _matchPropertyGetter; public VogenIdValueGenerator() { var matchingProperties = typeof(TContext).GetProperties().Where(p => p!.GetGetMethod()!.IsPublic && p.PropertyType == typeof(DbSet)).ToList(); if (matchingProperties.Count == 0) { throw new InvalidOperationException($"No properties found in the EFCore context for a DBSet of {nameof(TEntityBase)}"); } if (matchingProperties.Count > 1) { throw new InvalidOperationException($"Multiple properties found in the EFCore context for a DBSet of {nameof(TEntityBase)}"); } _matchPropertyGetter = matchingProperties[0]; } public override TId Next(EntityEntry entry) { TContext ctx = (TContext)entry.Context; DbSet entities = (DbSet)_matchPropertyGetter!.GetValue(ctx)!; var next = Math.Max( MaxFrom(entities.Local), MaxFrom(entities)) + 1; return TId.From(next); static int MaxFrom(IEnumerable es) => es.Any() ? es.Max(e => e.Id.Value) : 0; } public override bool GeneratesTemporaryValues => false; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/EfRepository.cs ================================================ using NimblePros.SharedKernel; namespace NimblePros.SampleToDo.Infrastructure.Data; // inherit from Ardalis.Specification type public class EfRepository : RepositoryBase, IReadRepository, IRepository where T : class, IAggregateRoot { public EfRepository(AppDbContext dbContext) : base(dbContext) { } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/EventDispatchInterceptor.cs ================================================ using Microsoft.EntityFrameworkCore.Diagnostics; using NimblePros.SharedKernel; namespace NimblePros.SampleToDo.Infrastructure.Data; // Intercepts SaveChanges to dispatch domain events after changes are successfully saved public class EventDispatchInterceptor(IDomainEventDispatcher domainEventDispatcher) : SaveChangesInterceptor { private readonly IDomainEventDispatcher _domainEventDispatcher = domainEventDispatcher; // Called after SaveChangesAsync has completed successfully public override async ValueTask SavedChangesAsync(SaveChangesCompletedEventData eventData, int result, CancellationToken cancellationToken = new CancellationToken()) { var context = eventData.Context; if (context is not AppDbContext appDbContext) { return await base.SavedChangesAsync(eventData, result, cancellationToken).ConfigureAwait(false); } // Retrieve all tracked entities that have domain events var entitiesWithEvents = appDbContext.ChangeTracker.Entries() .Select(e => e.Entity) .Where(e => e.DomainEvents.Any()) .ToArray(); // Dispatch and clear domain events await _domainEventDispatcher.DispatchAndClearEvents(entitiesWithEvents); return await base.SavedChangesAsync(eventData, result, cancellationToken); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/FakeListContributorsQueryService.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.UseCases; using NimblePros.SampleToDo.UseCases.Contributors; using NimblePros.SampleToDo.UseCases.Contributors.Queries.List; namespace NimblePros.SampleToDo.Infrastructure.Data.Queries; public class FakeListContributorsQueryService : IListContributorsQueryService { public Task> ListAsync(int page, int perPage) { var items = new List(); for (int i = 1; i <= 25; i++) { items.Add(new ContributorDto(ContributorId.From(i), ContributorName.From($"Fake {i}"))); }; int totalPages = (int)Math.Ceiling(items.Count / (double)perPage); var result = new PagedResult(items, page, perPage, items.Count, totalPages); return Task.FromResult(result); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/FakeListIncompleteItemsQueryService.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.UseCases.Projects; using NimblePros.SampleToDo.UseCases.Projects.ListIncompleteItems; namespace NimblePros.SampleToDo.Infrastructure.Data.Queries; public class FakeListIncompleteItemsQueryService : IListIncompleteItemsQueryService { public async Task> ListAsync(int projectId) { var testItem = new ToDoItemDto(Id: ToDoItemId.From(1000), Title: "test", Description: "test description", IsComplete: false, null); return await Task.FromResult(new List() { testItem}); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/FakeListProjectsShallowQueryService.cs ================================================ using NimblePros.SampleToDo.UseCases.Projects; using NimblePros.SampleToDo.UseCases.Projects.ListShallow; namespace NimblePros.SampleToDo.Infrastructure.Data.Queries; public class FakeListProjectsShallowQueryService : IListProjectsShallowQueryService { public async Task> ListAsync() { var testProject = new ProjectDto(1000, "Test Project", "InProgress"); return await Task.FromResult(new List { testProject }); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/ListContributorsQueryService.cs ================================================ using NimblePros.SampleToDo.UseCases; using NimblePros.SampleToDo.UseCases.Contributors; using NimblePros.SampleToDo.UseCases.Contributors.Queries.List; namespace NimblePros.SampleToDo.Infrastructure.Data.Queries; public class ListContributorsQueryService : IListContributorsQueryService { // You can use EF, Dapper, SqlClient, etc. for queries private readonly AppDbContext _db; public ListContributorsQueryService(AppDbContext db) { _db = db; } public async Task> ListAsync(int page, int perPage) { var items = await _db.Contributors.FromSqlRaw("SELECT Id, Name FROM Contributors") // don't fetch other big columns .OrderBy(c => c.Id) .Skip((page - 1) * perPage) .Take(perPage) .Select(c => new ContributorDto(c.Id, c.Name)) .ToListAsync(); int totalCount = await _db.Contributors.CountAsync(); int totalPages = (int)Math.Ceiling(totalCount / (double)perPage); var result = new PagedResult(items, page, perPage, totalCount, totalPages); return result; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/ListIncompleteItemsQueryService.cs ================================================ using NimblePros.SampleToDo.UseCases.Projects; using NimblePros.SampleToDo.UseCases.Projects.ListIncompleteItems; namespace NimblePros.SampleToDo.Infrastructure.Data.Queries; public class ListIncompleteItemsQueryService : IListIncompleteItemsQueryService { private readonly AppDbContext _db; public ListIncompleteItemsQueryService(AppDbContext db) { _db = db; } public async Task> ListAsync(int projectId) { var projectParameter = new SqlParameter("@projectId", System.Data.SqlDbType.Int); var result = await _db.ToDoItems.FromSqlRaw("SELECT Id, Title, Description, IsDone, ContributorId FROM ToDoItems WHERE ProjectId = @ProjectId", projectParameter) // don't fetch other big columns .Select(x => new ToDoItemDto(x.Id, x.Title.Value, x.Description.Value, x.IsDone, x.ContributorId)) .ToListAsync(); return result; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries/ListProjectsShallowQueryService.cs ================================================ using NimblePros.SampleToDo.UseCases.Projects; using NimblePros.SampleToDo.UseCases.Projects.ListShallow; namespace NimblePros.SampleToDo.Infrastructure.Data.Queries; public class ListProjectsShallowQueryService(AppDbContext db) : IListProjectsShallowQueryService { private readonly AppDbContext _db = db; public async Task> ListAsync() { var result = await _db.Projects.FromSqlRaw("SELECT Id, Name FROM Projects") // don't fetch other big columns .Select(x => new ProjectDto(x.Id.Value, x.Name.Value, x.Status.ToString())) .ToListAsync(); return result; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Email/FakeEmailSender.cs ================================================ using NimblePros.SampleToDo.Core.Interfaces; namespace NimblePros.SampleToDo.Infrastructure.Email; public class FakeEmailSender : IEmailSender { private readonly ILogger _logger; public FakeEmailSender(ILogger logger) { _logger = logger; } public Task SendEmailAsync(string to, string from, string subject, string body) { _logger.LogInformation("Not actually sending an email to {to} from {from} with subject {subject}", to, from, subject); return Task.CompletedTask; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Email/MailserverConfiguration.cs ================================================ namespace NimblePros.SampleToDo.Infrastructure.Email; public class MailserverConfiguration() { public const string SectionName = "Mailserver"; public string Hostname { get; set; } = "localhost"; public int Port { get; set; } = 25; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Email/MimeKitEmailSender.cs ================================================ using Microsoft.Extensions.Options; using MimeKit; using NimblePros.SampleToDo.Core.Interfaces; namespace NimblePros.SampleToDo.Infrastructure.Email; public class MimeKitEmailSender(ILogger logger, IOptions mailserverOptions) : IEmailSender { private readonly ILogger _logger = logger; private readonly MailserverConfiguration _mailserverConfiguration = mailserverOptions.Value!; public async Task SendEmailAsync(string to, string from, string subject, string body) { _logger.LogWarning("Sending email to {to} from {from} with subject {subject} using {type}.", to, from, subject, ToString()); try { using var client = new MailKit.Net.Smtp.SmtpClient(); await client.ConnectAsync(_mailserverConfiguration.Hostname, _mailserverConfiguration.Port, false); var message = new MimeMessage(); message.From.Add(new MailboxAddress(from, from)); message.To.Add(new MailboxAddress(to, to)); message.Subject = subject; message.Body = new TextPart("plain") { Text = body }; await client.SendAsync(message); await client.DisconnectAsync(true, new CancellationToken(canceled: true)); } catch (Exception ex) { _logger.LogWarning("Run Papercut docker image: "); _logger.LogWarning("docker run --name=papercut -p 25:25 -p 37408:37408 jijiechen/papercut:latest"); _logger.LogError(ex, "Error sending email"); throw; } } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/Email/SmtpEmailSender.cs ================================================ using NimblePros.SampleToDo.Core.Interfaces; namespace NimblePros.SampleToDo.Infrastructure.Email; [Obsolete("Use MimeKitEmailSender instead")] public class SmtpEmailSender : IEmailSender { private readonly ILogger _logger; public SmtpEmailSender(ILogger logger) { _logger = logger; } public async Task SendEmailAsync(string to, string from, string subject, string body) { var emailClient = new SmtpClient("localhost"); var message = new MailMessage { From = new MailAddress(from), Subject = subject, Body = body }; message.To.Add(new MailAddress(to)); await emailClient.SendMailAsync(message); _logger.LogWarning("Sending email to {to} from {from} with subject {subject}.", to, from, subject); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/GlobalUsings.cs ================================================ global using System.Net.Mail; global using System.Reflection; global using Ardalis.Specification.EntityFrameworkCore; global using Microsoft.Data.SqlClient; global using Microsoft.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore.Metadata.Builders; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.Logging; ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/InfrastructureServiceExtensions.cs ================================================ using Microsoft.Extensions.Configuration; using NimblePros.Metronome; using NimblePros.SampleToDo.Core.Interfaces; using NimblePros.SampleToDo.Infrastructure.Data; using NimblePros.SampleToDo.Infrastructure.Data.Queries; using NimblePros.SampleToDo.Infrastructure.Email; using NimblePros.SampleToDo.UseCases.Contributors.Queries.List; using NimblePros.SampleToDo.UseCases.Projects.ListIncompleteItems; using NimblePros.SampleToDo.UseCases.Projects.ListShallow; using NimblePros.SharedKernel; namespace NimblePros.SampleToDo.Infrastructure; public static class InfrastructureServiceExtensions { public static IServiceCollection AddInfrastructureServices( this IServiceCollection services, IConfiguration configuration, ILogger logger, string environmentName) { if (environmentName == "Development") { RegisterDevelopmentOnlyDependencies(services, configuration); } else if (environmentName == "Testing") { RegisterTestingOnlyDependencies(services); } else { RegisterProductionOnlyDependencies(services, configuration); } RegisterEFRepositories(services); logger.LogInformation("{Project} services registered", "Infrastructure"); return services; } private static void AddDbContextWithSqlite(IServiceCollection services, IConfiguration configuration) { services.AddScoped(); services.AddScoped(); var connectionString = configuration.GetConnectionString("SqliteConnection"); services.AddDbContext((provider, options) => { options.UseSqlite(connectionString) .AddMetronomeDbTracking(provider) .AddInterceptors(provider.GetRequiredService()); }); } private static void RegisterDevelopmentOnlyDependencies(IServiceCollection services, IConfiguration configuration) { AddDbContextWithSqlite(services, configuration); services.AddScoped(); // to demo with a localhost test email server like Papercut services.AddScoped(); services.AddScoped(); services.AddScoped(); } private static void RegisterTestingOnlyDependencies(IServiceCollection services) { // do not configure a DbContext here for testing - it's configured in CustomWebApplicationFactory services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); } private static void RegisterProductionOnlyDependencies(IServiceCollection services, IConfiguration configuration) { AddDbContextWithSqlite(services, configuration); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); } private static void RegisterEFRepositories(IServiceCollection services) { services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>)); services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>)); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Infrastructure/NimblePros.SampleToDo.Infrastructure.csproj ================================================  ================================================ FILE: sample/src/NimblePros.SampleToDo.ServiceDefaults/Extensions.cs ================================================ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.ServiceDiscovery; using OpenTelemetry; using OpenTelemetry.Metrics; using OpenTelemetry.Trace; namespace Microsoft.Extensions.Hosting; // Adds common Aspire services: service discovery, resilience, health checks, and OpenTelemetry. // This project should be referenced by each service project in your solution. // To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults public static class Extensions { private const string HealthEndpointPath = "/health"; private const string AlivenessEndpointPath = "/alive"; public static TBuilder AddServiceDefaults(this TBuilder builder) where TBuilder : IHostApplicationBuilder { builder.ConfigureOpenTelemetry(); builder.AddDefaultHealthChecks(); builder.Services.AddServiceDiscovery(); builder.Services.ConfigureHttpClientDefaults(http => { // Turn on resilience by default http.AddStandardResilienceHandler(); // Turn on service discovery by default http.AddServiceDiscovery(); }); // Uncomment the following to restrict the allowed schemes for service discovery. // builder.Services.Configure(options => // { // options.AllowedSchemes = ["https"]; // }); return builder; } public static TBuilder ConfigureOpenTelemetry(this TBuilder builder) where TBuilder : IHostApplicationBuilder { builder.Logging.AddOpenTelemetry(logging => { logging.IncludeFormattedMessage = true; logging.IncludeScopes = true; }); builder.Services.AddOpenTelemetry() .WithMetrics(metrics => { metrics.AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddRuntimeInstrumentation(); }) .WithTracing(tracing => { tracing.AddSource(builder.Environment.ApplicationName) .AddAspNetCoreInstrumentation(tracing => // Exclude health check requests from tracing tracing.Filter = context => !context.Request.Path.StartsWithSegments(HealthEndpointPath) && !context.Request.Path.StartsWithSegments(AlivenessEndpointPath) ) // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) //.AddGrpcClientInstrumentation() .AddHttpClientInstrumentation(); }); builder.AddOpenTelemetryExporters(); return builder; } private static TBuilder AddOpenTelemetryExporters(this TBuilder builder) where TBuilder : IHostApplicationBuilder { var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); if (useOtlpExporter) { builder.Services.AddOpenTelemetry().UseOtlpExporter(); } // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) //{ // builder.Services.AddOpenTelemetry() // .UseAzureMonitor(); //} return builder; } public static TBuilder AddDefaultHealthChecks(this TBuilder builder) where TBuilder : IHostApplicationBuilder { builder.Services.AddHealthChecks() // Add a default liveness check to ensure app is responsive .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); return builder; } public static WebApplication MapDefaultEndpoints(this WebApplication app) { // Adding health checks endpoints to applications in non-development environments has security implications. // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. if (app.Environment.IsDevelopment()) { // All health checks must pass for app to be considered ready to accept traffic after starting app.MapHealthChecks(HealthEndpointPath); // Only health checks tagged with the "live" tag must pass for app to be considered alive app.MapHealthChecks(AlivenessEndpointPath, new HealthCheckOptions { Predicate = r => r.Tags.Contains("live") }); } return app; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.ServiceDefaults/NimblePros.SampleToDo.ServiceDefaults.csproj ================================================ true ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Constants.cs ================================================ namespace NimblePros.SampleToDo.UseCases; public class Constants { public const int DEFAULT_PAGE_SIZE = 10; public const int MAX_PAGE_SIZE = 100; } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Create/CreateContributorCommand.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; namespace NimblePros.SampleToDo.UseCases.Contributors.Commands.Create; /// /// Create a new Contributor. /// /// public record CreateContributorCommand(ContributorName Name) : Mediator.ICommand>; ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Create/CreateContributorHandler.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; namespace NimblePros.SampleToDo.UseCases.Contributors.Commands.Create; public class CreateContributorHandler(IRepository repository) : ICommandHandler> { private readonly IRepository _repository = repository; public async ValueTask> Handle(CreateContributorCommand command, CancellationToken cancellationToken) { var newContributor = new Contributor(command.Name); var createdItem = await _repository.AddAsync(newContributor, cancellationToken); return createdItem.Id.Value; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Delete/DeleteContributorCommand.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; namespace NimblePros.SampleToDo.UseCases.Contributors.Commands.Delete; public record DeleteContributorCommand(ContributorId ContributorId) : ICommand; ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Delete/DeleteContributorHandler.cs ================================================ using NimblePros.SampleToDo.Core.Interfaces; namespace NimblePros.SampleToDo.UseCases.Contributors.Commands.Delete; public class DeleteContributorHandler : ICommandHandler { private readonly IDeleteContributorService _deleteContributorService; public DeleteContributorHandler(IDeleteContributorService deleteContributorService) { _deleteContributorService = deleteContributorService; } public async ValueTask Handle(DeleteContributorCommand request, CancellationToken cancellationToken) { // This Approach: Keep Domain Events in the Domain Model / Core project; this becomes a pass-through return await _deleteContributorService.DeleteContributor(request.ContributorId); // Another Approach: Do the real work here including dispatching domain events - change the event from internal to public // Ardalis prefers using the service so that "domain event" behavior remains in the domain model / core project // var aggregateToDelete = await _repository.GetByIdAsync(request.ContributorId); // if (aggregateToDelete == null) return Result.NotFound(); // await _repository.DeleteAsync(aggregateToDelete); // var domainEvent = new ContributorDeletedEvent(request.ContributorId); // await _mediator.Publish(domainEvent); // return Result.Success(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Update/UpdateContributorCommand.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; namespace NimblePros.SampleToDo.UseCases.Contributors.Commands.Update; public record UpdateContributorCommand(ContributorId ContributorId, ContributorName NewName) : ICommand>; ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Commands/Update/UpdateContributorHandler.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Core.ContributorAggregate.Specifications; namespace NimblePros.SampleToDo.UseCases.Contributors.Commands.Update; public class UpdateContributorHandler : ICommandHandler> { private readonly IRepository _repository; public UpdateContributorHandler(IRepository repository) { _repository = repository; } public async ValueTask> Handle(UpdateContributorCommand request, CancellationToken cancellationToken) { var spec = new ContributorByIdSpec(request.ContributorId); var existingContributor = await _repository.SingleOrDefaultAsync(spec, cancellationToken); if (existingContributor == null) { return Result.NotFound(); } existingContributor.UpdateName(request.NewName!); await _repository.UpdateAsync(existingContributor, cancellationToken); return Result.Success(new ContributorDto(existingContributor.Id, existingContributor.Name)); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/ContributorDTO.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; namespace NimblePros.SampleToDo.UseCases.Contributors; public record ContributorDto(ContributorId Id, ContributorName Name); ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Queries/Get/GetContributorHandler.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Core.ContributorAggregate.Specifications; namespace NimblePros.SampleToDo.UseCases.Contributors.Queries.Get; /// /// Queries don't necessarily need to use repository methods, but they can if it's convenient /// public class GetContributorHandler(IReadRepository repository) : IQueryHandler> { private readonly IReadRepository _repository = repository; public async ValueTask> Handle(GetContributorQuery request, CancellationToken cancellationToken) { var spec = new ContributorByIdSpec(request.ContributorId); var entity = await _repository.FirstOrDefaultAsync(spec, cancellationToken); if (entity == null) return Result.NotFound(); return new ContributorDto(entity.Id, entity.Name); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Queries/Get/GetContributorQuery.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; namespace NimblePros.SampleToDo.UseCases.Contributors.Queries.Get; public record GetContributorQuery(ContributorId ContributorId) : IQuery>, ICacheable { public string? CacheProfile => null; public string GetCacheKey() { return $"{nameof(GetContributorQuery)}-{ContributorId.Value}"; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Queries/List/IListContributorsQueryService.cs ================================================ namespace NimblePros.SampleToDo.UseCases.Contributors.Queries.List; /// /// Represents a service that will actually fetch the necessary data /// Typically implemented in Infrastructure /// public interface IListContributorsQueryService { Task> ListAsync(int page, int perPage); } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Queries/List/ListContributorsHandler.cs ================================================ namespace NimblePros.SampleToDo.UseCases.Contributors.Queries.List; public class ListContributorsHandler : IQueryHandler>> { private readonly IListContributorsQueryService _query; public ListContributorsHandler(IListContributorsQueryService query) { _query = query; } public async ValueTask>> Handle(ListContributorsQuery request, CancellationToken cancellationToken) { var result = await _query.ListAsync(request.Page ?? 1, request.PerPage ?? Constants.DEFAULT_PAGE_SIZE); return Result.Success(result); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Contributors/Queries/List/ListContributorsQuery.cs ================================================ namespace NimblePros.SampleToDo.UseCases.Contributors.Queries.List; public record ListContributorsQuery(int? Page = 1, int? PerPage = Constants.DEFAULT_PAGE_SIZE) : IQuery>>, ICacheable { public string? CacheProfile => "Long"; public string GetCacheKey() { return $"{nameof(ListContributorsQuery)}-{Page}-{PerPage}"; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/GlobalUsings.cs ================================================ global using Ardalis.Result; global using Mediator; global using NimblePros.SharedKernel; ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/ICacheable.cs ================================================ namespace NimblePros.SampleToDo.UseCases; public interface ICacheable { string GetCacheKey(); string? CacheProfile { get; } // TODO: Use SmartEnum for this with CacheProfile.None } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/NimblePros.SampleToDo.UseCases.csproj ================================================  ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/PagedResult.cs ================================================ namespace NimblePros.SampleToDo.UseCases; public record PagedResult( IReadOnlyList Items, int Page, int PerPage, int TotalCount, int TotalPages); ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/AddToDoItem/AddToDoItemCommand.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.UseCases.Projects.AddToDoItem; /// /// Creates a new ToDoItem and adds it to a Project /// /// /// /// /// public record AddToDoItemCommand(ProjectId ProjectId, ContributorId? ContributorId, ToDoItemTitle Title, ToDoItemDescription Description) : ICommand>; ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/AddToDoItem/AddToDoItemHandler.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate.Specifications; namespace NimblePros.SampleToDo.UseCases.Projects.AddToDoItem; public class AddToDoItemHandler : ICommandHandler> { private readonly IRepository _repository; public AddToDoItemHandler(IRepository repository) { _repository = repository; } public async ValueTask> Handle(AddToDoItemCommand request, CancellationToken cancellationToken) { var spec = new ProjectByIdWithItemsSpec(request.ProjectId); var entity = await _repository.FirstOrDefaultAsync(spec, cancellationToken); if (entity == null) { return Result.NotFound(); } var newItem = new ToDoItem(title: request.Title!, description: request.Description!); if (request.ContributorId.HasValue) { newItem.AddContributor(request.ContributorId.Value); } entity.AddItem(newItem); await _repository.UpdateAsync(entity); return Result.Success(newItem.Id); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Create/CreateProjectCommand.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.UseCases.Projects.Create; /// /// Create a new Project. /// /// public record CreateProjectCommand(ProjectName Name) : ICommand>; ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Create/CreateProjectHandler.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.UseCases.Projects.Create; public class CreateProjectHandler(IRepository repository) : ICommandHandler> { private readonly IRepository _repository = repository; public async ValueTask> Handle(CreateProjectCommand request, CancellationToken cancellationToken) { var newProject = new Project(request.Name); // NOTE: This implementation issues 3 queries due to Vogen implementation var createdItem = await _repository.AddAsync(newProject, cancellationToken); return createdItem.Id; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Delete/DeleteProjectCommand.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.UseCases.Projects.Delete; public record DeleteProjectCommand(ProjectId ProjectId) : ICommand; ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Delete/DeleteProjectHandler.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.UseCases.Projects.Delete; public class DeleteProjectHandler : ICommandHandler { private readonly IRepository _repository; public DeleteProjectHandler(IRepository repository) { _repository = repository; } public async ValueTask Handle(DeleteProjectCommand request, CancellationToken cancellationToken) { var aggregateToDelete = await _repository.GetByIdAsync(request.ProjectId, cancellationToken); if (aggregateToDelete == null) { return Result.NotFound(); } await _repository.DeleteAsync(aggregateToDelete, cancellationToken); return Result.Success(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/GetWithAllItems/GetProjectWithAllItemsHandler.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate.Specifications; namespace NimblePros.SampleToDo.UseCases.Projects.GetWithAllItems; /// /// Queries don't necessarily need to use repository methods, but they can if it's convenient /// public class GetProjectWithAllItemsHandler : IQueryHandler> { private readonly IReadRepository _repository; public GetProjectWithAllItemsHandler(IReadRepository repository) { _repository = repository; } public async ValueTask> Handle(GetProjectWithAllItemsQuery request, CancellationToken cancellationToken) { var spec = new ProjectByIdWithItemsSpec(request.ProjectId); var project = await _repository.FirstOrDefaultAsync(spec, cancellationToken); if (project == null) return Result.NotFound(); var items = project.Items .Select(i => new ToDoItemDto(i.Id, i.Title.Value, i.Description.Value, i.IsDone, i.ContributorId)).ToList(); return new ProjectWithAllItemsDto(project.Id, project.Name, items, project.Status.ToString()) ; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/GetWithAllItems/GetProjectWithAllItemsQuery.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.UseCases.Projects.GetWithAllItems; public record GetProjectWithAllItemsQuery(ProjectId ProjectId) : IQuery>, ICacheable { public string? CacheProfile => "Short"; public string GetCacheKey() { return $"{nameof(GetProjectWithAllItemsQuery)}-{ProjectId}"; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListIncompleteItems/IListIncompleteItemsQueryService.cs ================================================ namespace NimblePros.SampleToDo.UseCases.Projects.ListIncompleteItems; /// /// Represents a service that will actually fetch the necessary data /// Typically implemented in Infrastructure /// public interface IListIncompleteItemsQueryService { Task> ListAsync(int projectId); } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListIncompleteItems/ListIncompleteItemsByProjectHandler.cs ================================================ namespace NimblePros.SampleToDo.UseCases.Projects.ListIncompleteItems; public class ListIncompleteItemsByProjectHandler : IQueryHandler>> { private readonly IListIncompleteItemsQueryService _query; public ListIncompleteItemsByProjectHandler(IListIncompleteItemsQueryService query) { _query = query; } public async ValueTask>> Handle(ListIncompleteItemsByProjectQuery request, CancellationToken cancellationToken) { var result = await _query.ListAsync(request.ProjectId); return Result.Success(result); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListIncompleteItems/ListIncompleteItemsByProjectQuery.cs ================================================ namespace NimblePros.SampleToDo.UseCases.Projects.ListIncompleteItems; public record ListIncompleteItemsByProjectQuery(int ProjectId) : IQuery>>, ICacheable { public string? CacheProfile => null; public string GetCacheKey() { return $"{nameof(ListIncompleteItemsByProjectQuery)}-{ProjectId}"; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListShallow/IListProjectsShallowQueryService.cs ================================================ namespace NimblePros.SampleToDo.UseCases.Projects.ListShallow; /// /// Represents a service that will actually fetch the necessary data /// Typically implemented in Infrastructure /// public interface IListProjectsShallowQueryService { Task> ListAsync(); } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListShallow/ListProjectsShallowHandler.cs ================================================ namespace NimblePros.SampleToDo.UseCases.Projects.ListShallow; public class ListProjectsShallowHandler(IListProjectsShallowQueryService query) : IQueryHandler>> { private readonly IListProjectsShallowQueryService _query = query; public async ValueTask>> Handle(ListProjectsShallowQuery request, CancellationToken cancellationToken) { var result = await _query.ListAsync(); return Result.Success(result); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ListShallow/ListProjectsShallowQuery.cs ================================================ namespace NimblePros.SampleToDo.UseCases.Projects.ListShallow; public record ListProjectsShallowQuery(int? Skip, int? Take) : IQuery>>, ICacheable { public string? CacheProfile => null; public string GetCacheKey() { return $"{nameof(ListProjectsShallowQuery)}-{Skip}-{Take}"; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/MarkToDoItemComplete/MarkToDoItemCompleteCommand.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.UseCases.Projects.MarkToDoItemComplete; /// /// Create a new Project. /// /// public record MarkToDoItemCompleteCommand(ProjectId ProjectId, int ToDoItemId) : ICommand; ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/MarkToDoItemComplete/MarkToDoItemCompleteHandler.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate.Specifications; namespace NimblePros.SampleToDo.UseCases.Projects.MarkToDoItemComplete; public class MarkToDoItemCompleteHandler : ICommandHandler { private readonly IRepository _repository; public MarkToDoItemCompleteHandler(IRepository repository) { _repository = repository; } public async ValueTask Handle(MarkToDoItemCompleteCommand request, CancellationToken cancellationToken) { var spec = new ProjectByIdWithItemsSpec(request.ProjectId); var entity = await _repository.FirstOrDefaultAsync(spec, cancellationToken); if (entity == null) return Result.NotFound("Project not found."); var item = entity.Items.FirstOrDefault(i => i.Id == request.ToDoItemId); if (item == null) return Result.NotFound("Item not found."); item.MarkComplete(); await _repository.UpdateAsync(entity); return Result.Success(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ProjectDTO.cs ================================================ namespace NimblePros.SampleToDo.UseCases.Projects; public record ProjectDto(int Id, string Name, string Status); ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ProjectWithAllItemsDTO.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.UseCases.Projects; public record ProjectWithAllItemsDto(ProjectId Id, ProjectName Name, List Items, string Status); ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/ToDoItemDTO.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.UseCases.Projects; public record ToDoItemDto(ToDoItemId Id, string Title, string Description, bool IsComplete, ContributorId? ContributorId); ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Update/UpdateProjectCommand.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.UseCases.Projects.Update; public record UpdateProjectCommand(ProjectId ProjectId, ProjectName NewName) : ICommand>; ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/Projects/Update/UpdateProjectHandler.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.UseCases.Projects.Update; public class UpdateProjectHandler : ICommandHandler> { private readonly IRepository _repository; public UpdateProjectHandler(IRepository repository) { _repository = repository; } public async ValueTask> Handle(UpdateProjectCommand request, CancellationToken cancellationToken) { var existingEntity = await _repository.GetByIdAsync(request.ProjectId, cancellationToken); if (existingEntity == null) { return Result.NotFound(); } existingEntity.UpdateName(request.NewName!); await _repository.UpdateAsync(existingEntity, cancellationToken); return Result.Success(new ProjectDto(existingEntity.Id.Value, existingEntity.Name.Value, existingEntity.Status.ToString())); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.UseCases/README.md ================================================ ## Use Cases Project In Clean Architecture, the Use Cases (or Application Services) project is a relatively thin layer that wraps the domain model. Use Cases are typically organized by feature. These may be simple CRUD operations or much more complex activities. Use Cases should not depend directly on infrastructure concerns, making them simple to unit test in most cases. Use Cases are often grouped into Commands and Queries, following CQRS. Having Use Cases as a separate project can reduce the amount of logic in UI and Infrastructure projects. For simpler projects, the Use Cases project can be omitted, and its behavior moved into the UI project, either as using separate services or Mediator handlers, or by simply putting the logic into the API endpoints. ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/CachingBehavior.cs ================================================ using Ardalis.GuardClauses; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using NimblePros.SampleToDo.UseCases; using NimblePros.SampleToDo.Web.Configurations; namespace NimblePros.SampleToDo.Web; public class CachingBehavior(IMemoryCache cache, ILogger> logger, IOptions cachingOptions) : IPipelineBehavior where TRequest : notnull, IMessage { private readonly IMemoryCache _cache = cache; private readonly ILogger> _logger = logger; private readonly CachingOptions _cachingOptions = cachingOptions.Value; public async ValueTask Handle( TRequest request, Mediator.MessageHandlerDelegate next, CancellationToken cancellationToken) { Guard.Against.Null(request, nameof(request)); if (request is not ICacheable cacheable) return await next(request, cancellationToken); int cacheDurationSeconds = _cachingOptions.DefaultDurationSeconds; if (cacheable.CacheProfile != null) { var profile = _cachingOptions.Profiles.FirstOrDefault(p => p.Name.Equals(cacheable.CacheProfile, StringComparison.OrdinalIgnoreCase)); if (profile != null) { _logger.LogInformation("Using cache profile {ProfileName} with duration {DurationSeconds} seconds.", profile.Name, profile.CacheDurationSeconds); cacheDurationSeconds = profile?.CacheDurationSeconds ?? _cachingOptions.DefaultDurationSeconds; } } var cacheOptions = new MemoryCacheEntryOptions() .SetAbsoluteExpiration(TimeSpan.FromSeconds(cacheDurationSeconds)); var cacheKey = cacheable.GetCacheKey(); _logger.LogDebug("Checking cache for {CacheKey}", cacheKey); return await _cache.GetOrCreateAsync(cacheKey, async entry => { _logger.LogInformation($"Cache miss. Getting data from database. ({cacheKey})"); entry.SetOptions(cacheOptions); return await next(request, cancellationToken); }); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/CachingOptions.cs ================================================ namespace NimblePros.SampleToDo.Web.Configurations; public class CachingOptions { public const string SectionName = "Caching"; public int DefaultDurationSeconds { get; set; } = 10; public List Profiles { get; set; } = []; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/CachingProfile.cs ================================================ namespace NimblePros.SampleToDo.Web.Configurations; public class CachingProfile { public string Name { get; set; } = string.Empty; public int CacheDurationSeconds { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/GlobalExceptionHandler.cs ================================================ using Microsoft.AspNetCore.Diagnostics; namespace NimblePros.SampleToDo.Web.Configurations; public class GlobalExceptionHandler( IHostEnvironment env, ILogger logger) : IExceptionHandler { public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { logger.LogError(exception, "Unhandled exception occurred"); var problemDetails = new { type = "https://tools.ietf.org/html/rfc7231#section-6.6.1", title = "Internal Server Error", status = StatusCodes.Status500InternalServerError, detail = env.IsDevelopment() ? exception.Message : "An internal server error occurred", instance = httpContext.Request.Path }; httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError; httpContext.Response.ContentType = "application/json"; await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); return true; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/LoggerConfig.cs ================================================ namespace NimblePros.SampleToDo.Web.Configurations; public static class LoggerConfig { public static WebApplicationBuilder AddLoggerConfigs(this WebApplicationBuilder builder) { builder.Host.UseSerilog((_, config) => config.ReadFrom.Configuration(builder.Configuration)); return builder; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/MediatorConfig.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Infrastructure; using NimblePros.SampleToDo.UseCases.Contributors.Commands.Create; namespace NimblePros.SampleToDo.Web.Configurations; public static class MediatorConfig { // Should be called from ServiceConfigs.cs, not Program.cs public static IServiceCollection AddMediatorSourceGen(this IServiceCollection services, Microsoft.Extensions.Logging.ILogger logger) { logger.LogInformation("Registering Mediator SourceGen and Behaviors"); services.AddMediator(options => { // Lifetime: Singleton is fastest per docs; Scoped/Transient also supported. options.ServiceLifetime = ServiceLifetime.Scoped; // Supply any TYPE from each assembly you want scanned (the generator finds the assembly from the type) options.Assemblies = [ typeof(Contributor), // Core typeof(CreateContributorCommand), // UseCases typeof(InfrastructureServiceExtensions), // Infrastructure typeof(MediatorConfig) // Web ]; // Register pipeline behaviors here (order matters) options.PipelineBehaviors = [ typeof(LoggingBehavior<,>), typeof(CachingBehavior<,>) ]; // If you have stream behaviors: // options.StreamPipelineBehaviors = [ typeof(YourStreamBehavior<,>) ]; }); // Alternative: register behaviors via DI yourself (useful if not doing AOT): // services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>)); // services.AddScoped(typeof(IPipelineBehavior<,>), typeof(CachingBehavior<,>)); return services; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/MiddlewareConfig.cs ================================================ using NimblePros.Metronome; using NimblePros.SampleToDo.Infrastructure.Data; namespace NimblePros.SampleToDo.Web.Configurations; public static class MiddlewareConfig { public static async Task UseAppMiddleware(this WebApplication app) { // Use global exception handler in both dev and prod app.UseExceptionHandler(); if (app.Environment.IsDevelopment()) { app.UseShowAllServicesMiddleware(); // see https://github.com/ardalis/AspNetCoreStartupServices app.UseMetronomeLoggingMiddleware(); } else { app.UseHsts(); } app.UseFastEndpoints() .UseSwaggerGen(); // Includes AddFileServer and static files middleware app.UseHttpsRedirection(); await SeedDatabase(app); app.MapDefaultEndpoints(); // aspire health checks return app; } static async Task SeedDatabase(WebApplication app) { using var scope = app.Services.CreateScope(); var services = scope.ServiceProvider; try { var context = services.GetRequiredService(); // context.Database.Migrate(); context.Database.EnsureCreated(); await SeedData.InitializeAsync(context); } catch (Exception ex) { var logger = services.GetRequiredService>(); logger.LogError(ex, "An error occurred seeding the DB. {exceptionMessage}", ex.Message); } } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/OptionConfigs.cs ================================================ using NimblePros.SampleToDo.Infrastructure.Email; namespace NimblePros.SampleToDo.Web.Configurations; public static class OptionConfig { public static IServiceCollection AddOptionConfigs(this IServiceCollection services, IConfiguration configuration, Microsoft.Extensions.Logging.ILogger logger, WebApplicationBuilder builder) { services.Configure(configuration.GetSection(MailserverConfiguration.SectionName)); services.Configure(builder.Configuration.GetSection(CachingOptions.SectionName)); services.Configure(options => { options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); // Register global exception handler services.AddExceptionHandler(); services.AddProblemDetails(); if (builder.Environment.IsDevelopment()) { // add list services for diagnostic purposes - see https://github.com/ardalis/AspNetCoreStartupServices services.Configure((Ardalis.ListStartupServices.ServiceConfig config) => { config.Services = new List(builder.Services); // optional - default path to view services is /listallservices - recommended to choose your own path config.Path = "/listservices"; }); } logger.LogInformation("{Project} were configured", "Configuration and Options"); return services; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Configurations/ServiceConfigs.cs ================================================ using NimblePros.Metronome; using NimblePros.SampleToDo.Core; using NimblePros.SampleToDo.Infrastructure; namespace NimblePros.SampleToDo.Web.Configurations; public static class ServiceConfig { public static IServiceCollection AddServiceConfigs(this IServiceCollection services, Microsoft.Extensions.Logging.ILogger logger, WebApplicationBuilder builder) { services.AddCoreServices(logger) .AddInfrastructureServices(builder.Configuration, logger, builder.Environment.EnvironmentName) .AddMediatorSourceGen(logger); // add a default http client services.AddHttpClient("Default") .AddMetronomeHandler(); return services; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/ContributorRecord.cs ================================================ namespace NimblePros.SampleToDo.Web.Contributors; public record ContributorRecord(int Id, string Name); ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Create.cs ================================================ using System.ComponentModel.DataAnnotations; using FluentValidation; using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.UseCases.Contributors.Commands.Create; using NimblePros.SampleToDo.Web.Extensions; namespace NimblePros.SampleToDo.Web.Contributors; // This shows an example of having all related types in one file for simplicity. // Fast-Endpoints generally uses one file per class for larger projects, which // is the recommended approach. More files, but fewer merge conflicts and easier to // see what changed in a given commit or PR. public class Create(IMediator mediator) : Endpoint, ValidationProblem, ProblemHttpResult>> { private readonly IMediator _mediator = mediator; public override void Configure() { Post(CreateContributorRequest.Route); AllowAnonymous(); Summary(s => { s.Summary = "Create a new contributor"; s.Description = "Creates a new contributor with the provided name. The contributor name must be between 2 and 100 characters long."; s.ExampleRequest = new CreateContributorRequest { Name = "John Doe" }; s.ResponseExamples[201] = new CreateContributorResponse(1, "John Doe"); // Document possible responses s.Responses[201] = "Contributor created successfully"; s.Responses[400] = "Invalid input data - validation errors"; s.Responses[500] = "Internal server error"; }); // Add tags for API grouping Tags("Contributors"); // Add additional metadata Description(builder => builder .Accepts("application/json") .Produces(201, "application/json") .ProducesProblem(400) .ProducesProblem(500)); } public override async Task, ValidationProblem, ProblemHttpResult>> ExecuteAsync(CreateContributorRequest request, CancellationToken cancellationToken) { var result = await _mediator.Send(new CreateContributorCommand(ContributorName.From(request.Name!))); return result.ToCreatedResult( id => $"/Contributors/{id}", id => new CreateContributorResponse(id, request.Name!)); } } public class CreateContributorRequest { public const string Route = "/Contributors"; [Required] public string Name { get; set; } = String.Empty; } public class CreateContributorValidator : Validator { public CreateContributorValidator() { RuleFor(x => x.Name) .NotEmpty() .WithMessage("Name is required.") .MinimumLength(2) .MaximumLength(ContributorName.MaxLength); } } public class CreateContributorResponse(int id, string name) { public int Id { get; set; } = id; public string Name { get; set; } = name; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Delete.DeleteContributorRequest.cs ================================================ namespace NimblePros.SampleToDo.Web.Contributors; public record DeleteContributorRequest { public const string Route = "/Contributors/{ContributorId:int}"; public static string BuildRoute(int contributorId) => Route.Replace("{ContributorId:int}", contributorId.ToString()); public int ContributorId { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Delete.DeleteContributorValidator.cs ================================================ using FastEndpoints; using FluentValidation; namespace NimblePros.SampleToDo.Web.Contributors; /// /// See: https://fast-endpoints.com/docs/validation /// public class DeleteContributorValidator : Validator { public DeleteContributorValidator() { RuleFor(x => x.ContributorId) .GreaterThan(0); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Delete.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.UseCases.Contributors.Commands.Delete; using NimblePros.SampleToDo.Web.Extensions; namespace NimblePros.SampleToDo.Web.Contributors; public class Delete : Endpoint> { private readonly IMediator _mediator; public Delete(IMediator mediator) => _mediator = mediator; public override void Configure() { Delete(DeleteContributorRequest.Route); AllowAnonymous(); Summary(s => { s.Summary = "Delete a contributor"; s.Description = "Deletes an existing contributor by ID. This action cannot be undone."; s.ExampleRequest = new DeleteContributorRequest { ContributorId = 1 }; // Document possible responses s.Responses[204] = "Contributor deleted successfully"; s.Responses[404] = "Contributor not found"; s.Responses[400] = "Invalid request or deletion failed"; }); // Add tags for API grouping Tags("Contributors"); // Add additional metadata Description(builder => builder .Accepts() .Produces(204) .ProducesProblem(404) .ProducesProblem(400)); } public override async Task> ExecuteAsync(DeleteContributorRequest req, CancellationToken ct) { var cmd = new DeleteContributorCommand(ContributorId.From(req.ContributorId)); var result = await _mediator.Send(cmd, ct); return result.ToDeleteResult(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/GetById.GetContributorByIdMapper.cs ================================================ using NimblePros.SampleToDo.UseCases.Contributors; namespace NimblePros.SampleToDo.Web.Contributors; public sealed class GetContributorByIdMapper : Mapper { public override ContributorRecord FromEntity(ContributorDto e) => new(e.Id.Value, e.Name.Value); } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/GetById.GetContributorByIdRequest.cs ================================================ namespace NimblePros.SampleToDo.Web.Contributors; public class GetContributorByIdRequest { public const string Route = "/Contributors/{ContributorId:int}"; public static string BuildRoute(int contributorId) => Route.Replace("{ContributorId:int}", contributorId.ToString()); public int ContributorId { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/GetById.GetContributorValidator.cs ================================================ using FastEndpoints; using FluentValidation; namespace NimblePros.SampleToDo.Web.Contributors; /// /// See: https://fast-endpoints.com/docs/validation /// public class GetContributorValidator : Validator { public GetContributorValidator() { RuleFor(x => x.ContributorId) .GreaterThan(0); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/GetById.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.UseCases.Contributors.Queries.Get; using NimblePros.SampleToDo.Web.Extensions; namespace NimblePros.SampleToDo.Web.Contributors; public class GetById(IMediator mediator) : Endpoint, NotFound, ProblemHttpResult>, GetContributorByIdMapper> { public override void Configure() { Get(GetContributorByIdRequest.Route); AllowAnonymous(); // Optional: document statuses for Swagger Summary(s => { s.Summary = "Get a contributor by ID"; s.Description = "Retrieves a specific contributor by their unique identifier. Returns detailed contributor information including ID and name."; s.ExampleRequest = new GetContributorByIdRequest { ContributorId = 1 }; s.ResponseExamples[200] = new ContributorRecord(1, "John Doe"); // Document possible responses s.Responses[200] = "Contributor found and returned successfully"; s.Responses[404] = "Contributor with specified ID not found"; }); // Add tags for API grouping Tags("Contributors"); // Add additional metadata Description(builder => builder .Accepts() .Produces(200, "application/json") .ProducesProblem(404)); } public override async Task, NotFound, ProblemHttpResult>> ExecuteAsync(GetContributorByIdRequest request, CancellationToken ct) { var result = await mediator.Send(new GetContributorQuery(ContributorId.From(request.ContributorId)), ct); return result.ToGetByIdResult(Map.FromEntity); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/List.ContributorListResponse.cs ================================================  namespace NimblePros.SampleToDo.Web.Contributors; public record ContributorListResponse : UseCases.PagedResult { public ContributorListResponse(IReadOnlyList Items, int Page, int PerPage, int TotalCount, int TotalPages) : base(Items, Page, PerPage, TotalCount, TotalPages) { } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/List.cs ================================================ using FluentValidation; using NimblePros.SampleToDo.UseCases.Contributors; using NimblePros.SampleToDo.UseCases.Contributors.Queries.List; namespace NimblePros.SampleToDo.Web.Contributors; public class List(IMediator mediator) : Endpoint { private readonly IMediator _mediator = mediator; public override void Configure() { Get("/Contributors"); AllowAnonymous(); Summary(s => { s.Summary = "List contributors with pagination"; s.Description = "Retrieves a paginated list of all contributors. Supports GitHub-style pagination with 1-based page indexing and configurable page size."; s.ExampleRequest = new ListContributorsRequest { Page = 1, PerPage = 10 }; s.ResponseExamples[200] = new ContributorListResponse( new List { new(1, "John Doe"), new(2, "Jane Smith") }, 1, 10, 2, 1); // Document pagination parameters s.Params["page"] = "1-based page index (default 1)"; s.Params["per_page"] = $"Page size 1–{UseCases.Constants.MAX_PAGE_SIZE} (default {UseCases.Constants.DEFAULT_PAGE_SIZE})"; // Document possible responses s.Responses[200] = "Paginated list of contributors returned successfully"; s.Responses[400] = "Invalid pagination parameters"; }); // Add tags for API grouping Tags("Contributors"); // Add additional metadata Description(builder => builder .Accepts() .Produces(200, "application/json") .ProducesProblem(400)); } public override async Task HandleAsync(ListContributorsRequest request, CancellationToken cancellationToken) { var result = await _mediator.Send(new ListContributorsQuery(request.Page, request.PerPage)); if (!result.IsSuccess) { await Send.ErrorsAsync(statusCode: 400, cancellationToken); return; } var pagedResult = result.Value; AddLinkHeader(pagedResult.Page, pagedResult.PerPage, pagedResult.TotalPages); var response = Map.FromEntity(pagedResult); await Send.OkAsync(response, cancellationToken); } private void AddLinkHeader(int page, int perPage, int totalPages) { var baseUrl = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}{HttpContext.Request.Path}"; string Link(string rel, int p) => $"<{baseUrl}?page={p}&per_page={perPage}>; rel=\"{rel}\""; var parts = new List(); if (page > 1) { parts.Add(Link("first", 1)); parts.Add(Link("prev", page - 1)); } if (page < totalPages) { parts.Add(Link("next", page + 1)); parts.Add(Link("last", totalPages)); } if (parts.Count > 0) HttpContext.Response.Headers["Link"] = string.Join(", ", parts); } } public sealed class ListContributorsRequest { // Bind to ?page= [BindFrom("page")] public int Page { get; init; } = 1; // Bind to ?per_page= [BindFrom("per_page")] public int PerPage { get; init; } = UseCases.Constants.DEFAULT_PAGE_SIZE; } public sealed class ListContributorsValidator : Validator { public ListContributorsValidator() { RuleFor(x => x.Page) .GreaterThanOrEqualTo(1) .WithMessage("page must be >= 1"); RuleFor(x => x.PerPage) .InclusiveBetween(1, UseCases.Constants.MAX_PAGE_SIZE) .WithMessage($"per_page must be between 1 and {UseCases.Constants.MAX_PAGE_SIZE}"); } } public sealed class ListContributorsMapper : Mapper> { public override ContributorListResponse FromEntity(UseCases.PagedResult e) { var items = e.Items .Select(c => new ContributorRecord(c.Id.Value, c.Name.Value)) .ToList(); return new ContributorListResponse(items, e.Page, e.PerPage, e.TotalCount, e.TotalPages); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Update.UpdateContributorRequest.cs ================================================ using System.ComponentModel.DataAnnotations; namespace NimblePros.SampleToDo.Web.Contributors; public class UpdateContributorRequest { public const string Route = "/Contributors/{ContributorId:int}"; public static string BuildRoute(int contributorId) => Route.Replace("{ContributorId:int}", contributorId.ToString()); public int ContributorId { get; set; } [Required] public int Id { get; set; } [Required] public string? Name { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Update.UpdateContributorResponse.cs ================================================ namespace NimblePros.SampleToDo.Web.Contributors; public class UpdateContributorResponse { public UpdateContributorResponse(ContributorRecord contributor) { Contributor = contributor; } public ContributorRecord Contributor { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Update.UpdateContributorValidator.cs ================================================ using FluentValidation; using NimblePros.SampleToDo.Infrastructure.Data.Config; namespace NimblePros.SampleToDo.Web.Contributors; /// /// See: https://fast-endpoints.com/docs/validation /// public class UpdateContributorValidator : Validator { public UpdateContributorValidator() { RuleFor(x => x.Name) .NotEmpty() .WithMessage("Name is required.") .MinimumLength(2) .MaximumLength(DataSchemaConstants.DEFAULT_NAME_LENGTH); RuleFor(x => x.ContributorId) .Must((args, contributorId) => args.Id == contributorId) .WithMessage("Route and body Ids must match; cannot update Id of an existing resource."); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Contributors/Update.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.UseCases.Contributors; using NimblePros.SampleToDo.UseCases.Contributors.Commands.Update; using NimblePros.SampleToDo.Web.Extensions; namespace NimblePros.SampleToDo.Web.Contributors; public class Update(IMediator mediator) : Endpoint< UpdateContributorRequest, Results, NotFound, ProblemHttpResult>, UpdateContributorMapper> { private readonly IMediator _mediator = mediator; public override void Configure() { Put(UpdateContributorRequest.Route); AllowAnonymous(); // Optional but nice: enumerate for Swagger Summary(s => { s.Summary = "Update a contributor"; s.Description = "Updates an existing contributor's information. The contributor name must be between 2 and 100 characters long."; s.ExampleRequest = new UpdateContributorRequest { Id = 1, Name = "Updated Name" }; s.ResponseExamples[200] = new UpdateContributorResponse(new ContributorRecord(1, "Updated Name")); // Document possible responses s.Responses[200] = "Contributor updated successfully"; s.Responses[404] = "Contributor with specified ID not found"; s.Responses[400] = "Invalid input data or business rule violation"; }); // Add tags for API grouping Tags("Contributors"); // Add additional metadata Description(builder => builder .Accepts("application/json") .Produces(200, "application/json") .ProducesProblem(404) .ProducesProblem(400)); } public override async Task, NotFound, ProblemHttpResult>> ExecuteAsync(UpdateContributorRequest request, CancellationToken ct) { var cmd = new UpdateContributorCommand( ContributorId.From(request.Id), ContributorName.From(request.Name!)); var result = await _mediator.Send(cmd, ct); return result.ToUpdateResult(Map.FromEntity); } } public sealed class UpdateContributorMapper : Mapper { public override UpdateContributorResponse FromEntity(ContributorDto e) => new(new ContributorRecord(e.Id.Value, e.Name.Value)); } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Extensions/ResultExtensions.cs ================================================ using Ardalis.Result; namespace NimblePros.SampleToDo.Web.Extensions; public static class ResultExtensions { /// /// Maps Result to TypedResults for endpoints that return Created, ValidationProblem, or ProblemHttpResult /// public static Results, ValidationProblem, ProblemHttpResult> ToCreatedResult( this Result result, Func locationBuilder, Func mapResponse) { return result.Status switch { ResultStatus.Ok => TypedResults.Created(locationBuilder(result.Value), mapResponse(result.Value)), ResultStatus.Invalid => TypedResults.ValidationProblem( result.ValidationErrors .GroupBy(e => e.Identifier ?? string.Empty) .ToDictionary( g => g.Key, g => g.Select(e => e.ErrorMessage).ToArray() ) ), _ => TypedResults.Problem( title: "Create failed", detail: string.Join("; ", result.Errors), statusCode: StatusCodes.Status400BadRequest) }; } /// /// Maps Result to TypedResults for GetById endpoints that return Ok, NotFound, or ProblemHttpResult /// public static Results, NotFound, ProblemHttpResult> ToGetByIdResult( this Result result, Func mapResponse) { return ToOkOrNotFoundResult(result, mapResponse, "Get"); } /// /// Maps Result to TypedResults for Update endpoints that return Ok, NotFound, or ProblemHttpResult /// public static Results, NotFound, ProblemHttpResult> ToUpdateResult( this Result result, Func mapResponse) { return ToOkOrNotFoundResult(result, mapResponse, "Update"); } /// /// Maps Result to TypedResults for Delete endpoints that return NoContent, NotFound, or ProblemHttpResult /// public static Results ToDeleteResult( this Result result) { return result.Status switch { ResultStatus.Ok => TypedResults.NoContent(), ResultStatus.NotFound => TypedResults.NotFound(), _ => TypedResults.Problem( title: "Delete failed", detail: string.Join("; ", result.Errors), statusCode: StatusCodes.Status400BadRequest) }; } /// /// Private helper method for Ok/NotFound result patterns /// private static Results, NotFound, ProblemHttpResult> ToOkOrNotFoundResult( Result result, Func mapResponse, string operationName) { return result.Status switch { ResultStatus.Ok => TypedResults.Ok(mapResponse(result.Value)), ResultStatus.NotFound => TypedResults.NotFound(), _ => TypedResults.Problem( title: $"{operationName} failed", detail: string.Join("; ", result.Errors), statusCode: StatusCodes.Status400BadRequest) }; } /// /// Maps Result to TypedResults for endpoints that return Ok only (like List endpoints) /// public static Ok ToOkOnlyResult( this Result result, Func mapResponse) { return TypedResults.Ok(mapResponse(result.Value)); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/GlobalUsings.cs ================================================ global using Ardalis.ListStartupServices; global using Ardalis.Result; global using FastEndpoints; global using FastEndpoints.Swagger; global using Mediator; global using Microsoft.AspNetCore.Http; // Ok, NotFound, NoContent, ProblemDetails global using Microsoft.AspNetCore.Http.HttpResults; global using Microsoft.EntityFrameworkCore; global using NimblePros.SharedKernel; global using Serilog; global using Serilog.Extensions.Logging; ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/LoggingBehavior.cs ================================================ using System.Diagnostics; using System.Reflection; using Ardalis.GuardClauses; namespace NimblePros.SampleToDo.Web; public class LoggingBehavior : IPipelineBehavior where TRequest : notnull, IMessage { private readonly ILogger> _logger; public LoggingBehavior(ILogger> logger) { _logger = logger; } public async ValueTask Handle( TRequest request, MessageHandlerDelegate next, CancellationToken cancellationToken) { Guard.Against.Null(request); if (_logger.IsEnabled(LogLevel.Information)) { _logger.LogInformation("Handling {RequestName}", typeof(TRequest).Name); Type myType = request.GetType(); IList props = new List(myType.GetProperties()); foreach (PropertyInfo prop in props) { object? propValue = prop?.GetValue(request, null); _logger.LogInformation("Property {Property} : {@Value}", prop?.Name, propValue); } } var sw = Stopwatch.StartNew(); var response = await next(request, cancellationToken); _logger.LogInformation("Handled {RequestName} with {Response} in {ms} ms", typeof(TRequest).Name, response, sw.ElapsedMilliseconds); sw.Stop(); return response; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/NimblePros.SampleToDo.Web.csproj ================================================  Exe true True ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Program.cs ================================================ using System.Text; using AspNetCore.Localizer.Json.Extensions; using FluentValidation; using Microsoft.Extensions.Localization; using NimblePros.Metronome; using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.Infrastructure.Data; using NimblePros.SampleToDo.Web.Configurations; using NimblePros.SampleToDo.Web.Projects; public partial class Program { private static async Task Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.WebHost.ConfigureKestrel(o => { o.AddServerHeader = false; // <- removes "Server: Kestrel" }); builder.AddServiceDefaults(); var logger = Log.Logger = new LoggerConfiguration() .Enrich.FromLogContext() .WriteTo.Console() .CreateLogger(); logger.Information("Starting web host"); builder.AddLoggerConfigs(); var appLogger = new SerilogLoggerFactory(logger) .CreateLogger(); builder.Services.AddOptionConfigs(builder.Configuration, appLogger, builder); builder.Services.AddServiceConfigs(appLogger, builder); builder.Services.AddFastEndpoints() .SwaggerDocument(o => { o.ShortSchemaNames = true; }); builder.Services.AddValidatorsFromAssemblyContaining(); if (!builder.Environment.EnvironmentName.Equals("Testing")) { var connectionString = builder.Configuration.GetConnectionString("SqliteConnection"); builder.Services.AddDbContext(options => options.UseSqlite(connectionString)); } builder.Services.AddMemoryCache(); // add list services for diagnostic purposes - see https://github.com/ardalis/AspNetCoreStartupServices builder.Services.Configure((Ardalis.ListStartupServices.ServiceConfig config) => { config.Services = new List(builder.Services); // optional - default path to view services is /listallservices - recommended to choose your own path config.Path = "/listservices"; }); // track db and external service calls builder.Services.AddMetronome(); // Add localization with the JSON path builder.Services.AddLocalization(options => options.ResourcesPath = "i18n"); // ----- Add JSON-specific localization builder.Services.AddJsonLocalization(options => { options.ResourcesPath = "i18n"; // Path to the JSON files (e.g., i18n/en/Project.json) options.CacheDuration = TimeSpan.FromHours(1); // Optional: Cache for performance options.FileEncoding = Encoding.UTF8; //Optional: Specify file encoding }); // ----- Register the typed localizer for the Project aggregate ----- builder.Services.AddSingleton(sp => { var factory = sp.GetRequiredService(); // Creates a localizer for 'ProjectAggregate' – loads from i18n/{culture}/Project.json return factory.Create(typeof(ProjectErrorMessages)); }); var app = builder.Build(); // ----- Set the static holder for Core access ----- var localizer = app.Services.GetRequiredService(); Localization.Current = new Localization.LocalizationContext(localizer); // ----- Add request localization middleware (before app.Run()) ----- var supportedCultures = new[] { "en", "fr", "fa" }; // Add your cultures var localizationOptions = new RequestLocalizationOptions() .SetDefaultCulture(supportedCultures[0]) .AddSupportedCultures(supportedCultures) .AddSupportedUICultures(supportedCultures); app.UseRequestLocalization(localizationOptions); // Verify validators are registered properly in development if (app.Environment.IsDevelopment()) { using var scope = app.Services.CreateScope(); var validatorsCount = scope.ServiceProvider.GetServices>().Count(); appLogger.LogInformation("Validators found: {validatorsCount}", validatorsCount); } // see Configurations/MiddlewareConfig.cs await app.UseAppMiddleware(); app.Run(); } } // Make the implicit Program.cs class public, so integration tests can reference the correct assembly for host building public partial class Program { } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Create.CreateProjectRequest.cs ================================================ using System.ComponentModel.DataAnnotations; namespace NimblePros.SampleToDo.Web.Projects; public class CreateProjectRequest { public const string Route = "/Projects"; [Required] public string Name { get; set; } = String.Empty; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Create.CreateProjectResponse.cs ================================================ namespace NimblePros.SampleToDo.Web.Projects; public record CreateProjectResponse(int Id, string Name); ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Create.CreateProjectValidator.cs ================================================ using FastEndpoints; using FluentValidation; using NimblePros.SampleToDo.Core.ProjectAggregate; namespace NimblePros.SampleToDo.Web.Projects; public class CreateProjectValidator : Validator { public CreateProjectValidator() { RuleFor(x => x.Name) .NotEmpty() .WithMessage("Name is required.") .MinimumLength(2) .MaximumLength(ProjectName.MaxLength); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Create.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.UseCases.Projects.Create; using NimblePros.SampleToDo.Web.Extensions; namespace NimblePros.SampleToDo.Web.Projects; public class Create(IMediator mediator) : Endpoint, ValidationProblem, ProblemHttpResult>> { private readonly IMediator _mediator = mediator; public override void Configure() { Post(CreateProjectRequest.Route); AllowAnonymous(); Summary(s => { s.Summary = "Create a new project"; s.Description = "Creates a new project with the provided name. The project name must be between 2 and 100 characters long."; s.ExampleRequest = new CreateProjectRequest { Name = "My New Project" }; s.ResponseExamples[201] = new CreateProjectResponse(1, "My New Project"); // Document possible responses s.Responses[201] = "Project created successfully"; s.Responses[400] = "Invalid input data - validation errors"; s.Responses[500] = "Internal server error"; }); // Add tags for API grouping Tags("Projects"); // Add additional metadata Description(builder => builder .Accepts("application/json") .Produces(201, "application/json") .ProducesProblem(400) .ProducesProblem(500)); } public override async Task, ValidationProblem, ProblemHttpResult>> ExecuteAsync(CreateProjectRequest request, CancellationToken cancellationToken) { var result = await _mediator.Send(new CreateProjectCommand(ProjectName.From(request.Name!))); return result.ToCreatedResult( id => $"/Projects/{id}", id => new CreateProjectResponse(id.Value, request.Name!)); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/CreateToDoItem.CreateToDoItemRequest.cs ================================================ using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Mvc; namespace NimblePros.SampleToDo.Web.Projects; public class CreateToDoItemRequest { public const string Route = "/Projects/{ProjectId:int}/ToDoItems"; public static string BuildRoute(int projectId) => Route.Replace("{ProjectId:int}", projectId.ToString()); [Required] [FromRoute] public int ProjectId { get; set; } = 0; [Required] public string Title { get; set; } = string.Empty; [Required] public string Description { get; set; } = string.Empty; public int? ContributorId { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/CreateToDoItem.CreateToDoItemValidator.cs ================================================ using FluentValidation; using NimblePros.SampleToDo.Infrastructure.Data.Config; namespace NimblePros.SampleToDo.Web.Projects; /// /// See: https://fast-endpoints.com/docs/validation /// public class CreateToDoItemValidator : Validator { public CreateToDoItemValidator() { RuleFor(x => x.ProjectId) .GreaterThan(0); RuleFor(x => x.Title) .NotEmpty() .MinimumLength(2) .MaximumLength(DataSchemaConstants.DEFAULT_NAME_LENGTH); RuleFor(x => x.Description) .MaximumLength(200) // TODO: Move to constant .NotEmpty(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/CreateToDoItem.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.UseCases.Projects.AddToDoItem; using NimblePros.SampleToDo.Web.Projects; namespace NimblePros.SampleToDo.Web.ProjectEndpoints; public class Create : Endpoint> { private readonly IMediator _mediator; public Create(IMediator mediator) { _mediator = mediator; } public override void Configure() { Post(CreateToDoItemRequest.Route); AllowAnonymous(); Summary(s => { s.Summary = "Add a new todo item to a project"; s.Description = "Creates a new todo item within an existing project. The project must exist and the contributor (if specified) must be valid."; s.ExampleRequest = new CreateToDoItemRequest { ContributorId = 1, ProjectId = 1, Title = "Implement user authentication", Description = "Add JWT-based authentication to the API" }; // Document possible responses s.Responses[201] = "Todo item created successfully"; s.Responses[404] = "Project or contributor not found"; s.Responses[400] = "Invalid input data"; s.Responses[500] = "Internal server error"; }); // Add tags for API grouping Tags("Projects"); // Add additional metadata Description(builder => builder .Accepts("application/json") .Produces(201) .ProducesProblem(404) .ProducesProblem(400) .ProducesProblem(500)); } public override async Task> ExecuteAsync(CreateToDoItemRequest request, CancellationToken cancellationToken) { ContributorId? contributorId = request.ContributorId.HasValue ? ContributorId.From(request.ContributorId.Value) : null; var command = new AddToDoItemCommand(ProjectId.From(request.ProjectId), contributorId, ToDoItemTitle.From(request.Title), ToDoItemDescription.From(request.Description)); var result = await _mediator.Send(command); return result.Status switch { ResultStatus.Ok => TypedResults.Created($"/Projects/{request.ProjectId}"), ResultStatus.NotFound => TypedResults.NotFound(), _ => TypedResults.Problem( title: "Create todo item failed", detail: string.Join("; ", result.Errors), statusCode: StatusCodes.Status400BadRequest) }; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Delete.DeleteProjectRequest.cs ================================================ namespace NimblePros.SampleToDo.Web.Projects; public class DeleteProjectRequest { public const string Route = "/Projects/{ProjectId:int}"; public static string BuildRoute(int projectId) => Route.Replace("{ProjectId:int}", projectId.ToString()); public int ProjectId { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Delete.DeleteProjectValidator.cs ================================================ using FastEndpoints; using FluentValidation; namespace NimblePros.SampleToDo.Web.Projects; /// /// See: https://fast-endpoints.com/docs/validation /// public class DeleteProjectValidator : Validator { public DeleteProjectValidator() { RuleFor(x => x.ProjectId) .GreaterThan(0); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Delete.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.UseCases.Projects.Delete; using NimblePros.SampleToDo.Web.Extensions; namespace NimblePros.SampleToDo.Web.Projects; public class Delete : Endpoint> { private readonly IMediator _mediator; public Delete(IMediator mediator) => _mediator = mediator; public override void Configure() { Delete(DeleteProjectRequest.Route); AllowAnonymous(); Summary(s => { s.Summary = "Delete a project"; s.Description = "Deletes an existing project by ID. This will also delete all associated todo items. This action cannot be undone."; s.ExampleRequest = new DeleteProjectRequest { ProjectId = 1 }; // Document possible responses s.Responses[204] = "Project deleted successfully"; s.Responses[404] = "Project not found"; s.Responses[400] = "Invalid request or deletion failed"; }); // Add tags for API grouping Tags("Projects"); // Add additional metadata Description(builder => builder .Accepts() .Produces(204) .ProducesProblem(404) .ProducesProblem(400)); } public override async Task> ExecuteAsync(DeleteProjectRequest req, CancellationToken ct) { var cmd = new DeleteProjectCommand(ProjectId.From(req.ProjectId)); var result = await _mediator.Send(cmd, ct); return result.ToDeleteResult(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/GetById.GetProjectByIdRequest.cs ================================================  namespace NimblePros.SampleToDo.Web.Endpoints.Projects; public class GetProjectByIdRequest { public const string Route = "/Projects/{ProjectId:int}"; public static string BuildRoute(int projectId) => Route.Replace("{ProjectId:int}", projectId.ToString()); public int ProjectId { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/GetById.GetProjectByIdResponse.cs ================================================ namespace NimblePros.SampleToDo.Web.Projects; public record GetProjectByIdResponse(int Id, string Name, List Items); ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/GetById.GetProjectByIdValidator.cs ================================================ using FastEndpoints; using FluentValidation; using NimblePros.SampleToDo.Web.Endpoints.Projects; namespace NimblePros.SampleToDo.Web.Projects; /// /// See: https://fast-endpoints.com/docs/validation /// public class GetProjectByIdValidator : Validator { public GetProjectByIdValidator() { RuleFor(x => x.ProjectId) .GreaterThan(0); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/GetById.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.UseCases.Projects.GetWithAllItems; using NimblePros.SampleToDo.Web.Endpoints.Projects; using NimblePros.SampleToDo.Web.Extensions; namespace NimblePros.SampleToDo.Web.Projects; public class GetById(IMediator mediator) : Endpoint, NotFound, ProblemHttpResult>> { public override void Configure() { Get(GetProjectByIdRequest.Route); AllowAnonymous(); Summary(s => { s.Summary = "Get a project by ID"; s.Description = "Retrieves a specific project by its unique identifier. Returns detailed project information including all associated todo items."; s.ExampleRequest = new GetProjectByIdRequest { ProjectId = 1 }; s.ResponseExamples[200] = new GetProjectByIdResponse( 1, "Sample Project", new List { new(1, "Sample Task", "Sample task description", false, 1) }); // Document possible responses s.Responses[200] = "Project found and returned successfully"; s.Responses[404] = "Project with specified ID not found"; s.Responses[400] = "Invalid project ID provided"; }); // Add tags for API grouping Tags("Projects"); // Add additional metadata Description(builder => builder .Accepts() .Produces(200, "application/json") .ProducesProblem(404) .ProducesProblem(400)); } public override async Task, NotFound, ProblemHttpResult>> ExecuteAsync(GetProjectByIdRequest request, CancellationToken ct) { var command = new GetProjectWithAllItemsQuery(ProjectId.From(request.ProjectId)); var result = await mediator.Send(command, ct); return result.ToGetByIdResult(project => new GetProjectByIdResponse( project.Id.Value, project.Name.Value, project.Items .Select(item => new ToDoItemRecord( item.Id.Value, item.Title, item.Description, item.IsComplete, item.ContributorId?.Value)) .ToList())); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/List.ProjectListResponse.cs ================================================ namespace NimblePros.SampleToDo.Web.Projects; public record ProjectListResponse : UseCases.PagedResult { public ProjectListResponse(IReadOnlyList Items, int Page, int PerPage, int TotalCount, int TotalPages) : base(Items, Page, PerPage, TotalCount, TotalPages) { } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/List.cs ================================================ using FluentValidation; using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.UseCases.Projects; using NimblePros.SampleToDo.UseCases.Projects.ListShallow; namespace NimblePros.SampleToDo.Web.Projects; public class List(IMediator mediator) : Endpoint { private readonly IMediator _mediator = mediator; public override void Configure() { Get($"/{nameof(Project)}s"); AllowAnonymous(); Summary(s => { s.Summary = "List projects with pagination"; s.Description = "Retrieves a paginated list of all projects without their todo items. Supports GitHub-style pagination with 1-based page indexing and configurable page size."; s.ExampleRequest = new ListProjectsRequest { Page = 1, PerPage = 10 }; s.ResponseExamples[200] = new ProjectListResponse( new List { new(1, "Sample Project"), new(2, "Another Project") }, 1, 10, 2, 1); // Document pagination parameters s.Params["page"] = "1-based page index (default 1)"; s.Params["per_page"] = $"Page size 1–{UseCases.Constants.MAX_PAGE_SIZE} (default {UseCases.Constants.DEFAULT_PAGE_SIZE})"; // Document possible responses s.Responses[200] = "Paginated list of projects returned successfully"; s.Responses[400] = "Invalid pagination parameters"; }); // Add tags for API grouping Tags("Projects"); // Add additional metadata Description(builder => builder .Accepts() .Produces(200, "application/json") .ProducesProblem(400)); } public override async Task HandleAsync(ListProjectsRequest request, CancellationToken cancellationToken) { var result = await _mediator.Send(new ListProjectsShallowQuery(null, null)); if (!result.IsSuccess) { await Send.ErrorsAsync(statusCode: 400, cancellationToken); return; } // For now, simulate pagination behavior until ListProjectsShallowQuery supports it var allProjects = result.Value.ToList(); var skip = (request.Page - 1) * request.PerPage; var pagedProjects = allProjects.Skip(skip).Take(request.PerPage).ToList(); var totalCount = allProjects.Count; var totalPages = (int)Math.Ceiling((double)totalCount / request.PerPage); AddLinkHeader(request.Page, request.PerPage, totalPages); var pagedResult = new UseCases.PagedResult( pagedProjects, request.Page, request.PerPage, totalCount, totalPages); var response = Map.FromEntity(pagedResult); await Send.OkAsync(response, cancellationToken); } private void AddLinkHeader(int page, int perPage, int totalPages) { var baseUrl = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}{HttpContext.Request.Path}"; string Link(string rel, int p) => $"<{baseUrl}?page={p}&per_page={perPage}>; rel=\"{rel}\""; var parts = new List(); if (page > 1) { parts.Add(Link("first", 1)); parts.Add(Link("prev", page - 1)); } if (page < totalPages) { parts.Add(Link("next", page + 1)); parts.Add(Link("last", totalPages)); } if (parts.Count > 0) HttpContext.Response.Headers["Link"] = string.Join(", ", parts); } } public sealed class ListProjectsRequest { // Bind to ?page= [BindFrom("page")] public int Page { get; init; } = 1; // Bind to ?per_page= [BindFrom("per_page")] public int PerPage { get; init; } = UseCases.Constants.DEFAULT_PAGE_SIZE; } public sealed class ListProjectsValidator : Validator { public ListProjectsValidator() { RuleFor(x => x.Page) .GreaterThanOrEqualTo(1) .WithMessage("page must be >= 1"); RuleFor(x => x.PerPage) .InclusiveBetween(1, UseCases.Constants.MAX_PAGE_SIZE) .WithMessage($"per_page must be between 1 and {UseCases.Constants.MAX_PAGE_SIZE}"); } } public sealed class ListProjectsMapper : Mapper> { public override ProjectListResponse FromEntity(UseCases.PagedResult e) { var items = e.Items .Select(p => new ProjectRecord(p.Id, p.Name)) .ToList(); return new ProjectListResponse(items, e.Page, e.PerPage, e.TotalCount, e.TotalPages); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/ListIncompleteItems.ListIncompleteItemsRequest.cs ================================================ using Microsoft.AspNetCore.Mvc; namespace NimblePros.SampleToDo.Web.Endpoints.ProjectEndpoints; public class ListIncompleteItemsRequest { public const string Route = "/Projects/{ProjectId}/IncompleteItems"; public static string BuildRoute(int projectId) => Route.Replace("{ProjectId:int}", projectId.ToString()); [FromRoute] public int ProjectId { get; set; } //[FromQuery] //public string? SearchString { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/ListIncompleteItems.ListIncompleteItemsResponse.cs ================================================ namespace NimblePros.SampleToDo.Web.Projects; public class ListIncompleteItemsResponse { public ListIncompleteItemsResponse(int projectId, List incompleteItems) { ProjectId = projectId; IncompleteItems = incompleteItems; } public int ProjectId { get; set; } public List IncompleteItems { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/ListIncompleteItems.cs ================================================ using NimblePros.SampleToDo.UseCases.Projects.ListIncompleteItems; using NimblePros.SampleToDo.Web.Endpoints.ProjectEndpoints; namespace NimblePros.SampleToDo.Web.Projects; /// /// Lists all incomplete items in a project. /// /// /// Lists all incomplete items in a project. /// Returns FAKE data in DEV. Run in production to use real database-driven data. /// public class ListIncompleteItems(IMediator mediator) : Endpoint { private readonly IMediator _mediator = mediator; public override void Configure() { Get(ListIncompleteItemsRequest.Route); AllowAnonymous(); } public override async Task HandleAsync(ListIncompleteItemsRequest request, CancellationToken cancellationToken) { Response = new ListIncompleteItemsResponse(request.ProjectId, new List()); var result = await _mediator.Send(new ListIncompleteItemsByProjectQuery(request.ProjectId)); if (result.Status == ResultStatus.NotFound) { await Send.NotFoundAsync(cancellationToken); return; } Response.IncompleteItems = result.Value.Select(item => new ToDoItemRecord(item.Id.Value, item.Title, item.Description, item.IsComplete, item.ContributorId?.Value)) .ToList(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/MarkItemComplete.MarkItemCompleteRequest.cs ================================================ using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Mvc; namespace NimblePros.SampleToDo.Web.ProjectEndpoints; public class MarkItemCompleteRequest { public const string Route = "/Projects/{ProjectId:int}/ToDoItems/{ToDoItemId:int}"; public static string BuildRoute(int projectId, int toDoItemId) => Route.Replace("{ProjectId:int}", projectId.ToString()) .Replace("{ToDoItemId:int}", toDoItemId.ToString()); [Required] [FromRoute] public int ProjectId { get; set; } = 0; [Required] [FromRoute] public int ToDoItemId { get; set; } = 0; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/MarkItemComplete.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.UseCases.Projects.MarkToDoItemComplete; namespace NimblePros.SampleToDo.Web.ProjectEndpoints; /// /// Mark an item as complete /// public class MarkItemComplete(IMediator mediator) : Endpoint { private readonly IMediator _mediator = mediator; public override void Configure() { Post(MarkItemCompleteRequest.Route); AllowAnonymous(); Summary(s => { s.ExampleRequest = new MarkItemCompleteRequest { ProjectId = 1, ToDoItemId = 1 }; }); } public override async Task HandleAsync( MarkItemCompleteRequest request, CancellationToken cancellationToken) { var command = new MarkToDoItemCompleteCommand(ProjectId.From(request.ProjectId), request.ToDoItemId); var result = await _mediator.Send(command); if (result.Status == Ardalis.Result.ResultStatus.NotFound) { await Send.NotFoundAsync(cancellationToken); return; } if (result.IsSuccess) { await Send.NoContentAsync(cancellationToken); }; // TODO: Handle other issues as needed } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/ProjectRecord.cs ================================================ namespace NimblePros.SampleToDo.Web.Projects; public record ProjectRecord(int Id, string Name); ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/ToDoItemRecord.cs ================================================ namespace NimblePros.SampleToDo.Web.Projects; public record ToDoItemRecord(int Id, string Title, string Description, bool IsDone, int? ContributorId); ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Update.UpdateProjectRequest.cs ================================================ using System.ComponentModel.DataAnnotations; namespace NimblePros.SampleToDo.Web.Projects; public class UpdateProjectRequest { public const string Route = "/Projects/{ProjectId:int}"; public static string BuildRoute(int projectId) => Route.Replace("{ProjectId:int}", projectId.ToString()); public int ProjectId { get; set; } [Required] public int Id { get; set; } [Required] public string? Name { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Update.UpdateProjectRequestValidator.cs ================================================ using FluentValidation; using NimblePros.SampleToDo.Infrastructure.Data.Config; namespace NimblePros.SampleToDo.Web.Projects; /// /// See: https://fast-endpoints.com/docs/validation /// public class UpdateProjectRequestValidator : Validator { public UpdateProjectRequestValidator() { RuleFor(x => x.Name) .NotEmpty() .WithMessage("Name is required.") .MinimumLength(2) .MaximumLength(DataSchemaConstants.DEFAULT_NAME_LENGTH); RuleFor(x => x.ProjectId) .Must((args, projectId) => args.Id == projectId) .WithMessage("Route and body Ids must match; cannot update Id of an existing resource."); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Update.UpdateProjectResponse.cs ================================================ namespace NimblePros.SampleToDo.Web.Projects; public class UpdateProjectResponse { public UpdateProjectResponse(ProjectRecord project) { Project = project; } public ProjectRecord Project { get; set; } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Projects/Update.cs ================================================ using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.UseCases.Projects; using NimblePros.SampleToDo.UseCases.Projects.Update; using NimblePros.SampleToDo.Web.Extensions; namespace NimblePros.SampleToDo.Web.Projects; public class Update(IMediator mediator) : Endpoint< UpdateProjectRequest, Results, NotFound, ProblemHttpResult>, UpdateProjectMapper> { private readonly IMediator _mediator = mediator; public override void Configure() { Put(UpdateProjectRequest.Route); AllowAnonymous(); // Optional but nice: enumerate for Swagger Summary(s => { s.Summary = "Update a project"; s.Description = "Updates an existing project's information. The project name must be between 2 and 100 characters long."; s.ExampleRequest = new UpdateProjectRequest { Id = 1, Name = "Updated Project Name" }; s.ResponseExamples[200] = new UpdateProjectResponse(new ProjectRecord(1, "Updated Project Name")); // Document possible responses s.Responses[200] = "Project updated successfully"; s.Responses[404] = "Project with specified ID not found"; s.Responses[400] = "Invalid input data or business rule violation"; }); // Add tags for API grouping Tags("Projects"); // Add additional metadata Description(builder => builder .Accepts("application/json") .Produces(200, "application/json") .ProducesProblem(404) .ProducesProblem(400)); } public override async Task, NotFound, ProblemHttpResult>> ExecuteAsync(UpdateProjectRequest request, CancellationToken ct) { var cmd = new UpdateProjectCommand( ProjectId.From(request.Id), ProjectName.From(request.Name!)); var result = await _mediator.Send(cmd, ct); return result.ToUpdateResult(Map.FromEntity); } } public sealed class UpdateProjectMapper : Mapper { public override UpdateProjectResponse FromEntity(ProjectDto e) => new(new ProjectRecord(e.Id, e.Name)); } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/Properties/launchSettings.json ================================================ { "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:57677/", "sslPort": 0 } }, "profiles": { "https": { "commandName": "Project", "dotnetRunMessages": true, "launchUrl": "swagger", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, "applicationUrl": "https://localhost:57678/" }, "IIS Express": { "commandName": "IISExpress", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/SeedData.cs ================================================ using NimblePros.SampleToDo.Core.ContributorAggregate; using NimblePros.SampleToDo.Core.ProjectAggregate; using NimblePros.SampleToDo.Infrastructure.Data; namespace NimblePros.SampleToDo.Web; public static class SeedData { public static readonly Contributor Contributor1 = new(ContributorName.From("Ardalis")); public static readonly Contributor Contributor2 = new(ContributorName.From("Snowfrog")); public static readonly Project TestProject1 = new Project(ProjectName.From("Test Project")); public static readonly ToDoItem ToDoItem1 = new ToDoItem(title: ToDoItemTitle.From("Get Sample Working"), description: ToDoItemDescription.From("Try to get the sample to build.")); public static readonly ToDoItem ToDoItem2 = new ToDoItem(title: ToDoItemTitle.From("Review Solution"), description: ToDoItemDescription.From("Review the different projects in the solution and how they relate to one another.")); public static readonly ToDoItem ToDoItem3 = new ToDoItem(title: ToDoItemTitle.From("Run and Review Tests"), description: ToDoItemDescription.From("Make sure all the tests run and review what they are doing.")); public static async Task InitializeAsync(AppDbContext dbContext) { if (await dbContext.ToDoItems.AnyAsync()) { return; // DB has been seeded } await PopulateTestDataAsync(dbContext); } public static async Task PopulateTestDataAsync(AppDbContext dbContext) { foreach (var item in dbContext.Projects) { dbContext.Remove(item); } foreach (var item in dbContext.ToDoItems) { dbContext.Remove(item); } foreach (var item in dbContext.Contributors) { dbContext.Remove(item); } await dbContext.SaveChangesAsync(); dbContext.Contributors.Add(Contributor1); dbContext.Contributors.Add(Contributor2); await dbContext.SaveChangesAsync(); ToDoItem1.AddContributor(Contributor1.Id); ToDoItem2.AddContributor(Contributor2.Id); ToDoItem3.AddContributor(Contributor1.Id); TestProject1.AddItem(ToDoItem1); TestProject1.AddItem(ToDoItem2); TestProject1.AddItem(ToDoItem3); dbContext.Projects.Add(TestProject1); await dbContext.SaveChangesAsync(); // add a bunch more contributors to support demonstrating paging for (int i = 1; i <= 25; i++) { dbContext.Contributors.Add(new Contributor(ContributorName.From($"Contributor {i}"))); } await dbContext.SaveChangesAsync(); } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/api.http ================================================ # For more info on HTTP files go to https://aka.ms/vs/httpfile @host=https://localhost @port=57678 // List all contributors GET {{host}}:{{port}}/Contributors ### // Get a specific contributor @id_to_get=1 GET {{host}}:{{port}}/Contributors/{{id_to_get}} ### // Add a new contributor POST {{host}}:{{port}}/Contributors Content-Type: application/json { "name": "John Doe 123", "email": "test@t2est.com", "phoneNumber": "1224567890" } ### // Update a contributor @id_to_update=1 PUT {{host}}:{{port}}/Contributors/{{id_to_update}} Content-Type: application/json { "id": {{id_to_update}}, "name": "ardalis" } ### // Delete a contributor @id_to_delete=5 DELETE {{host}}:{{port}}/Contributors/{{id_to_delete}} ### // List all Projects GET {{host}}:{{port}}/Projects ### // Get a specific project @projectId_to_get=1 GET {{host}}:{{port}}/Projects/{{projectId_to_get}} ### // Delete a specific project @projectId_to_delete=20 DELETE {{host}}:{{port}}/Projects/{{projectId_to_delete}} ### // Create a new project POST {{host}}:{{port}}/Projects Content-Type: application/json { "name": "New Project" } ### // Update project - specify id in body PUT {{host}}:{{port}}/Projects/ Content-Type: application/json { "id": 2, "name": "new name" } ### // Mark an item as complete @project_id=1 @item_id=2 POST {{host}}:{{port}}/Projects/{{project_id}}/ToDoItems/{{item_id}} Content-Type: application/json { } ### ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/appsettings.json ================================================ { "ConnectionStrings": { "DefaultConnection": "Server=(localdb)\\v11.0;Database=cleanarchitecture;Trusted_Connection=True;MultipleActiveResultSets=true", "SqliteConnection": "Data Source=database.sqlite" }, "Serilog": { "MinimumLevel": { "Default": "Information", "Override": { "NimblePros.SampleToDo": "Debug", "Microsoft" : "Warning" } }, "WriteTo": [ { "Name": "Console" }, { "Name": "File", "Args": { "path": "log.txt", "rollingInterval": "Day" } }, { "Name": "OpenTelemetry" } //Uncomment this section if you'd like to push your logs to Azure Application Insights //Full list of Serilog Sinks can be found here: https://github.com/serilog/serilog/wiki/Provided-Sinks //{ // "Name": "ApplicationInsights", // "Args": { // "instrumentationKey": "", //Fill in with your ApplicationInsights InstrumentationKey // "telemetryConverter": "Serilog.Sinks.ApplicationInsights.Sinks.ApplicationInsights.TelemetryConverters.TraceTelemetryConverter, Serilog.Sinks.ApplicationInsights" // } //} ] }, "Caching": { "DefaultDurationSeconds": 10, "Profiles": { "Short": 5, "Medium": 60, "Long": 300 } } } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/i18n/en/Project.json ================================================ { "CoreProjectNameEmpty": "Name cannot be empty", "CoreProjectNameTooLong": "Name cannot be longer than {0} characters", "CoreToDoItemDescriptionEmpty": "Description cannot be empty", "CoreToDoItemDescriptionTooLong": "Description cannot be longer than {0} characters", "CoreToDoItemTitleEmpty": "Title cannot be empty", "CoreToDoItemTitleTooLong": "Title cannot be longer than {0} characters" } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/i18n/fa/Project.json ================================================ { "CoreProjectNameEmpty": "نام نمی‌تواند خالی باشد", "CoreProjectNameTooLong": "نام نمی‌تواند بیش از {0} کاراکتر باشد", "CoreToDoItemDescriptionEmpty": "توضیحات نمی‌تواند خالی باشد", "CoreToDoItemDescriptionTooLong": "توضیحات نمی‌تواند بیش از {0} کاراکتر باشد", "CoreToDoItemTitleEmpty": "عنوان نمی‌تواند خالی باشد", "CoreToDoItemTitleTooLong": "عنوان نمی‌تواند بیش از {0} کاراکتر باشد" } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/i18n/fr/Project.json ================================================ { "CoreProjectNameEmpty": "Le nom ne peut pas être vide", "CoreProjectNameTooLong": "Le nom ne peut pas dépasser {0} caractères", "CoreToDoItemDescriptionEmpty": "La description ne peut pas être vide", "CoreToDoItemDescriptionTooLong": "La description ne peut pas dépasser {0} caractères", "CoreToDoItemTitleEmpty": "Le titre ne peut pas être vide", "CoreToDoItemTitleTooLong": "Le titre ne peut pas dépasser {0} caractères" } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/css/site.css ================================================ html { font-size: 14px; } @media (min-width: 768px) { html { font-size: 16px; } } html { position: relative; min-height: 100%; } body { margin-bottom: 60px; } ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/js/site.js ================================================ // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification // for details on configuring this project to bundle and minify static web assets. // Write your JavaScript code. ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2011-2021 Twitter, Inc. Copyright (c) 2011-2021 The Bootstrap Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.css ================================================ /*! * Bootstrap Grid 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) */ .container, .container-fluid, .container-xxl, .container-xl, .container-lg, .container-md, .container-sm { width: 100%; padding-right: var(--bs-gutter-x, 0.75rem); padding-left: var(--bs-gutter-x, 0.75rem); margin-right: auto; margin-left: auto; } @media (min-width: 576px) { .container-sm, .container { max-width: 540px; } } @media (min-width: 768px) { .container-md, .container-sm, .container { max-width: 720px; } } @media (min-width: 992px) { .container-lg, .container-md, .container-sm, .container { max-width: 960px; } } @media (min-width: 1200px) { .container-xl, .container-lg, .container-md, .container-sm, .container { max-width: 1140px; } } @media (min-width: 1400px) { .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container { 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 > * { box-sizing: border-box; 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; } } .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; } .flex-fill { flex: 1 1 auto !important; } .flex-row { flex-direction: row !important; } .flex-column { flex-direction: column !important; } .flex-row-reverse { flex-direction: row-reverse !important; } .flex-column-reverse { flex-direction: column-reverse !important; } .flex-grow-0 { flex-grow: 0 !important; } .flex-grow-1 { flex-grow: 1 !important; } .flex-shrink-0 { flex-shrink: 0 !important; } .flex-shrink-1 { flex-shrink: 1 !important; } .flex-wrap { flex-wrap: wrap !important; } .flex-nowrap { flex-wrap: nowrap !important; } .flex-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-start { justify-content: flex-start !important; } .justify-content-end { justify-content: flex-end !important; } .justify-content-center { justify-content: center !important; } .justify-content-between { justify-content: space-between !important; } .justify-content-around { justify-content: space-around !important; } .justify-content-evenly { justify-content: space-evenly !important; } .align-items-start { align-items: flex-start !important; } .align-items-end { align-items: flex-end !important; } .align-items-center { align-items: center !important; } .align-items-baseline { align-items: baseline !important; } .align-items-stretch { align-items: stretch !important; } .align-content-start { align-content: flex-start !important; } .align-content-end { align-content: flex-end !important; } .align-content-center { align-content: center !important; } .align-content-between { align-content: space-between !important; } .align-content-around { align-content: space-around !important; } .align-content-stretch { align-content: stretch !important; } .align-self-auto { align-self: auto !important; } .align-self-start { align-self: flex-start !important; } .align-self-end { align-self: flex-end !important; } .align-self-center { align-self: center !important; } .align-self-baseline { align-self: baseline !important; } .align-self-stretch { align-self: stretch !important; } .order-first { order: -1 !important; } .order-0 { order: 0 !important; } .order-1 { order: 1 !important; } .order-2 { order: 2 !important; } .order-3 { order: 3 !important; } .order-4 { order: 4 !important; } .order-5 { order: 5 !important; } .order-last { order: 6 !important; } .m-0 { margin: 0 !important; } .m-1 { margin: 0.25rem !important; } .m-2 { margin: 0.5rem !important; } .m-3 { margin: 1rem !important; } .m-4 { margin: 1.5rem !important; } .m-5 { margin: 3rem !important; } .m-auto { margin: auto !important; } .mx-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-5 { margin-top: 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: 0.25rem !important; } .mt-2 { margin-top: 0.5rem !important; } .mt-3 { margin-top: 1rem !important; } .mt-4 { margin-top: 1.5rem !important; } .mt-5 { margin-top: 3rem !important; } .mt-auto { margin-top: auto !important; } .me-0 { margin-right: 0 !important; } .me-1 { margin-right: 0.25rem !important; } .me-2 { margin-right: 0.5rem !important; } .me-3 { margin-right: 1rem !important; } .me-4 { margin-right: 1.5rem !important; } .me-5 { margin-right: 3rem !important; } .me-auto { margin-right: auto !important; } .mb-0 { margin-bottom: 0 !important; } .mb-1 { margin-bottom: 0.25rem !important; } .mb-2 { margin-bottom: 0.5rem !important; } .mb-3 { margin-bottom: 1rem !important; } .mb-4 { margin-bottom: 1.5rem !important; } .mb-5 { margin-bottom: 3rem !important; } .mb-auto { margin-bottom: auto !important; } .ms-0 { margin-left: 0 !important; } .ms-1 { margin-left: 0.25rem !important; } .ms-2 { margin-left: 0.5rem !important; } .ms-3 { margin-left: 1rem !important; } .ms-4 { margin-left: 1.5rem !important; } .ms-5 { margin-left: 3rem !important; } .ms-auto { margin-left: auto !important; } .p-0 { padding: 0 !important; } .p-1 { padding: 0.25rem !important; } .p-2 { padding: 0.5rem !important; } .p-3 { padding: 1rem !important; } .p-4 { padding: 1.5rem !important; } .p-5 { padding: 3rem !important; } .px-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-0 { padding-top: 0 !important; } .pt-1 { padding-top: 0.25rem !important; } .pt-2 { padding-top: 0.5rem !important; } .pt-3 { padding-top: 1rem !important; } .pt-4 { padding-top: 1.5rem !important; } .pt-5 { padding-top: 3rem !important; } .pe-0 { padding-right: 0 !important; } .pe-1 { padding-right: 0.25rem !important; } .pe-2 { padding-right: 0.5rem !important; } .pe-3 { padding-right: 1rem !important; } .pe-4 { padding-right: 1.5rem !important; } .pe-5 { padding-right: 3rem !important; } .pb-0 { padding-bottom: 0 !important; } .pb-1 { padding-bottom: 0.25rem !important; } .pb-2 { padding-bottom: 0.5rem !important; } .pb-3 { padding-bottom: 1rem !important; } .pb-4 { padding-bottom: 1.5rem !important; } .pb-5 { padding-bottom: 3rem !important; } .ps-0 { padding-left: 0 !important; } .ps-1 { padding-left: 0.25rem !important; } .ps-2 { padding-left: 0.5rem !important; } .ps-3 { padding-left: 1rem !important; } .ps-4 { padding-left: 1.5rem !important; } .ps-5 { padding-left: 3rem !important; } @media (min-width: 576px) { .d-sm-inline { display: inline !important; } .d-sm-inline-block { display: inline-block !important; } .d-sm-block { display: block !important; } .d-sm-grid { display: grid !important; } .d-sm-table { display: table !important; } .d-sm-table-row { display: table-row !important; } .d-sm-table-cell { display: table-cell !important; } .d-sm-flex { display: flex !important; } .d-sm-inline-flex { display: inline-flex !important; } .d-sm-none { display: none !important; } .flex-sm-fill { flex: 1 1 auto !important; } .flex-sm-row { flex-direction: row !important; } .flex-sm-column { flex-direction: column !important; } .flex-sm-row-reverse { flex-direction: row-reverse !important; } .flex-sm-column-reverse { flex-direction: column-reverse !important; } .flex-sm-grow-0 { flex-grow: 0 !important; } .flex-sm-grow-1 { flex-grow: 1 !important; } .flex-sm-shrink-0 { flex-shrink: 0 !important; } .flex-sm-shrink-1 { flex-shrink: 1 !important; } .flex-sm-wrap { flex-wrap: wrap !important; } .flex-sm-nowrap { flex-wrap: nowrap !important; } .flex-sm-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-sm-start { justify-content: flex-start !important; } .justify-content-sm-end { justify-content: flex-end !important; } .justify-content-sm-center { justify-content: center !important; } .justify-content-sm-between { justify-content: space-between !important; } .justify-content-sm-around { justify-content: space-around !important; } .justify-content-sm-evenly { justify-content: space-evenly !important; } .align-items-sm-start { align-items: flex-start !important; } .align-items-sm-end { align-items: flex-end !important; } .align-items-sm-center { align-items: center !important; } .align-items-sm-baseline { align-items: baseline !important; } .align-items-sm-stretch { align-items: stretch !important; } .align-content-sm-start { align-content: flex-start !important; } .align-content-sm-end { align-content: flex-end !important; } .align-content-sm-center { align-content: center !important; } .align-content-sm-between { align-content: space-between !important; } .align-content-sm-around { align-content: space-around !important; } .align-content-sm-stretch { align-content: stretch !important; } .align-self-sm-auto { align-self: auto !important; } .align-self-sm-start { align-self: flex-start !important; } .align-self-sm-end { align-self: flex-end !important; } .align-self-sm-center { align-self: center !important; } .align-self-sm-baseline { align-self: baseline !important; } .align-self-sm-stretch { align-self: stretch !important; } .order-sm-first { order: -1 !important; } .order-sm-0 { order: 0 !important; } .order-sm-1 { order: 1 !important; } .order-sm-2 { order: 2 !important; } .order-sm-3 { order: 3 !important; } .order-sm-4 { order: 4 !important; } .order-sm-5 { order: 5 !important; } .order-sm-last { order: 6 !important; } .m-sm-0 { margin: 0 !important; } .m-sm-1 { margin: 0.25rem !important; } .m-sm-2 { margin: 0.5rem !important; } .m-sm-3 { margin: 1rem !important; } .m-sm-4 { margin: 1.5rem !important; } .m-sm-5 { margin: 3rem !important; } .m-sm-auto { margin: auto !important; } .mx-sm-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-sm-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-sm-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-sm-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-sm-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-sm-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-sm-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-sm-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-sm-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-sm-5 { margin-top: 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: 0.25rem !important; } .mt-sm-2 { margin-top: 0.5rem !important; } .mt-sm-3 { margin-top: 1rem !important; } .mt-sm-4 { margin-top: 1.5rem !important; } .mt-sm-5 { margin-top: 3rem !important; } .mt-sm-auto { margin-top: auto !important; } .me-sm-0 { margin-right: 0 !important; } .me-sm-1 { margin-right: 0.25rem !important; } .me-sm-2 { margin-right: 0.5rem !important; } .me-sm-3 { margin-right: 1rem !important; } .me-sm-4 { margin-right: 1.5rem !important; } .me-sm-5 { margin-right: 3rem !important; } .me-sm-auto { margin-right: auto !important; } .mb-sm-0 { margin-bottom: 0 !important; } .mb-sm-1 { margin-bottom: 0.25rem !important; } .mb-sm-2 { margin-bottom: 0.5rem !important; } .mb-sm-3 { margin-bottom: 1rem !important; } .mb-sm-4 { margin-bottom: 1.5rem !important; } .mb-sm-5 { margin-bottom: 3rem !important; } .mb-sm-auto { margin-bottom: auto !important; } .ms-sm-0 { margin-left: 0 !important; } .ms-sm-1 { margin-left: 0.25rem !important; } .ms-sm-2 { margin-left: 0.5rem !important; } .ms-sm-3 { margin-left: 1rem !important; } .ms-sm-4 { margin-left: 1.5rem !important; } .ms-sm-5 { margin-left: 3rem !important; } .ms-sm-auto { margin-left: auto !important; } .p-sm-0 { padding: 0 !important; } .p-sm-1 { padding: 0.25rem !important; } .p-sm-2 { padding: 0.5rem !important; } .p-sm-3 { padding: 1rem !important; } .p-sm-4 { padding: 1.5rem !important; } .p-sm-5 { padding: 3rem !important; } .px-sm-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-sm-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-sm-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-sm-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-sm-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-sm-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-sm-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-sm-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-sm-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-sm-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-sm-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-sm-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-sm-0 { padding-top: 0 !important; } .pt-sm-1 { padding-top: 0.25rem !important; } .pt-sm-2 { padding-top: 0.5rem !important; } .pt-sm-3 { padding-top: 1rem !important; } .pt-sm-4 { padding-top: 1.5rem !important; } .pt-sm-5 { padding-top: 3rem !important; } .pe-sm-0 { padding-right: 0 !important; } .pe-sm-1 { padding-right: 0.25rem !important; } .pe-sm-2 { padding-right: 0.5rem !important; } .pe-sm-3 { padding-right: 1rem !important; } .pe-sm-4 { padding-right: 1.5rem !important; } .pe-sm-5 { padding-right: 3rem !important; } .pb-sm-0 { padding-bottom: 0 !important; } .pb-sm-1 { padding-bottom: 0.25rem !important; } .pb-sm-2 { padding-bottom: 0.5rem !important; } .pb-sm-3 { padding-bottom: 1rem !important; } .pb-sm-4 { padding-bottom: 1.5rem !important; } .pb-sm-5 { padding-bottom: 3rem !important; } .ps-sm-0 { padding-left: 0 !important; } .ps-sm-1 { padding-left: 0.25rem !important; } .ps-sm-2 { padding-left: 0.5rem !important; } .ps-sm-3 { padding-left: 1rem !important; } .ps-sm-4 { padding-left: 1.5rem !important; } .ps-sm-5 { padding-left: 3rem !important; } } @media (min-width: 768px) { .d-md-inline { display: inline !important; } .d-md-inline-block { display: inline-block !important; } .d-md-block { display: block !important; } .d-md-grid { display: grid !important; } .d-md-table { display: table !important; } .d-md-table-row { display: table-row !important; } .d-md-table-cell { display: table-cell !important; } .d-md-flex { display: flex !important; } .d-md-inline-flex { display: inline-flex !important; } .d-md-none { display: none !important; } .flex-md-fill { flex: 1 1 auto !important; } .flex-md-row { flex-direction: row !important; } .flex-md-column { flex-direction: column !important; } .flex-md-row-reverse { flex-direction: row-reverse !important; } .flex-md-column-reverse { flex-direction: column-reverse !important; } .flex-md-grow-0 { flex-grow: 0 !important; } .flex-md-grow-1 { flex-grow: 1 !important; } .flex-md-shrink-0 { flex-shrink: 0 !important; } .flex-md-shrink-1 { flex-shrink: 1 !important; } .flex-md-wrap { flex-wrap: wrap !important; } .flex-md-nowrap { flex-wrap: nowrap !important; } .flex-md-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-md-start { justify-content: flex-start !important; } .justify-content-md-end { justify-content: flex-end !important; } .justify-content-md-center { justify-content: center !important; } .justify-content-md-between { justify-content: space-between !important; } .justify-content-md-around { justify-content: space-around !important; } .justify-content-md-evenly { justify-content: space-evenly !important; } .align-items-md-start { align-items: flex-start !important; } .align-items-md-end { align-items: flex-end !important; } .align-items-md-center { align-items: center !important; } .align-items-md-baseline { align-items: baseline !important; } .align-items-md-stretch { align-items: stretch !important; } .align-content-md-start { align-content: flex-start !important; } .align-content-md-end { align-content: flex-end !important; } .align-content-md-center { align-content: center !important; } .align-content-md-between { align-content: space-between !important; } .align-content-md-around { align-content: space-around !important; } .align-content-md-stretch { align-content: stretch !important; } .align-self-md-auto { align-self: auto !important; } .align-self-md-start { align-self: flex-start !important; } .align-self-md-end { align-self: flex-end !important; } .align-self-md-center { align-self: center !important; } .align-self-md-baseline { align-self: baseline !important; } .align-self-md-stretch { align-self: stretch !important; } .order-md-first { order: -1 !important; } .order-md-0 { order: 0 !important; } .order-md-1 { order: 1 !important; } .order-md-2 { order: 2 !important; } .order-md-3 { order: 3 !important; } .order-md-4 { order: 4 !important; } .order-md-5 { order: 5 !important; } .order-md-last { order: 6 !important; } .m-md-0 { margin: 0 !important; } .m-md-1 { margin: 0.25rem !important; } .m-md-2 { margin: 0.5rem !important; } .m-md-3 { margin: 1rem !important; } .m-md-4 { margin: 1.5rem !important; } .m-md-5 { margin: 3rem !important; } .m-md-auto { margin: auto !important; } .mx-md-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-md-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-md-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-md-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-md-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-md-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-md-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-md-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-md-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-md-5 { margin-top: 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: 0.25rem !important; } .mt-md-2 { margin-top: 0.5rem !important; } .mt-md-3 { margin-top: 1rem !important; } .mt-md-4 { margin-top: 1.5rem !important; } .mt-md-5 { margin-top: 3rem !important; } .mt-md-auto { margin-top: auto !important; } .me-md-0 { margin-right: 0 !important; } .me-md-1 { margin-right: 0.25rem !important; } .me-md-2 { margin-right: 0.5rem !important; } .me-md-3 { margin-right: 1rem !important; } .me-md-4 { margin-right: 1.5rem !important; } .me-md-5 { margin-right: 3rem !important; } .me-md-auto { margin-right: auto !important; } .mb-md-0 { margin-bottom: 0 !important; } .mb-md-1 { margin-bottom: 0.25rem !important; } .mb-md-2 { margin-bottom: 0.5rem !important; } .mb-md-3 { margin-bottom: 1rem !important; } .mb-md-4 { margin-bottom: 1.5rem !important; } .mb-md-5 { margin-bottom: 3rem !important; } .mb-md-auto { margin-bottom: auto !important; } .ms-md-0 { margin-left: 0 !important; } .ms-md-1 { margin-left: 0.25rem !important; } .ms-md-2 { margin-left: 0.5rem !important; } .ms-md-3 { margin-left: 1rem !important; } .ms-md-4 { margin-left: 1.5rem !important; } .ms-md-5 { margin-left: 3rem !important; } .ms-md-auto { margin-left: auto !important; } .p-md-0 { padding: 0 !important; } .p-md-1 { padding: 0.25rem !important; } .p-md-2 { padding: 0.5rem !important; } .p-md-3 { padding: 1rem !important; } .p-md-4 { padding: 1.5rem !important; } .p-md-5 { padding: 3rem !important; } .px-md-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-md-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-md-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-md-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-md-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-md-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-md-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-md-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-md-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-md-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-md-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-md-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-md-0 { padding-top: 0 !important; } .pt-md-1 { padding-top: 0.25rem !important; } .pt-md-2 { padding-top: 0.5rem !important; } .pt-md-3 { padding-top: 1rem !important; } .pt-md-4 { padding-top: 1.5rem !important; } .pt-md-5 { padding-top: 3rem !important; } .pe-md-0 { padding-right: 0 !important; } .pe-md-1 { padding-right: 0.25rem !important; } .pe-md-2 { padding-right: 0.5rem !important; } .pe-md-3 { padding-right: 1rem !important; } .pe-md-4 { padding-right: 1.5rem !important; } .pe-md-5 { padding-right: 3rem !important; } .pb-md-0 { padding-bottom: 0 !important; } .pb-md-1 { padding-bottom: 0.25rem !important; } .pb-md-2 { padding-bottom: 0.5rem !important; } .pb-md-3 { padding-bottom: 1rem !important; } .pb-md-4 { padding-bottom: 1.5rem !important; } .pb-md-5 { padding-bottom: 3rem !important; } .ps-md-0 { padding-left: 0 !important; } .ps-md-1 { padding-left: 0.25rem !important; } .ps-md-2 { padding-left: 0.5rem !important; } .ps-md-3 { padding-left: 1rem !important; } .ps-md-4 { padding-left: 1.5rem !important; } .ps-md-5 { padding-left: 3rem !important; } } @media (min-width: 992px) { .d-lg-inline { display: inline !important; } .d-lg-inline-block { display: inline-block !important; } .d-lg-block { display: block !important; } .d-lg-grid { display: grid !important; } .d-lg-table { display: table !important; } .d-lg-table-row { display: table-row !important; } .d-lg-table-cell { display: table-cell !important; } .d-lg-flex { display: flex !important; } .d-lg-inline-flex { display: inline-flex !important; } .d-lg-none { display: none !important; } .flex-lg-fill { flex: 1 1 auto !important; } .flex-lg-row { flex-direction: row !important; } .flex-lg-column { flex-direction: column !important; } .flex-lg-row-reverse { flex-direction: row-reverse !important; } .flex-lg-column-reverse { flex-direction: column-reverse !important; } .flex-lg-grow-0 { flex-grow: 0 !important; } .flex-lg-grow-1 { flex-grow: 1 !important; } .flex-lg-shrink-0 { flex-shrink: 0 !important; } .flex-lg-shrink-1 { flex-shrink: 1 !important; } .flex-lg-wrap { flex-wrap: wrap !important; } .flex-lg-nowrap { flex-wrap: nowrap !important; } .flex-lg-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-lg-start { justify-content: flex-start !important; } .justify-content-lg-end { justify-content: flex-end !important; } .justify-content-lg-center { justify-content: center !important; } .justify-content-lg-between { justify-content: space-between !important; } .justify-content-lg-around { justify-content: space-around !important; } .justify-content-lg-evenly { justify-content: space-evenly !important; } .align-items-lg-start { align-items: flex-start !important; } .align-items-lg-end { align-items: flex-end !important; } .align-items-lg-center { align-items: center !important; } .align-items-lg-baseline { align-items: baseline !important; } .align-items-lg-stretch { align-items: stretch !important; } .align-content-lg-start { align-content: flex-start !important; } .align-content-lg-end { align-content: flex-end !important; } .align-content-lg-center { align-content: center !important; } .align-content-lg-between { align-content: space-between !important; } .align-content-lg-around { align-content: space-around !important; } .align-content-lg-stretch { align-content: stretch !important; } .align-self-lg-auto { align-self: auto !important; } .align-self-lg-start { align-self: flex-start !important; } .align-self-lg-end { align-self: flex-end !important; } .align-self-lg-center { align-self: center !important; } .align-self-lg-baseline { align-self: baseline !important; } .align-self-lg-stretch { align-self: stretch !important; } .order-lg-first { order: -1 !important; } .order-lg-0 { order: 0 !important; } .order-lg-1 { order: 1 !important; } .order-lg-2 { order: 2 !important; } .order-lg-3 { order: 3 !important; } .order-lg-4 { order: 4 !important; } .order-lg-5 { order: 5 !important; } .order-lg-last { order: 6 !important; } .m-lg-0 { margin: 0 !important; } .m-lg-1 { margin: 0.25rem !important; } .m-lg-2 { margin: 0.5rem !important; } .m-lg-3 { margin: 1rem !important; } .m-lg-4 { margin: 1.5rem !important; } .m-lg-5 { margin: 3rem !important; } .m-lg-auto { margin: auto !important; } .mx-lg-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-lg-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-lg-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-lg-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-lg-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-lg-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-lg-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-lg-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-lg-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-lg-5 { margin-top: 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: 0.25rem !important; } .mt-lg-2 { margin-top: 0.5rem !important; } .mt-lg-3 { margin-top: 1rem !important; } .mt-lg-4 { margin-top: 1.5rem !important; } .mt-lg-5 { margin-top: 3rem !important; } .mt-lg-auto { margin-top: auto !important; } .me-lg-0 { margin-right: 0 !important; } .me-lg-1 { margin-right: 0.25rem !important; } .me-lg-2 { margin-right: 0.5rem !important; } .me-lg-3 { margin-right: 1rem !important; } .me-lg-4 { margin-right: 1.5rem !important; } .me-lg-5 { margin-right: 3rem !important; } .me-lg-auto { margin-right: auto !important; } .mb-lg-0 { margin-bottom: 0 !important; } .mb-lg-1 { margin-bottom: 0.25rem !important; } .mb-lg-2 { margin-bottom: 0.5rem !important; } .mb-lg-3 { margin-bottom: 1rem !important; } .mb-lg-4 { margin-bottom: 1.5rem !important; } .mb-lg-5 { margin-bottom: 3rem !important; } .mb-lg-auto { margin-bottom: auto !important; } .ms-lg-0 { margin-left: 0 !important; } .ms-lg-1 { margin-left: 0.25rem !important; } .ms-lg-2 { margin-left: 0.5rem !important; } .ms-lg-3 { margin-left: 1rem !important; } .ms-lg-4 { margin-left: 1.5rem !important; } .ms-lg-5 { margin-left: 3rem !important; } .ms-lg-auto { margin-left: auto !important; } .p-lg-0 { padding: 0 !important; } .p-lg-1 { padding: 0.25rem !important; } .p-lg-2 { padding: 0.5rem !important; } .p-lg-3 { padding: 1rem !important; } .p-lg-4 { padding: 1.5rem !important; } .p-lg-5 { padding: 3rem !important; } .px-lg-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-lg-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-lg-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-lg-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-lg-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-lg-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-lg-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-lg-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-lg-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-lg-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-lg-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-lg-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-lg-0 { padding-top: 0 !important; } .pt-lg-1 { padding-top: 0.25rem !important; } .pt-lg-2 { padding-top: 0.5rem !important; } .pt-lg-3 { padding-top: 1rem !important; } .pt-lg-4 { padding-top: 1.5rem !important; } .pt-lg-5 { padding-top: 3rem !important; } .pe-lg-0 { padding-right: 0 !important; } .pe-lg-1 { padding-right: 0.25rem !important; } .pe-lg-2 { padding-right: 0.5rem !important; } .pe-lg-3 { padding-right: 1rem !important; } .pe-lg-4 { padding-right: 1.5rem !important; } .pe-lg-5 { padding-right: 3rem !important; } .pb-lg-0 { padding-bottom: 0 !important; } .pb-lg-1 { padding-bottom: 0.25rem !important; } .pb-lg-2 { padding-bottom: 0.5rem !important; } .pb-lg-3 { padding-bottom: 1rem !important; } .pb-lg-4 { padding-bottom: 1.5rem !important; } .pb-lg-5 { padding-bottom: 3rem !important; } .ps-lg-0 { padding-left: 0 !important; } .ps-lg-1 { padding-left: 0.25rem !important; } .ps-lg-2 { padding-left: 0.5rem !important; } .ps-lg-3 { padding-left: 1rem !important; } .ps-lg-4 { padding-left: 1.5rem !important; } .ps-lg-5 { padding-left: 3rem !important; } } @media (min-width: 1200px) { .d-xl-inline { display: inline !important; } .d-xl-inline-block { display: inline-block !important; } .d-xl-block { display: block !important; } .d-xl-grid { display: grid !important; } .d-xl-table { display: table !important; } .d-xl-table-row { display: table-row !important; } .d-xl-table-cell { display: table-cell !important; } .d-xl-flex { display: flex !important; } .d-xl-inline-flex { display: inline-flex !important; } .d-xl-none { display: none !important; } .flex-xl-fill { flex: 1 1 auto !important; } .flex-xl-row { flex-direction: row !important; } .flex-xl-column { flex-direction: column !important; } .flex-xl-row-reverse { flex-direction: row-reverse !important; } .flex-xl-column-reverse { flex-direction: column-reverse !important; } .flex-xl-grow-0 { flex-grow: 0 !important; } .flex-xl-grow-1 { flex-grow: 1 !important; } .flex-xl-shrink-0 { flex-shrink: 0 !important; } .flex-xl-shrink-1 { flex-shrink: 1 !important; } .flex-xl-wrap { flex-wrap: wrap !important; } .flex-xl-nowrap { flex-wrap: nowrap !important; } .flex-xl-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-xl-start { justify-content: flex-start !important; } .justify-content-xl-end { justify-content: flex-end !important; } .justify-content-xl-center { justify-content: center !important; } .justify-content-xl-between { justify-content: space-between !important; } .justify-content-xl-around { justify-content: space-around !important; } .justify-content-xl-evenly { justify-content: space-evenly !important; } .align-items-xl-start { align-items: flex-start !important; } .align-items-xl-end { align-items: flex-end !important; } .align-items-xl-center { align-items: center !important; } .align-items-xl-baseline { align-items: baseline !important; } .align-items-xl-stretch { align-items: stretch !important; } .align-content-xl-start { align-content: flex-start !important; } .align-content-xl-end { align-content: flex-end !important; } .align-content-xl-center { align-content: center !important; } .align-content-xl-between { align-content: space-between !important; } .align-content-xl-around { align-content: space-around !important; } .align-content-xl-stretch { align-content: stretch !important; } .align-self-xl-auto { align-self: auto !important; } .align-self-xl-start { align-self: flex-start !important; } .align-self-xl-end { align-self: flex-end !important; } .align-self-xl-center { align-self: center !important; } .align-self-xl-baseline { align-self: baseline !important; } .align-self-xl-stretch { align-self: stretch !important; } .order-xl-first { order: -1 !important; } .order-xl-0 { order: 0 !important; } .order-xl-1 { order: 1 !important; } .order-xl-2 { order: 2 !important; } .order-xl-3 { order: 3 !important; } .order-xl-4 { order: 4 !important; } .order-xl-5 { order: 5 !important; } .order-xl-last { order: 6 !important; } .m-xl-0 { margin: 0 !important; } .m-xl-1 { margin: 0.25rem !important; } .m-xl-2 { margin: 0.5rem !important; } .m-xl-3 { margin: 1rem !important; } .m-xl-4 { margin: 1.5rem !important; } .m-xl-5 { margin: 3rem !important; } .m-xl-auto { margin: auto !important; } .mx-xl-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-xl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-xl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-xl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-xl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-xl-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xl-5 { margin-top: 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: 0.25rem !important; } .mt-xl-2 { margin-top: 0.5rem !important; } .mt-xl-3 { margin-top: 1rem !important; } .mt-xl-4 { margin-top: 1.5rem !important; } .mt-xl-5 { margin-top: 3rem !important; } .mt-xl-auto { margin-top: auto !important; } .me-xl-0 { margin-right: 0 !important; } .me-xl-1 { margin-right: 0.25rem !important; } .me-xl-2 { margin-right: 0.5rem !important; } .me-xl-3 { margin-right: 1rem !important; } .me-xl-4 { margin-right: 1.5rem !important; } .me-xl-5 { margin-right: 3rem !important; } .me-xl-auto { margin-right: auto !important; } .mb-xl-0 { margin-bottom: 0 !important; } .mb-xl-1 { margin-bottom: 0.25rem !important; } .mb-xl-2 { margin-bottom: 0.5rem !important; } .mb-xl-3 { margin-bottom: 1rem !important; } .mb-xl-4 { margin-bottom: 1.5rem !important; } .mb-xl-5 { margin-bottom: 3rem !important; } .mb-xl-auto { margin-bottom: auto !important; } .ms-xl-0 { margin-left: 0 !important; } .ms-xl-1 { margin-left: 0.25rem !important; } .ms-xl-2 { margin-left: 0.5rem !important; } .ms-xl-3 { margin-left: 1rem !important; } .ms-xl-4 { margin-left: 1.5rem !important; } .ms-xl-5 { margin-left: 3rem !important; } .ms-xl-auto { margin-left: auto !important; } .p-xl-0 { padding: 0 !important; } .p-xl-1 { padding: 0.25rem !important; } .p-xl-2 { padding: 0.5rem !important; } .p-xl-3 { padding: 1rem !important; } .p-xl-4 { padding: 1.5rem !important; } .p-xl-5 { padding: 3rem !important; } .px-xl-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-xl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-xl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-xl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-xl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-xl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-xl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xl-0 { padding-top: 0 !important; } .pt-xl-1 { padding-top: 0.25rem !important; } .pt-xl-2 { padding-top: 0.5rem !important; } .pt-xl-3 { padding-top: 1rem !important; } .pt-xl-4 { padding-top: 1.5rem !important; } .pt-xl-5 { padding-top: 3rem !important; } .pe-xl-0 { padding-right: 0 !important; } .pe-xl-1 { padding-right: 0.25rem !important; } .pe-xl-2 { padding-right: 0.5rem !important; } .pe-xl-3 { padding-right: 1rem !important; } .pe-xl-4 { padding-right: 1.5rem !important; } .pe-xl-5 { padding-right: 3rem !important; } .pb-xl-0 { padding-bottom: 0 !important; } .pb-xl-1 { padding-bottom: 0.25rem !important; } .pb-xl-2 { padding-bottom: 0.5rem !important; } .pb-xl-3 { padding-bottom: 1rem !important; } .pb-xl-4 { padding-bottom: 1.5rem !important; } .pb-xl-5 { padding-bottom: 3rem !important; } .ps-xl-0 { padding-left: 0 !important; } .ps-xl-1 { padding-left: 0.25rem !important; } .ps-xl-2 { padding-left: 0.5rem !important; } .ps-xl-3 { padding-left: 1rem !important; } .ps-xl-4 { padding-left: 1.5rem !important; } .ps-xl-5 { padding-left: 3rem !important; } } @media (min-width: 1400px) { .d-xxl-inline { display: inline !important; } .d-xxl-inline-block { display: inline-block !important; } .d-xxl-block { display: block !important; } .d-xxl-grid { display: grid !important; } .d-xxl-table { display: table !important; } .d-xxl-table-row { display: table-row !important; } .d-xxl-table-cell { display: table-cell !important; } .d-xxl-flex { display: flex !important; } .d-xxl-inline-flex { display: inline-flex !important; } .d-xxl-none { display: none !important; } .flex-xxl-fill { flex: 1 1 auto !important; } .flex-xxl-row { flex-direction: row !important; } .flex-xxl-column { flex-direction: column !important; } .flex-xxl-row-reverse { flex-direction: row-reverse !important; } .flex-xxl-column-reverse { flex-direction: column-reverse !important; } .flex-xxl-grow-0 { flex-grow: 0 !important; } .flex-xxl-grow-1 { flex-grow: 1 !important; } .flex-xxl-shrink-0 { flex-shrink: 0 !important; } .flex-xxl-shrink-1 { flex-shrink: 1 !important; } .flex-xxl-wrap { flex-wrap: wrap !important; } .flex-xxl-nowrap { flex-wrap: nowrap !important; } .flex-xxl-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-xxl-start { justify-content: flex-start !important; } .justify-content-xxl-end { justify-content: flex-end !important; } .justify-content-xxl-center { justify-content: center !important; } .justify-content-xxl-between { justify-content: space-between !important; } .justify-content-xxl-around { justify-content: space-around !important; } .justify-content-xxl-evenly { justify-content: space-evenly !important; } .align-items-xxl-start { align-items: flex-start !important; } .align-items-xxl-end { align-items: flex-end !important; } .align-items-xxl-center { align-items: center !important; } .align-items-xxl-baseline { align-items: baseline !important; } .align-items-xxl-stretch { align-items: stretch !important; } .align-content-xxl-start { align-content: flex-start !important; } .align-content-xxl-end { align-content: flex-end !important; } .align-content-xxl-center { align-content: center !important; } .align-content-xxl-between { align-content: space-between !important; } .align-content-xxl-around { align-content: space-around !important; } .align-content-xxl-stretch { align-content: stretch !important; } .align-self-xxl-auto { align-self: auto !important; } .align-self-xxl-start { align-self: flex-start !important; } .align-self-xxl-end { align-self: flex-end !important; } .align-self-xxl-center { align-self: center !important; } .align-self-xxl-baseline { align-self: baseline !important; } .align-self-xxl-stretch { align-self: stretch !important; } .order-xxl-first { order: -1 !important; } .order-xxl-0 { order: 0 !important; } .order-xxl-1 { order: 1 !important; } .order-xxl-2 { order: 2 !important; } .order-xxl-3 { order: 3 !important; } .order-xxl-4 { order: 4 !important; } .order-xxl-5 { order: 5 !important; } .order-xxl-last { order: 6 !important; } .m-xxl-0 { margin: 0 !important; } .m-xxl-1 { margin: 0.25rem !important; } .m-xxl-2 { margin: 0.5rem !important; } .m-xxl-3 { margin: 1rem !important; } .m-xxl-4 { margin: 1.5rem !important; } .m-xxl-5 { margin: 3rem !important; } .m-xxl-auto { margin: auto !important; } .mx-xxl-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-xxl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-xxl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-xxl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-xxl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-xxl-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xxl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xxl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xxl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xxl-5 { margin-top: 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: 0.25rem !important; } .mt-xxl-2 { margin-top: 0.5rem !important; } .mt-xxl-3 { margin-top: 1rem !important; } .mt-xxl-4 { margin-top: 1.5rem !important; } .mt-xxl-5 { margin-top: 3rem !important; } .mt-xxl-auto { margin-top: auto !important; } .me-xxl-0 { margin-right: 0 !important; } .me-xxl-1 { margin-right: 0.25rem !important; } .me-xxl-2 { margin-right: 0.5rem !important; } .me-xxl-3 { margin-right: 1rem !important; } .me-xxl-4 { margin-right: 1.5rem !important; } .me-xxl-5 { margin-right: 3rem !important; } .me-xxl-auto { margin-right: auto !important; } .mb-xxl-0 { margin-bottom: 0 !important; } .mb-xxl-1 { margin-bottom: 0.25rem !important; } .mb-xxl-2 { margin-bottom: 0.5rem !important; } .mb-xxl-3 { margin-bottom: 1rem !important; } .mb-xxl-4 { margin-bottom: 1.5rem !important; } .mb-xxl-5 { margin-bottom: 3rem !important; } .mb-xxl-auto { margin-bottom: auto !important; } .ms-xxl-0 { margin-left: 0 !important; } .ms-xxl-1 { margin-left: 0.25rem !important; } .ms-xxl-2 { margin-left: 0.5rem !important; } .ms-xxl-3 { margin-left: 1rem !important; } .ms-xxl-4 { margin-left: 1.5rem !important; } .ms-xxl-5 { margin-left: 3rem !important; } .ms-xxl-auto { margin-left: auto !important; } .p-xxl-0 { padding: 0 !important; } .p-xxl-1 { padding: 0.25rem !important; } .p-xxl-2 { padding: 0.5rem !important; } .p-xxl-3 { padding: 1rem !important; } .p-xxl-4 { padding: 1.5rem !important; } .p-xxl-5 { padding: 3rem !important; } .px-xxl-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-xxl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-xxl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-xxl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-xxl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-xxl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-xxl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xxl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xxl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xxl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xxl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xxl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xxl-0 { padding-top: 0 !important; } .pt-xxl-1 { padding-top: 0.25rem !important; } .pt-xxl-2 { padding-top: 0.5rem !important; } .pt-xxl-3 { padding-top: 1rem !important; } .pt-xxl-4 { padding-top: 1.5rem !important; } .pt-xxl-5 { padding-top: 3rem !important; } .pe-xxl-0 { padding-right: 0 !important; } .pe-xxl-1 { padding-right: 0.25rem !important; } .pe-xxl-2 { padding-right: 0.5rem !important; } .pe-xxl-3 { padding-right: 1rem !important; } .pe-xxl-4 { padding-right: 1.5rem !important; } .pe-xxl-5 { padding-right: 3rem !important; } .pb-xxl-0 { padding-bottom: 0 !important; } .pb-xxl-1 { padding-bottom: 0.25rem !important; } .pb-xxl-2 { padding-bottom: 0.5rem !important; } .pb-xxl-3 { padding-bottom: 1rem !important; } .pb-xxl-4 { padding-bottom: 1.5rem !important; } .pb-xxl-5 { padding-bottom: 3rem !important; } .ps-xxl-0 { padding-left: 0 !important; } .ps-xxl-1 { padding-left: 0.25rem !important; } .ps-xxl-2 { padding-left: 0.5rem !important; } .ps-xxl-3 { padding-left: 1rem !important; } .ps-xxl-4 { padding-left: 1.5rem !important; } .ps-xxl-5 { padding-left: 3rem !important; } } @media print { .d-print-inline { display: inline !important; } .d-print-inline-block { display: inline-block !important; } .d-print-block { display: block !important; } .d-print-grid { display: grid !important; } .d-print-table { display: table !important; } .d-print-table-row { display: table-row !important; } .d-print-table-cell { display: table-cell !important; } .d-print-flex { display: flex !important; } .d-print-inline-flex { display: inline-flex !important; } .d-print-none { display: none !important; } } /*# sourceMappingURL=bootstrap-grid.css.map */ ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-grid.rtl.css ================================================ /*! * Bootstrap Grid 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) */ .container, .container-fluid, .container-xxl, .container-xl, .container-lg, .container-md, .container-sm { width: 100%; padding-left: var(--bs-gutter-x, 0.75rem); padding-right: var(--bs-gutter-x, 0.75rem); margin-left: auto; margin-right: auto; } @media (min-width: 576px) { .container-sm, .container { max-width: 540px; } } @media (min-width: 768px) { .container-md, .container-sm, .container { max-width: 720px; } } @media (min-width: 992px) { .container-lg, .container-md, .container-sm, .container { max-width: 960px; } } @media (min-width: 1200px) { .container-xl, .container-lg, .container-md, .container-sm, .container { max-width: 1140px; } } @media (min-width: 1400px) { .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container { 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-left: calc(var(--bs-gutter-x) * -.5); margin-right: calc(var(--bs-gutter-x) * -.5); } .row > * { box-sizing: border-box; flex-shrink: 0; width: 100%; max-width: 100%; padding-left: calc(var(--bs-gutter-x) * .5); padding-right: 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-right: 8.33333333%; } .offset-2 { margin-right: 16.66666667%; } .offset-3 { margin-right: 25%; } .offset-4 { margin-right: 33.33333333%; } .offset-5 { margin-right: 41.66666667%; } .offset-6 { margin-right: 50%; } .offset-7 { margin-right: 58.33333333%; } .offset-8 { margin-right: 66.66666667%; } .offset-9 { margin-right: 75%; } .offset-10 { margin-right: 83.33333333%; } .offset-11 { margin-right: 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-right: 0; } .offset-sm-1 { margin-right: 8.33333333%; } .offset-sm-2 { margin-right: 16.66666667%; } .offset-sm-3 { margin-right: 25%; } .offset-sm-4 { margin-right: 33.33333333%; } .offset-sm-5 { margin-right: 41.66666667%; } .offset-sm-6 { margin-right: 50%; } .offset-sm-7 { margin-right: 58.33333333%; } .offset-sm-8 { margin-right: 66.66666667%; } .offset-sm-9 { margin-right: 75%; } .offset-sm-10 { margin-right: 83.33333333%; } .offset-sm-11 { margin-right: 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-right: 0; } .offset-md-1 { margin-right: 8.33333333%; } .offset-md-2 { margin-right: 16.66666667%; } .offset-md-3 { margin-right: 25%; } .offset-md-4 { margin-right: 33.33333333%; } .offset-md-5 { margin-right: 41.66666667%; } .offset-md-6 { margin-right: 50%; } .offset-md-7 { margin-right: 58.33333333%; } .offset-md-8 { margin-right: 66.66666667%; } .offset-md-9 { margin-right: 75%; } .offset-md-10 { margin-right: 83.33333333%; } .offset-md-11 { margin-right: 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-right: 0; } .offset-lg-1 { margin-right: 8.33333333%; } .offset-lg-2 { margin-right: 16.66666667%; } .offset-lg-3 { margin-right: 25%; } .offset-lg-4 { margin-right: 33.33333333%; } .offset-lg-5 { margin-right: 41.66666667%; } .offset-lg-6 { margin-right: 50%; } .offset-lg-7 { margin-right: 58.33333333%; } .offset-lg-8 { margin-right: 66.66666667%; } .offset-lg-9 { margin-right: 75%; } .offset-lg-10 { margin-right: 83.33333333%; } .offset-lg-11 { margin-right: 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-right: 0; } .offset-xl-1 { margin-right: 8.33333333%; } .offset-xl-2 { margin-right: 16.66666667%; } .offset-xl-3 { margin-right: 25%; } .offset-xl-4 { margin-right: 33.33333333%; } .offset-xl-5 { margin-right: 41.66666667%; } .offset-xl-6 { margin-right: 50%; } .offset-xl-7 { margin-right: 58.33333333%; } .offset-xl-8 { margin-right: 66.66666667%; } .offset-xl-9 { margin-right: 75%; } .offset-xl-10 { margin-right: 83.33333333%; } .offset-xl-11 { margin-right: 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-right: 0; } .offset-xxl-1 { margin-right: 8.33333333%; } .offset-xxl-2 { margin-right: 16.66666667%; } .offset-xxl-3 { margin-right: 25%; } .offset-xxl-4 { margin-right: 33.33333333%; } .offset-xxl-5 { margin-right: 41.66666667%; } .offset-xxl-6 { margin-right: 50%; } .offset-xxl-7 { margin-right: 58.33333333%; } .offset-xxl-8 { margin-right: 66.66666667%; } .offset-xxl-9 { margin-right: 75%; } .offset-xxl-10 { margin-right: 83.33333333%; } .offset-xxl-11 { margin-right: 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; } } .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; } .flex-fill { flex: 1 1 auto !important; } .flex-row { flex-direction: row !important; } .flex-column { flex-direction: column !important; } .flex-row-reverse { flex-direction: row-reverse !important; } .flex-column-reverse { flex-direction: column-reverse !important; } .flex-grow-0 { flex-grow: 0 !important; } .flex-grow-1 { flex-grow: 1 !important; } .flex-shrink-0 { flex-shrink: 0 !important; } .flex-shrink-1 { flex-shrink: 1 !important; } .flex-wrap { flex-wrap: wrap !important; } .flex-nowrap { flex-wrap: nowrap !important; } .flex-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-start { justify-content: flex-start !important; } .justify-content-end { justify-content: flex-end !important; } .justify-content-center { justify-content: center !important; } .justify-content-between { justify-content: space-between !important; } .justify-content-around { justify-content: space-around !important; } .justify-content-evenly { justify-content: space-evenly !important; } .align-items-start { align-items: flex-start !important; } .align-items-end { align-items: flex-end !important; } .align-items-center { align-items: center !important; } .align-items-baseline { align-items: baseline !important; } .align-items-stretch { align-items: stretch !important; } .align-content-start { align-content: flex-start !important; } .align-content-end { align-content: flex-end !important; } .align-content-center { align-content: center !important; } .align-content-between { align-content: space-between !important; } .align-content-around { align-content: space-around !important; } .align-content-stretch { align-content: stretch !important; } .align-self-auto { align-self: auto !important; } .align-self-start { align-self: flex-start !important; } .align-self-end { align-self: flex-end !important; } .align-self-center { align-self: center !important; } .align-self-baseline { align-self: baseline !important; } .align-self-stretch { align-self: stretch !important; } .order-first { order: -1 !important; } .order-0 { order: 0 !important; } .order-1 { order: 1 !important; } .order-2 { order: 2 !important; } .order-3 { order: 3 !important; } .order-4 { order: 4 !important; } .order-5 { order: 5 !important; } .order-last { order: 6 !important; } .m-0 { margin: 0 !important; } .m-1 { margin: 0.25rem !important; } .m-2 { margin: 0.5rem !important; } .m-3 { margin: 1rem !important; } .m-4 { margin: 1.5rem !important; } .m-5 { margin: 3rem !important; } .m-auto { margin: auto !important; } .mx-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-auto { margin-left: auto !important; margin-right: auto !important; } .my-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-5 { margin-top: 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: 0.25rem !important; } .mt-2 { margin-top: 0.5rem !important; } .mt-3 { margin-top: 1rem !important; } .mt-4 { margin-top: 1.5rem !important; } .mt-5 { margin-top: 3rem !important; } .mt-auto { margin-top: auto !important; } .me-0 { margin-left: 0 !important; } .me-1 { margin-left: 0.25rem !important; } .me-2 { margin-left: 0.5rem !important; } .me-3 { margin-left: 1rem !important; } .me-4 { margin-left: 1.5rem !important; } .me-5 { margin-left: 3rem !important; } .me-auto { margin-left: auto !important; } .mb-0 { margin-bottom: 0 !important; } .mb-1 { margin-bottom: 0.25rem !important; } .mb-2 { margin-bottom: 0.5rem !important; } .mb-3 { margin-bottom: 1rem !important; } .mb-4 { margin-bottom: 1.5rem !important; } .mb-5 { margin-bottom: 3rem !important; } .mb-auto { margin-bottom: auto !important; } .ms-0 { margin-right: 0 !important; } .ms-1 { margin-right: 0.25rem !important; } .ms-2 { margin-right: 0.5rem !important; } .ms-3 { margin-right: 1rem !important; } .ms-4 { margin-right: 1.5rem !important; } .ms-5 { margin-right: 3rem !important; } .ms-auto { margin-right: auto !important; } .p-0 { padding: 0 !important; } .p-1 { padding: 0.25rem !important; } .p-2 { padding: 0.5rem !important; } .p-3 { padding: 1rem !important; } .p-4 { padding: 1.5rem !important; } .p-5 { padding: 3rem !important; } .px-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-0 { padding-top: 0 !important; } .pt-1 { padding-top: 0.25rem !important; } .pt-2 { padding-top: 0.5rem !important; } .pt-3 { padding-top: 1rem !important; } .pt-4 { padding-top: 1.5rem !important; } .pt-5 { padding-top: 3rem !important; } .pe-0 { padding-left: 0 !important; } .pe-1 { padding-left: 0.25rem !important; } .pe-2 { padding-left: 0.5rem !important; } .pe-3 { padding-left: 1rem !important; } .pe-4 { padding-left: 1.5rem !important; } .pe-5 { padding-left: 3rem !important; } .pb-0 { padding-bottom: 0 !important; } .pb-1 { padding-bottom: 0.25rem !important; } .pb-2 { padding-bottom: 0.5rem !important; } .pb-3 { padding-bottom: 1rem !important; } .pb-4 { padding-bottom: 1.5rem !important; } .pb-5 { padding-bottom: 3rem !important; } .ps-0 { padding-right: 0 !important; } .ps-1 { padding-right: 0.25rem !important; } .ps-2 { padding-right: 0.5rem !important; } .ps-3 { padding-right: 1rem !important; } .ps-4 { padding-right: 1.5rem !important; } .ps-5 { padding-right: 3rem !important; } @media (min-width: 576px) { .d-sm-inline { display: inline !important; } .d-sm-inline-block { display: inline-block !important; } .d-sm-block { display: block !important; } .d-sm-grid { display: grid !important; } .d-sm-table { display: table !important; } .d-sm-table-row { display: table-row !important; } .d-sm-table-cell { display: table-cell !important; } .d-sm-flex { display: flex !important; } .d-sm-inline-flex { display: inline-flex !important; } .d-sm-none { display: none !important; } .flex-sm-fill { flex: 1 1 auto !important; } .flex-sm-row { flex-direction: row !important; } .flex-sm-column { flex-direction: column !important; } .flex-sm-row-reverse { flex-direction: row-reverse !important; } .flex-sm-column-reverse { flex-direction: column-reverse !important; } .flex-sm-grow-0 { flex-grow: 0 !important; } .flex-sm-grow-1 { flex-grow: 1 !important; } .flex-sm-shrink-0 { flex-shrink: 0 !important; } .flex-sm-shrink-1 { flex-shrink: 1 !important; } .flex-sm-wrap { flex-wrap: wrap !important; } .flex-sm-nowrap { flex-wrap: nowrap !important; } .flex-sm-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-sm-start { justify-content: flex-start !important; } .justify-content-sm-end { justify-content: flex-end !important; } .justify-content-sm-center { justify-content: center !important; } .justify-content-sm-between { justify-content: space-between !important; } .justify-content-sm-around { justify-content: space-around !important; } .justify-content-sm-evenly { justify-content: space-evenly !important; } .align-items-sm-start { align-items: flex-start !important; } .align-items-sm-end { align-items: flex-end !important; } .align-items-sm-center { align-items: center !important; } .align-items-sm-baseline { align-items: baseline !important; } .align-items-sm-stretch { align-items: stretch !important; } .align-content-sm-start { align-content: flex-start !important; } .align-content-sm-end { align-content: flex-end !important; } .align-content-sm-center { align-content: center !important; } .align-content-sm-between { align-content: space-between !important; } .align-content-sm-around { align-content: space-around !important; } .align-content-sm-stretch { align-content: stretch !important; } .align-self-sm-auto { align-self: auto !important; } .align-self-sm-start { align-self: flex-start !important; } .align-self-sm-end { align-self: flex-end !important; } .align-self-sm-center { align-self: center !important; } .align-self-sm-baseline { align-self: baseline !important; } .align-self-sm-stretch { align-self: stretch !important; } .order-sm-first { order: -1 !important; } .order-sm-0 { order: 0 !important; } .order-sm-1 { order: 1 !important; } .order-sm-2 { order: 2 !important; } .order-sm-3 { order: 3 !important; } .order-sm-4 { order: 4 !important; } .order-sm-5 { order: 5 !important; } .order-sm-last { order: 6 !important; } .m-sm-0 { margin: 0 !important; } .m-sm-1 { margin: 0.25rem !important; } .m-sm-2 { margin: 0.5rem !important; } .m-sm-3 { margin: 1rem !important; } .m-sm-4 { margin: 1.5rem !important; } .m-sm-5 { margin: 3rem !important; } .m-sm-auto { margin: auto !important; } .mx-sm-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-sm-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-sm-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-sm-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-sm-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-sm-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-sm-auto { margin-left: auto !important; margin-right: auto !important; } .my-sm-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-sm-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-sm-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-sm-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-sm-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-sm-5 { margin-top: 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: 0.25rem !important; } .mt-sm-2 { margin-top: 0.5rem !important; } .mt-sm-3 { margin-top: 1rem !important; } .mt-sm-4 { margin-top: 1.5rem !important; } .mt-sm-5 { margin-top: 3rem !important; } .mt-sm-auto { margin-top: auto !important; } .me-sm-0 { margin-left: 0 !important; } .me-sm-1 { margin-left: 0.25rem !important; } .me-sm-2 { margin-left: 0.5rem !important; } .me-sm-3 { margin-left: 1rem !important; } .me-sm-4 { margin-left: 1.5rem !important; } .me-sm-5 { margin-left: 3rem !important; } .me-sm-auto { margin-left: auto !important; } .mb-sm-0 { margin-bottom: 0 !important; } .mb-sm-1 { margin-bottom: 0.25rem !important; } .mb-sm-2 { margin-bottom: 0.5rem !important; } .mb-sm-3 { margin-bottom: 1rem !important; } .mb-sm-4 { margin-bottom: 1.5rem !important; } .mb-sm-5 { margin-bottom: 3rem !important; } .mb-sm-auto { margin-bottom: auto !important; } .ms-sm-0 { margin-right: 0 !important; } .ms-sm-1 { margin-right: 0.25rem !important; } .ms-sm-2 { margin-right: 0.5rem !important; } .ms-sm-3 { margin-right: 1rem !important; } .ms-sm-4 { margin-right: 1.5rem !important; } .ms-sm-5 { margin-right: 3rem !important; } .ms-sm-auto { margin-right: auto !important; } .p-sm-0 { padding: 0 !important; } .p-sm-1 { padding: 0.25rem !important; } .p-sm-2 { padding: 0.5rem !important; } .p-sm-3 { padding: 1rem !important; } .p-sm-4 { padding: 1.5rem !important; } .p-sm-5 { padding: 3rem !important; } .px-sm-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-sm-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-sm-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-sm-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-sm-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-sm-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-sm-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-sm-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-sm-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-sm-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-sm-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-sm-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-sm-0 { padding-top: 0 !important; } .pt-sm-1 { padding-top: 0.25rem !important; } .pt-sm-2 { padding-top: 0.5rem !important; } .pt-sm-3 { padding-top: 1rem !important; } .pt-sm-4 { padding-top: 1.5rem !important; } .pt-sm-5 { padding-top: 3rem !important; } .pe-sm-0 { padding-left: 0 !important; } .pe-sm-1 { padding-left: 0.25rem !important; } .pe-sm-2 { padding-left: 0.5rem !important; } .pe-sm-3 { padding-left: 1rem !important; } .pe-sm-4 { padding-left: 1.5rem !important; } .pe-sm-5 { padding-left: 3rem !important; } .pb-sm-0 { padding-bottom: 0 !important; } .pb-sm-1 { padding-bottom: 0.25rem !important; } .pb-sm-2 { padding-bottom: 0.5rem !important; } .pb-sm-3 { padding-bottom: 1rem !important; } .pb-sm-4 { padding-bottom: 1.5rem !important; } .pb-sm-5 { padding-bottom: 3rem !important; } .ps-sm-0 { padding-right: 0 !important; } .ps-sm-1 { padding-right: 0.25rem !important; } .ps-sm-2 { padding-right: 0.5rem !important; } .ps-sm-3 { padding-right: 1rem !important; } .ps-sm-4 { padding-right: 1.5rem !important; } .ps-sm-5 { padding-right: 3rem !important; } } @media (min-width: 768px) { .d-md-inline { display: inline !important; } .d-md-inline-block { display: inline-block !important; } .d-md-block { display: block !important; } .d-md-grid { display: grid !important; } .d-md-table { display: table !important; } .d-md-table-row { display: table-row !important; } .d-md-table-cell { display: table-cell !important; } .d-md-flex { display: flex !important; } .d-md-inline-flex { display: inline-flex !important; } .d-md-none { display: none !important; } .flex-md-fill { flex: 1 1 auto !important; } .flex-md-row { flex-direction: row !important; } .flex-md-column { flex-direction: column !important; } .flex-md-row-reverse { flex-direction: row-reverse !important; } .flex-md-column-reverse { flex-direction: column-reverse !important; } .flex-md-grow-0 { flex-grow: 0 !important; } .flex-md-grow-1 { flex-grow: 1 !important; } .flex-md-shrink-0 { flex-shrink: 0 !important; } .flex-md-shrink-1 { flex-shrink: 1 !important; } .flex-md-wrap { flex-wrap: wrap !important; } .flex-md-nowrap { flex-wrap: nowrap !important; } .flex-md-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-md-start { justify-content: flex-start !important; } .justify-content-md-end { justify-content: flex-end !important; } .justify-content-md-center { justify-content: center !important; } .justify-content-md-between { justify-content: space-between !important; } .justify-content-md-around { justify-content: space-around !important; } .justify-content-md-evenly { justify-content: space-evenly !important; } .align-items-md-start { align-items: flex-start !important; } .align-items-md-end { align-items: flex-end !important; } .align-items-md-center { align-items: center !important; } .align-items-md-baseline { align-items: baseline !important; } .align-items-md-stretch { align-items: stretch !important; } .align-content-md-start { align-content: flex-start !important; } .align-content-md-end { align-content: flex-end !important; } .align-content-md-center { align-content: center !important; } .align-content-md-between { align-content: space-between !important; } .align-content-md-around { align-content: space-around !important; } .align-content-md-stretch { align-content: stretch !important; } .align-self-md-auto { align-self: auto !important; } .align-self-md-start { align-self: flex-start !important; } .align-self-md-end { align-self: flex-end !important; } .align-self-md-center { align-self: center !important; } .align-self-md-baseline { align-self: baseline !important; } .align-self-md-stretch { align-self: stretch !important; } .order-md-first { order: -1 !important; } .order-md-0 { order: 0 !important; } .order-md-1 { order: 1 !important; } .order-md-2 { order: 2 !important; } .order-md-3 { order: 3 !important; } .order-md-4 { order: 4 !important; } .order-md-5 { order: 5 !important; } .order-md-last { order: 6 !important; } .m-md-0 { margin: 0 !important; } .m-md-1 { margin: 0.25rem !important; } .m-md-2 { margin: 0.5rem !important; } .m-md-3 { margin: 1rem !important; } .m-md-4 { margin: 1.5rem !important; } .m-md-5 { margin: 3rem !important; } .m-md-auto { margin: auto !important; } .mx-md-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-md-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-md-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-md-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-md-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-md-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-md-auto { margin-left: auto !important; margin-right: auto !important; } .my-md-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-md-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-md-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-md-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-md-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-md-5 { margin-top: 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: 0.25rem !important; } .mt-md-2 { margin-top: 0.5rem !important; } .mt-md-3 { margin-top: 1rem !important; } .mt-md-4 { margin-top: 1.5rem !important; } .mt-md-5 { margin-top: 3rem !important; } .mt-md-auto { margin-top: auto !important; } .me-md-0 { margin-left: 0 !important; } .me-md-1 { margin-left: 0.25rem !important; } .me-md-2 { margin-left: 0.5rem !important; } .me-md-3 { margin-left: 1rem !important; } .me-md-4 { margin-left: 1.5rem !important; } .me-md-5 { margin-left: 3rem !important; } .me-md-auto { margin-left: auto !important; } .mb-md-0 { margin-bottom: 0 !important; } .mb-md-1 { margin-bottom: 0.25rem !important; } .mb-md-2 { margin-bottom: 0.5rem !important; } .mb-md-3 { margin-bottom: 1rem !important; } .mb-md-4 { margin-bottom: 1.5rem !important; } .mb-md-5 { margin-bottom: 3rem !important; } .mb-md-auto { margin-bottom: auto !important; } .ms-md-0 { margin-right: 0 !important; } .ms-md-1 { margin-right: 0.25rem !important; } .ms-md-2 { margin-right: 0.5rem !important; } .ms-md-3 { margin-right: 1rem !important; } .ms-md-4 { margin-right: 1.5rem !important; } .ms-md-5 { margin-right: 3rem !important; } .ms-md-auto { margin-right: auto !important; } .p-md-0 { padding: 0 !important; } .p-md-1 { padding: 0.25rem !important; } .p-md-2 { padding: 0.5rem !important; } .p-md-3 { padding: 1rem !important; } .p-md-4 { padding: 1.5rem !important; } .p-md-5 { padding: 3rem !important; } .px-md-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-md-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-md-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-md-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-md-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-md-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-md-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-md-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-md-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-md-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-md-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-md-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-md-0 { padding-top: 0 !important; } .pt-md-1 { padding-top: 0.25rem !important; } .pt-md-2 { padding-top: 0.5rem !important; } .pt-md-3 { padding-top: 1rem !important; } .pt-md-4 { padding-top: 1.5rem !important; } .pt-md-5 { padding-top: 3rem !important; } .pe-md-0 { padding-left: 0 !important; } .pe-md-1 { padding-left: 0.25rem !important; } .pe-md-2 { padding-left: 0.5rem !important; } .pe-md-3 { padding-left: 1rem !important; } .pe-md-4 { padding-left: 1.5rem !important; } .pe-md-5 { padding-left: 3rem !important; } .pb-md-0 { padding-bottom: 0 !important; } .pb-md-1 { padding-bottom: 0.25rem !important; } .pb-md-2 { padding-bottom: 0.5rem !important; } .pb-md-3 { padding-bottom: 1rem !important; } .pb-md-4 { padding-bottom: 1.5rem !important; } .pb-md-5 { padding-bottom: 3rem !important; } .ps-md-0 { padding-right: 0 !important; } .ps-md-1 { padding-right: 0.25rem !important; } .ps-md-2 { padding-right: 0.5rem !important; } .ps-md-3 { padding-right: 1rem !important; } .ps-md-4 { padding-right: 1.5rem !important; } .ps-md-5 { padding-right: 3rem !important; } } @media (min-width: 992px) { .d-lg-inline { display: inline !important; } .d-lg-inline-block { display: inline-block !important; } .d-lg-block { display: block !important; } .d-lg-grid { display: grid !important; } .d-lg-table { display: table !important; } .d-lg-table-row { display: table-row !important; } .d-lg-table-cell { display: table-cell !important; } .d-lg-flex { display: flex !important; } .d-lg-inline-flex { display: inline-flex !important; } .d-lg-none { display: none !important; } .flex-lg-fill { flex: 1 1 auto !important; } .flex-lg-row { flex-direction: row !important; } .flex-lg-column { flex-direction: column !important; } .flex-lg-row-reverse { flex-direction: row-reverse !important; } .flex-lg-column-reverse { flex-direction: column-reverse !important; } .flex-lg-grow-0 { flex-grow: 0 !important; } .flex-lg-grow-1 { flex-grow: 1 !important; } .flex-lg-shrink-0 { flex-shrink: 0 !important; } .flex-lg-shrink-1 { flex-shrink: 1 !important; } .flex-lg-wrap { flex-wrap: wrap !important; } .flex-lg-nowrap { flex-wrap: nowrap !important; } .flex-lg-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-lg-start { justify-content: flex-start !important; } .justify-content-lg-end { justify-content: flex-end !important; } .justify-content-lg-center { justify-content: center !important; } .justify-content-lg-between { justify-content: space-between !important; } .justify-content-lg-around { justify-content: space-around !important; } .justify-content-lg-evenly { justify-content: space-evenly !important; } .align-items-lg-start { align-items: flex-start !important; } .align-items-lg-end { align-items: flex-end !important; } .align-items-lg-center { align-items: center !important; } .align-items-lg-baseline { align-items: baseline !important; } .align-items-lg-stretch { align-items: stretch !important; } .align-content-lg-start { align-content: flex-start !important; } .align-content-lg-end { align-content: flex-end !important; } .align-content-lg-center { align-content: center !important; } .align-content-lg-between { align-content: space-between !important; } .align-content-lg-around { align-content: space-around !important; } .align-content-lg-stretch { align-content: stretch !important; } .align-self-lg-auto { align-self: auto !important; } .align-self-lg-start { align-self: flex-start !important; } .align-self-lg-end { align-self: flex-end !important; } .align-self-lg-center { align-self: center !important; } .align-self-lg-baseline { align-self: baseline !important; } .align-self-lg-stretch { align-self: stretch !important; } .order-lg-first { order: -1 !important; } .order-lg-0 { order: 0 !important; } .order-lg-1 { order: 1 !important; } .order-lg-2 { order: 2 !important; } .order-lg-3 { order: 3 !important; } .order-lg-4 { order: 4 !important; } .order-lg-5 { order: 5 !important; } .order-lg-last { order: 6 !important; } .m-lg-0 { margin: 0 !important; } .m-lg-1 { margin: 0.25rem !important; } .m-lg-2 { margin: 0.5rem !important; } .m-lg-3 { margin: 1rem !important; } .m-lg-4 { margin: 1.5rem !important; } .m-lg-5 { margin: 3rem !important; } .m-lg-auto { margin: auto !important; } .mx-lg-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-lg-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-lg-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-lg-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-lg-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-lg-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-lg-auto { margin-left: auto !important; margin-right: auto !important; } .my-lg-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-lg-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-lg-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-lg-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-lg-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-lg-5 { margin-top: 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: 0.25rem !important; } .mt-lg-2 { margin-top: 0.5rem !important; } .mt-lg-3 { margin-top: 1rem !important; } .mt-lg-4 { margin-top: 1.5rem !important; } .mt-lg-5 { margin-top: 3rem !important; } .mt-lg-auto { margin-top: auto !important; } .me-lg-0 { margin-left: 0 !important; } .me-lg-1 { margin-left: 0.25rem !important; } .me-lg-2 { margin-left: 0.5rem !important; } .me-lg-3 { margin-left: 1rem !important; } .me-lg-4 { margin-left: 1.5rem !important; } .me-lg-5 { margin-left: 3rem !important; } .me-lg-auto { margin-left: auto !important; } .mb-lg-0 { margin-bottom: 0 !important; } .mb-lg-1 { margin-bottom: 0.25rem !important; } .mb-lg-2 { margin-bottom: 0.5rem !important; } .mb-lg-3 { margin-bottom: 1rem !important; } .mb-lg-4 { margin-bottom: 1.5rem !important; } .mb-lg-5 { margin-bottom: 3rem !important; } .mb-lg-auto { margin-bottom: auto !important; } .ms-lg-0 { margin-right: 0 !important; } .ms-lg-1 { margin-right: 0.25rem !important; } .ms-lg-2 { margin-right: 0.5rem !important; } .ms-lg-3 { margin-right: 1rem !important; } .ms-lg-4 { margin-right: 1.5rem !important; } .ms-lg-5 { margin-right: 3rem !important; } .ms-lg-auto { margin-right: auto !important; } .p-lg-0 { padding: 0 !important; } .p-lg-1 { padding: 0.25rem !important; } .p-lg-2 { padding: 0.5rem !important; } .p-lg-3 { padding: 1rem !important; } .p-lg-4 { padding: 1.5rem !important; } .p-lg-5 { padding: 3rem !important; } .px-lg-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-lg-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-lg-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-lg-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-lg-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-lg-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-lg-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-lg-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-lg-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-lg-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-lg-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-lg-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-lg-0 { padding-top: 0 !important; } .pt-lg-1 { padding-top: 0.25rem !important; } .pt-lg-2 { padding-top: 0.5rem !important; } .pt-lg-3 { padding-top: 1rem !important; } .pt-lg-4 { padding-top: 1.5rem !important; } .pt-lg-5 { padding-top: 3rem !important; } .pe-lg-0 { padding-left: 0 !important; } .pe-lg-1 { padding-left: 0.25rem !important; } .pe-lg-2 { padding-left: 0.5rem !important; } .pe-lg-3 { padding-left: 1rem !important; } .pe-lg-4 { padding-left: 1.5rem !important; } .pe-lg-5 { padding-left: 3rem !important; } .pb-lg-0 { padding-bottom: 0 !important; } .pb-lg-1 { padding-bottom: 0.25rem !important; } .pb-lg-2 { padding-bottom: 0.5rem !important; } .pb-lg-3 { padding-bottom: 1rem !important; } .pb-lg-4 { padding-bottom: 1.5rem !important; } .pb-lg-5 { padding-bottom: 3rem !important; } .ps-lg-0 { padding-right: 0 !important; } .ps-lg-1 { padding-right: 0.25rem !important; } .ps-lg-2 { padding-right: 0.5rem !important; } .ps-lg-3 { padding-right: 1rem !important; } .ps-lg-4 { padding-right: 1.5rem !important; } .ps-lg-5 { padding-right: 3rem !important; } } @media (min-width: 1200px) { .d-xl-inline { display: inline !important; } .d-xl-inline-block { display: inline-block !important; } .d-xl-block { display: block !important; } .d-xl-grid { display: grid !important; } .d-xl-table { display: table !important; } .d-xl-table-row { display: table-row !important; } .d-xl-table-cell { display: table-cell !important; } .d-xl-flex { display: flex !important; } .d-xl-inline-flex { display: inline-flex !important; } .d-xl-none { display: none !important; } .flex-xl-fill { flex: 1 1 auto !important; } .flex-xl-row { flex-direction: row !important; } .flex-xl-column { flex-direction: column !important; } .flex-xl-row-reverse { flex-direction: row-reverse !important; } .flex-xl-column-reverse { flex-direction: column-reverse !important; } .flex-xl-grow-0 { flex-grow: 0 !important; } .flex-xl-grow-1 { flex-grow: 1 !important; } .flex-xl-shrink-0 { flex-shrink: 0 !important; } .flex-xl-shrink-1 { flex-shrink: 1 !important; } .flex-xl-wrap { flex-wrap: wrap !important; } .flex-xl-nowrap { flex-wrap: nowrap !important; } .flex-xl-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-xl-start { justify-content: flex-start !important; } .justify-content-xl-end { justify-content: flex-end !important; } .justify-content-xl-center { justify-content: center !important; } .justify-content-xl-between { justify-content: space-between !important; } .justify-content-xl-around { justify-content: space-around !important; } .justify-content-xl-evenly { justify-content: space-evenly !important; } .align-items-xl-start { align-items: flex-start !important; } .align-items-xl-end { align-items: flex-end !important; } .align-items-xl-center { align-items: center !important; } .align-items-xl-baseline { align-items: baseline !important; } .align-items-xl-stretch { align-items: stretch !important; } .align-content-xl-start { align-content: flex-start !important; } .align-content-xl-end { align-content: flex-end !important; } .align-content-xl-center { align-content: center !important; } .align-content-xl-between { align-content: space-between !important; } .align-content-xl-around { align-content: space-around !important; } .align-content-xl-stretch { align-content: stretch !important; } .align-self-xl-auto { align-self: auto !important; } .align-self-xl-start { align-self: flex-start !important; } .align-self-xl-end { align-self: flex-end !important; } .align-self-xl-center { align-self: center !important; } .align-self-xl-baseline { align-self: baseline !important; } .align-self-xl-stretch { align-self: stretch !important; } .order-xl-first { order: -1 !important; } .order-xl-0 { order: 0 !important; } .order-xl-1 { order: 1 !important; } .order-xl-2 { order: 2 !important; } .order-xl-3 { order: 3 !important; } .order-xl-4 { order: 4 !important; } .order-xl-5 { order: 5 !important; } .order-xl-last { order: 6 !important; } .m-xl-0 { margin: 0 !important; } .m-xl-1 { margin: 0.25rem !important; } .m-xl-2 { margin: 0.5rem !important; } .m-xl-3 { margin: 1rem !important; } .m-xl-4 { margin: 1.5rem !important; } .m-xl-5 { margin: 3rem !important; } .m-xl-auto { margin: auto !important; } .mx-xl-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-xl-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-xl-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-xl-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-xl-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-xl-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-xl-auto { margin-left: auto !important; margin-right: auto !important; } .my-xl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-xl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xl-5 { margin-top: 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: 0.25rem !important; } .mt-xl-2 { margin-top: 0.5rem !important; } .mt-xl-3 { margin-top: 1rem !important; } .mt-xl-4 { margin-top: 1.5rem !important; } .mt-xl-5 { margin-top: 3rem !important; } .mt-xl-auto { margin-top: auto !important; } .me-xl-0 { margin-left: 0 !important; } .me-xl-1 { margin-left: 0.25rem !important; } .me-xl-2 { margin-left: 0.5rem !important; } .me-xl-3 { margin-left: 1rem !important; } .me-xl-4 { margin-left: 1.5rem !important; } .me-xl-5 { margin-left: 3rem !important; } .me-xl-auto { margin-left: auto !important; } .mb-xl-0 { margin-bottom: 0 !important; } .mb-xl-1 { margin-bottom: 0.25rem !important; } .mb-xl-2 { margin-bottom: 0.5rem !important; } .mb-xl-3 { margin-bottom: 1rem !important; } .mb-xl-4 { margin-bottom: 1.5rem !important; } .mb-xl-5 { margin-bottom: 3rem !important; } .mb-xl-auto { margin-bottom: auto !important; } .ms-xl-0 { margin-right: 0 !important; } .ms-xl-1 { margin-right: 0.25rem !important; } .ms-xl-2 { margin-right: 0.5rem !important; } .ms-xl-3 { margin-right: 1rem !important; } .ms-xl-4 { margin-right: 1.5rem !important; } .ms-xl-5 { margin-right: 3rem !important; } .ms-xl-auto { margin-right: auto !important; } .p-xl-0 { padding: 0 !important; } .p-xl-1 { padding: 0.25rem !important; } .p-xl-2 { padding: 0.5rem !important; } .p-xl-3 { padding: 1rem !important; } .p-xl-4 { padding: 1.5rem !important; } .p-xl-5 { padding: 3rem !important; } .px-xl-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-xl-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-xl-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-xl-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-xl-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-xl-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-xl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xl-0 { padding-top: 0 !important; } .pt-xl-1 { padding-top: 0.25rem !important; } .pt-xl-2 { padding-top: 0.5rem !important; } .pt-xl-3 { padding-top: 1rem !important; } .pt-xl-4 { padding-top: 1.5rem !important; } .pt-xl-5 { padding-top: 3rem !important; } .pe-xl-0 { padding-left: 0 !important; } .pe-xl-1 { padding-left: 0.25rem !important; } .pe-xl-2 { padding-left: 0.5rem !important; } .pe-xl-3 { padding-left: 1rem !important; } .pe-xl-4 { padding-left: 1.5rem !important; } .pe-xl-5 { padding-left: 3rem !important; } .pb-xl-0 { padding-bottom: 0 !important; } .pb-xl-1 { padding-bottom: 0.25rem !important; } .pb-xl-2 { padding-bottom: 0.5rem !important; } .pb-xl-3 { padding-bottom: 1rem !important; } .pb-xl-4 { padding-bottom: 1.5rem !important; } .pb-xl-5 { padding-bottom: 3rem !important; } .ps-xl-0 { padding-right: 0 !important; } .ps-xl-1 { padding-right: 0.25rem !important; } .ps-xl-2 { padding-right: 0.5rem !important; } .ps-xl-3 { padding-right: 1rem !important; } .ps-xl-4 { padding-right: 1.5rem !important; } .ps-xl-5 { padding-right: 3rem !important; } } @media (min-width: 1400px) { .d-xxl-inline { display: inline !important; } .d-xxl-inline-block { display: inline-block !important; } .d-xxl-block { display: block !important; } .d-xxl-grid { display: grid !important; } .d-xxl-table { display: table !important; } .d-xxl-table-row { display: table-row !important; } .d-xxl-table-cell { display: table-cell !important; } .d-xxl-flex { display: flex !important; } .d-xxl-inline-flex { display: inline-flex !important; } .d-xxl-none { display: none !important; } .flex-xxl-fill { flex: 1 1 auto !important; } .flex-xxl-row { flex-direction: row !important; } .flex-xxl-column { flex-direction: column !important; } .flex-xxl-row-reverse { flex-direction: row-reverse !important; } .flex-xxl-column-reverse { flex-direction: column-reverse !important; } .flex-xxl-grow-0 { flex-grow: 0 !important; } .flex-xxl-grow-1 { flex-grow: 1 !important; } .flex-xxl-shrink-0 { flex-shrink: 0 !important; } .flex-xxl-shrink-1 { flex-shrink: 1 !important; } .flex-xxl-wrap { flex-wrap: wrap !important; } .flex-xxl-nowrap { flex-wrap: nowrap !important; } .flex-xxl-wrap-reverse { flex-wrap: wrap-reverse !important; } .justify-content-xxl-start { justify-content: flex-start !important; } .justify-content-xxl-end { justify-content: flex-end !important; } .justify-content-xxl-center { justify-content: center !important; } .justify-content-xxl-between { justify-content: space-between !important; } .justify-content-xxl-around { justify-content: space-around !important; } .justify-content-xxl-evenly { justify-content: space-evenly !important; } .align-items-xxl-start { align-items: flex-start !important; } .align-items-xxl-end { align-items: flex-end !important; } .align-items-xxl-center { align-items: center !important; } .align-items-xxl-baseline { align-items: baseline !important; } .align-items-xxl-stretch { align-items: stretch !important; } .align-content-xxl-start { align-content: flex-start !important; } .align-content-xxl-end { align-content: flex-end !important; } .align-content-xxl-center { align-content: center !important; } .align-content-xxl-between { align-content: space-between !important; } .align-content-xxl-around { align-content: space-around !important; } .align-content-xxl-stretch { align-content: stretch !important; } .align-self-xxl-auto { align-self: auto !important; } .align-self-xxl-start { align-self: flex-start !important; } .align-self-xxl-end { align-self: flex-end !important; } .align-self-xxl-center { align-self: center !important; } .align-self-xxl-baseline { align-self: baseline !important; } .align-self-xxl-stretch { align-self: stretch !important; } .order-xxl-first { order: -1 !important; } .order-xxl-0 { order: 0 !important; } .order-xxl-1 { order: 1 !important; } .order-xxl-2 { order: 2 !important; } .order-xxl-3 { order: 3 !important; } .order-xxl-4 { order: 4 !important; } .order-xxl-5 { order: 5 !important; } .order-xxl-last { order: 6 !important; } .m-xxl-0 { margin: 0 !important; } .m-xxl-1 { margin: 0.25rem !important; } .m-xxl-2 { margin: 0.5rem !important; } .m-xxl-3 { margin: 1rem !important; } .m-xxl-4 { margin: 1.5rem !important; } .m-xxl-5 { margin: 3rem !important; } .m-xxl-auto { margin: auto !important; } .mx-xxl-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-xxl-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-xxl-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-xxl-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-xxl-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-xxl-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-xxl-auto { margin-left: auto !important; margin-right: auto !important; } .my-xxl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-xxl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xxl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xxl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xxl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xxl-5 { margin-top: 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: 0.25rem !important; } .mt-xxl-2 { margin-top: 0.5rem !important; } .mt-xxl-3 { margin-top: 1rem !important; } .mt-xxl-4 { margin-top: 1.5rem !important; } .mt-xxl-5 { margin-top: 3rem !important; } .mt-xxl-auto { margin-top: auto !important; } .me-xxl-0 { margin-left: 0 !important; } .me-xxl-1 { margin-left: 0.25rem !important; } .me-xxl-2 { margin-left: 0.5rem !important; } .me-xxl-3 { margin-left: 1rem !important; } .me-xxl-4 { margin-left: 1.5rem !important; } .me-xxl-5 { margin-left: 3rem !important; } .me-xxl-auto { margin-left: auto !important; } .mb-xxl-0 { margin-bottom: 0 !important; } .mb-xxl-1 { margin-bottom: 0.25rem !important; } .mb-xxl-2 { margin-bottom: 0.5rem !important; } .mb-xxl-3 { margin-bottom: 1rem !important; } .mb-xxl-4 { margin-bottom: 1.5rem !important; } .mb-xxl-5 { margin-bottom: 3rem !important; } .mb-xxl-auto { margin-bottom: auto !important; } .ms-xxl-0 { margin-right: 0 !important; } .ms-xxl-1 { margin-right: 0.25rem !important; } .ms-xxl-2 { margin-right: 0.5rem !important; } .ms-xxl-3 { margin-right: 1rem !important; } .ms-xxl-4 { margin-right: 1.5rem !important; } .ms-xxl-5 { margin-right: 3rem !important; } .ms-xxl-auto { margin-right: auto !important; } .p-xxl-0 { padding: 0 !important; } .p-xxl-1 { padding: 0.25rem !important; } .p-xxl-2 { padding: 0.5rem !important; } .p-xxl-3 { padding: 1rem !important; } .p-xxl-4 { padding: 1.5rem !important; } .p-xxl-5 { padding: 3rem !important; } .px-xxl-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-xxl-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-xxl-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-xxl-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-xxl-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-xxl-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-xxl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xxl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xxl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xxl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xxl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xxl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xxl-0 { padding-top: 0 !important; } .pt-xxl-1 { padding-top: 0.25rem !important; } .pt-xxl-2 { padding-top: 0.5rem !important; } .pt-xxl-3 { padding-top: 1rem !important; } .pt-xxl-4 { padding-top: 1.5rem !important; } .pt-xxl-5 { padding-top: 3rem !important; } .pe-xxl-0 { padding-left: 0 !important; } .pe-xxl-1 { padding-left: 0.25rem !important; } .pe-xxl-2 { padding-left: 0.5rem !important; } .pe-xxl-3 { padding-left: 1rem !important; } .pe-xxl-4 { padding-left: 1.5rem !important; } .pe-xxl-5 { padding-left: 3rem !important; } .pb-xxl-0 { padding-bottom: 0 !important; } .pb-xxl-1 { padding-bottom: 0.25rem !important; } .pb-xxl-2 { padding-bottom: 0.5rem !important; } .pb-xxl-3 { padding-bottom: 1rem !important; } .pb-xxl-4 { padding-bottom: 1.5rem !important; } .pb-xxl-5 { padding-bottom: 3rem !important; } .ps-xxl-0 { padding-right: 0 !important; } .ps-xxl-1 { padding-right: 0.25rem !important; } .ps-xxl-2 { padding-right: 0.5rem !important; } .ps-xxl-3 { padding-right: 1rem !important; } .ps-xxl-4 { padding-right: 1.5rem !important; } .ps-xxl-5 { padding-right: 3rem !important; } } @media print { .d-print-inline { display: inline !important; } .d-print-inline-block { display: inline-block !important; } .d-print-block { display: block !important; } .d-print-grid { display: grid !important; } .d-print-table { display: table !important; } .d-print-table-row { display: table-row !important; } .d-print-table-cell { display: table-cell !important; } .d-print-flex { display: flex !important; } .d-print-inline-flex { display: inline-flex !important; } .d-print-none { display: none !important; } } /*# sourceMappingURL=bootstrap-grid.rtl.css.map */ ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.css ================================================ /*! * Bootstrap Reboot 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) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */ *, *::before, *::after { box-sizing: border-box; } @media (prefers-reduced-motion: no-preference) { :root { scroll-behavior: smooth; } } body { margin: 0; font-family: var(--bs-body-font-family); font-size: var(--bs-body-font-size); font-weight: var(--bs-body-font-weight); line-height: var(--bs-body-line-height); color: var(--bs-body-color); text-align: var(--bs-body-text-align); background-color: var(--bs-body-bg); -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } hr { margin: 1rem 0; color: inherit; background-color: currentColor; border: 0; opacity: 0.25; } hr:not([size]) { height: 1px; } h6, h5, h4, h3, h2, h1 { margin-top: 0; margin-bottom: 0.5rem; font-weight: 500; line-height: 1.2; } h1 { font-size: calc(1.375rem + 1.5vw); } @media (min-width: 1200px) { h1 { font-size: 2.5rem; } } h2 { font-size: calc(1.325rem + 0.9vw); } @media (min-width: 1200px) { h2 { font-size: 2rem; } } h3 { font-size: calc(1.3rem + 0.6vw); } @media (min-width: 1200px) { h3 { font-size: 1.75rem; } } h4 { font-size: calc(1.275rem + 0.3vw); } @media (min-width: 1200px) { h4 { font-size: 1.5rem; } } h5 { font-size: 1.25rem; } h6 { font-size: 1rem; } p { margin-top: 0; margin-bottom: 1rem; } abbr[title], abbr[data-bs-original-title] { -webkit-text-decoration: underline dotted; text-decoration: underline dotted; cursor: help; -webkit-text-decoration-skip-ink: none; text-decoration-skip-ink: none; } address { margin-bottom: 1rem; font-style: normal; line-height: inherit; } ol, ul { padding-left: 2rem; } ol, ul, dl { margin-top: 0; margin-bottom: 1rem; } ol ol, ul ul, ol ul, ul ol { margin-bottom: 0; } dt { font-weight: 700; } dd { margin-bottom: 0.5rem; margin-left: 0; } blockquote { margin: 0 0 1rem; } b, strong { font-weight: bolder; } small { font-size: 0.875em; } mark { padding: 0.2em; background-color: #fcf8e3; } sub, sup { position: relative; font-size: 0.75em; line-height: 0; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.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; } pre, code, kbd, samp { font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 1em; direction: ltr /* rtl:ignore */; unicode-bidi: bidi-override; } pre { display: block; margin-top: 0; margin-bottom: 1rem; overflow: auto; font-size: 0.875em; } pre code { font-size: inherit; color: inherit; word-break: normal; } code { font-size: 0.875em; color: #d63384; word-wrap: break-word; } a > code { color: inherit; } kbd { padding: 0.2rem 0.4rem; font-size: 0.875em; color: #fff; background-color: #212529; border-radius: 0.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: 0.5rem; padding-bottom: 0.5rem; color: #6c757d; text-align: left; } th { text-align: inherit; text-align: -webkit-match-parent; } thead, tbody, tfoot, tr, td, th { border-color: inherit; border-style: solid; border-width: 0; } label { display: inline-block; } button { border-radius: 0; } button:focus:not(:focus-visible) { outline: 0; } input, button, select, optgroup, textarea { margin: 0; font-family: inherit; font-size: inherit; line-height: inherit; } button, select { text-transform: none; } [role=button] { cursor: pointer; } select { word-wrap: normal; } select:disabled { opacity: 1; } [list]::-webkit-calendar-picker-indicator { display: none; } button, [type=button], [type=reset], [type=submit] { -webkit-appearance: button; } button:not(:disabled), [type=button]:not(:disabled), [type=reset]:not(:disabled), [type=submit]:not(:disabled) { cursor: pointer; } ::-moz-focus-inner { padding: 0; border-style: none; } textarea { resize: vertical; } fieldset { min-width: 0; padding: 0; margin: 0; border: 0; } legend { float: left; width: 100%; padding: 0; margin-bottom: 0.5rem; font-size: calc(1.275rem + 0.3vw); line-height: inherit; } @media (min-width: 1200px) { legend { font-size: 1.5rem; } } legend + * { clear: left; } ::-webkit-datetime-edit-fields-wrapper, ::-webkit-datetime-edit-text, ::-webkit-datetime-edit-minute, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-year-field { padding: 0; } ::-webkit-inner-spin-button { height: auto; } [type=search] { outline-offset: -2px; -webkit-appearance: textfield; } /* rtl:raw: [type="tel"], [type="url"], [type="email"], [type="number"] { direction: ltr; } */ ::-webkit-search-decoration { -webkit-appearance: none; } ::-webkit-color-swatch-wrapper { padding: 0; } ::file-selector-button { font: inherit; } ::-webkit-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; } /*# sourceMappingURL=bootstrap-reboot.css.map */ ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.rtl.css ================================================ /*! * Bootstrap Reboot 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) * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) */ *, *::before, *::after { box-sizing: border-box; } @media (prefers-reduced-motion: no-preference) { :root { scroll-behavior: smooth; } } body { margin: 0; font-family: var(--bs-body-font-family); font-size: var(--bs-body-font-size); font-weight: var(--bs-body-font-weight); line-height: var(--bs-body-line-height); color: var(--bs-body-color); text-align: var(--bs-body-text-align); background-color: var(--bs-body-bg); -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } hr { margin: 1rem 0; color: inherit; background-color: currentColor; border: 0; opacity: 0.25; } hr:not([size]) { height: 1px; } h6, h5, h4, h3, h2, h1 { margin-top: 0; margin-bottom: 0.5rem; font-weight: 500; line-height: 1.2; } h1 { font-size: calc(1.375rem + 1.5vw); } @media (min-width: 1200px) { h1 { font-size: 2.5rem; } } h2 { font-size: calc(1.325rem + 0.9vw); } @media (min-width: 1200px) { h2 { font-size: 2rem; } } h3 { font-size: calc(1.3rem + 0.6vw); } @media (min-width: 1200px) { h3 { font-size: 1.75rem; } } h4 { font-size: calc(1.275rem + 0.3vw); } @media (min-width: 1200px) { h4 { font-size: 1.5rem; } } h5 { font-size: 1.25rem; } h6 { font-size: 1rem; } p { margin-top: 0; margin-bottom: 1rem; } abbr[title], abbr[data-bs-original-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-right: 2rem; } ol, ul, dl { margin-top: 0; margin-bottom: 1rem; } ol ol, ul ul, ol ul, ul ol { margin-bottom: 0; } dt { font-weight: 700; } dd { margin-bottom: 0.5rem; margin-right: 0; } blockquote { margin: 0 0 1rem; } b, strong { font-weight: bolder; } small { font-size: 0.875em; } mark { padding: 0.2em; background-color: #fcf8e3; } sub, sup { position: relative; font-size: 0.75em; line-height: 0; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.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; } pre, code, kbd, samp { font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 1em; direction: ltr ; unicode-bidi: bidi-override; } pre { display: block; margin-top: 0; margin-bottom: 1rem; overflow: auto; font-size: 0.875em; } pre code { font-size: inherit; color: inherit; word-break: normal; } code { font-size: 0.875em; color: #d63384; word-wrap: break-word; } a > code { color: inherit; } kbd { padding: 0.2rem 0.4rem; font-size: 0.875em; color: #fff; background-color: #212529; border-radius: 0.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: 0.5rem; padding-bottom: 0.5rem; color: #6c757d; text-align: right; } th { text-align: inherit; text-align: -webkit-match-parent; } thead, tbody, tfoot, tr, td, th { border-color: inherit; border-style: solid; border-width: 0; } label { display: inline-block; } button { border-radius: 0; } button:focus:not(:focus-visible) { outline: 0; } input, button, select, optgroup, textarea { margin: 0; font-family: inherit; font-size: inherit; line-height: inherit; } button, select { text-transform: none; } [role=button] { cursor: pointer; } select { word-wrap: normal; } select:disabled { opacity: 1; } [list]::-webkit-calendar-picker-indicator { display: none; } button, [type=button], [type=reset], [type=submit] { -webkit-appearance: button; } button:not(:disabled), [type=button]:not(:disabled), [type=reset]:not(:disabled), [type=submit]:not(:disabled) { cursor: pointer; } ::-moz-focus-inner { padding: 0; border-style: none; } textarea { resize: vertical; } fieldset { min-width: 0; padding: 0; margin: 0; border: 0; } legend { float: right; width: 100%; padding: 0; margin-bottom: 0.5rem; font-size: calc(1.275rem + 0.3vw); line-height: inherit; } @media (min-width: 1200px) { legend { font-size: 1.5rem; } } legend + * { clear: right; } ::-webkit-datetime-edit-fields-wrapper, ::-webkit-datetime-edit-text, ::-webkit-datetime-edit-minute, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-year-field { padding: 0; } ::-webkit-inner-spin-button { height: auto; } [type=search] { outline-offset: -2px; -webkit-appearance: textfield; } [type="tel"], [type="url"], [type="email"], [type="number"] { direction: ltr; } ::-webkit-search-decoration { -webkit-appearance: none; } ::-webkit-color-swatch-wrapper { padding: 0; } ::file-selector-button { font: inherit; } ::-webkit-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; } /*# sourceMappingURL=bootstrap-reboot.rtl.css.map */ ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.css ================================================ /*! * Bootstrap Utilities 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) */ .clearfix::after { display: block; clear: both; content: ""; } .link-primary { color: #0d6efd; } .link-primary:hover, .link-primary:focus { color: #0a58ca; } .link-secondary { color: #6c757d; } .link-secondary:hover, .link-secondary:focus { color: #565e64; } .link-success { color: #198754; } .link-success:hover, .link-success:focus { color: #146c43; } .link-info { color: #0dcaf0; } .link-info:hover, .link-info:focus { color: #3dd5f3; } .link-warning { color: #ffc107; } .link-warning:hover, .link-warning:focus { color: #ffcd39; } .link-danger { color: #dc3545; } .link-danger:hover, .link-danger:focus { color: #b02a37; } .link-light { color: #f8f9fa; } .link-light:hover, .link-light:focus { color: #f9fafb; } .link-dark { color: #212529; } .link-dark:hover, .link-dark:focus { 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: 0.25; } .align-baseline { vertical-align: baseline !important; } .align-top { vertical-align: top !important; } .align-middle { vertical-align: middle !important; } .align-bottom { vertical-align: bottom !important; } .align-text-bottom { vertical-align: text-bottom !important; } .align-text-top { vertical-align: text-top !important; } .float-start { float: left !important; } .float-end { float: right !important; } .float-none { float: none !important; } .opacity-0 { opacity: 0 !important; } .opacity-25 { opacity: 0.25 !important; } .opacity-50 { opacity: 0.5 !important; } .opacity-75 { opacity: 0.75 !important; } .opacity-100 { opacity: 1 !important; } .overflow-auto { overflow: auto !important; } .overflow-hidden { overflow: hidden !important; } .overflow-visible { overflow: visible !important; } .overflow-scroll { overflow: scroll !important; } .d-inline { display: inline !important; } .d-inline-block { display: inline-block !important; } .d-block { display: block !important; } .d-grid { display: grid !important; } .d-table { display: table !important; } .d-table-row { display: table-row !important; } .d-table-cell { display: table-cell !important; } .d-flex { display: flex !important; } .d-inline-flex { display: inline-flex !important; } .d-none { display: none !important; } .shadow { box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; } .shadow-sm { box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; } .shadow-lg { box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; } .shadow-none { box-shadow: none !important; } .position-static { position: static !important; } .position-relative { position: relative !important; } .position-absolute { position: absolute !important; } .position-fixed { position: fixed !important; } .position-sticky { position: -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: 0.25rem !important; } .gap-2 { gap: 0.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: 0.25rem !important; } .m-2 { margin: 0.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: 0.25rem !important; margin-left: 0.25rem !important; } .mx-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-5 { margin-top: 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: 0.25rem !important; } .mt-2 { margin-top: 0.5rem !important; } .mt-3 { margin-top: 1rem !important; } .mt-4 { margin-top: 1.5rem !important; } .mt-5 { margin-top: 3rem !important; } .mt-auto { margin-top: auto !important; } .me-0 { margin-right: 0 !important; } .me-1 { margin-right: 0.25rem !important; } .me-2 { margin-right: 0.5rem !important; } .me-3 { margin-right: 1rem !important; } .me-4 { margin-right: 1.5rem !important; } .me-5 { margin-right: 3rem !important; } .me-auto { margin-right: auto !important; } .mb-0 { margin-bottom: 0 !important; } .mb-1 { margin-bottom: 0.25rem !important; } .mb-2 { margin-bottom: 0.5rem !important; } .mb-3 { margin-bottom: 1rem !important; } .mb-4 { margin-bottom: 1.5rem !important; } .mb-5 { margin-bottom: 3rem !important; } .mb-auto { margin-bottom: auto !important; } .ms-0 { margin-left: 0 !important; } .ms-1 { margin-left: 0.25rem !important; } .ms-2 { margin-left: 0.5rem !important; } .ms-3 { margin-left: 1rem !important; } .ms-4 { margin-left: 1.5rem !important; } .ms-5 { margin-left: 3rem !important; } .ms-auto { margin-left: auto !important; } .p-0 { padding: 0 !important; } .p-1 { padding: 0.25rem !important; } .p-2 { padding: 0.5rem !important; } .p-3 { padding: 1rem !important; } .p-4 { padding: 1.5rem !important; } .p-5 { padding: 3rem !important; } .px-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-0 { padding-top: 0 !important; } .pt-1 { padding-top: 0.25rem !important; } .pt-2 { padding-top: 0.5rem !important; } .pt-3 { padding-top: 1rem !important; } .pt-4 { padding-top: 1.5rem !important; } .pt-5 { padding-top: 3rem !important; } .pe-0 { padding-right: 0 !important; } .pe-1 { padding-right: 0.25rem !important; } .pe-2 { padding-right: 0.5rem !important; } .pe-3 { padding-right: 1rem !important; } .pe-4 { padding-right: 1.5rem !important; } .pe-5 { padding-right: 3rem !important; } .pb-0 { padding-bottom: 0 !important; } .pb-1 { padding-bottom: 0.25rem !important; } .pb-2 { padding-bottom: 0.5rem !important; } .pb-3 { padding-bottom: 1rem !important; } .pb-4 { padding-bottom: 1.5rem !important; } .pb-5 { padding-bottom: 3rem !important; } .ps-0 { padding-left: 0 !important; } .ps-1 { padding-left: 0.25rem !important; } .ps-2 { padding-left: 0.5rem !important; } .ps-3 { padding-left: 1rem !important; } .ps-4 { padding-left: 1.5rem !important; } .ps-5 { padding-left: 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 + 0.9vw) !important; } .fs-3 { font-size: calc(1.3rem + 0.6vw) !important; } .fs-4 { font-size: calc(1.275rem + 0.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; } /* rtl:begin:remove */ .text-break { word-wrap: break-word !important; word-break: break-word !important; } /* rtl:end:remove */ .text-primary { --bs-text-opacity: 1; color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important; } .text-secondary { --bs-text-opacity: 1; color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important; } .text-success { --bs-text-opacity: 1; color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important; } .text-info { --bs-text-opacity: 1; color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important; } .text-warning { --bs-text-opacity: 1; color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important; } .text-danger { --bs-text-opacity: 1; color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important; } .text-light { --bs-text-opacity: 1; color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important; } .text-dark { --bs-text-opacity: 1; color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important; } .text-black { --bs-text-opacity: 1; color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important; } .text-white { --bs-text-opacity: 1; color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important; } .text-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, 0.5) !important; } .text-white-50 { --bs-text-opacity: 1; color: rgba(255, 255, 255, 0.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: 0.25rem !important; } .rounded-0 { border-radius: 0 !important; } .rounded-1 { border-radius: 0.2rem !important; } .rounded-2 { border-radius: 0.25rem !important; } .rounded-3 { border-radius: 0.3rem !important; } .rounded-circle { border-radius: 50% !important; } .rounded-pill { border-radius: 50rem !important; } .rounded-top { border-top-left-radius: 0.25rem !important; border-top-right-radius: 0.25rem !important; } .rounded-end { border-top-right-radius: 0.25rem !important; border-bottom-right-radius: 0.25rem !important; } .rounded-bottom { border-bottom-right-radius: 0.25rem !important; border-bottom-left-radius: 0.25rem !important; } .rounded-start { border-bottom-left-radius: 0.25rem !important; border-top-left-radius: 0.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: 0.25rem !important; } .gap-sm-2 { gap: 0.5rem !important; } .gap-sm-3 { gap: 1rem !important; } .gap-sm-4 { gap: 1.5rem !important; } .gap-sm-5 { gap: 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: 0.25rem !important; } .m-sm-2 { margin: 0.5rem !important; } .m-sm-3 { margin: 1rem !important; } .m-sm-4 { margin: 1.5rem !important; } .m-sm-5 { margin: 3rem !important; } .m-sm-auto { margin: auto !important; } .mx-sm-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-sm-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-sm-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-sm-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-sm-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-sm-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-sm-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-sm-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-sm-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-sm-5 { margin-top: 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: 0.25rem !important; } .mt-sm-2 { margin-top: 0.5rem !important; } .mt-sm-3 { margin-top: 1rem !important; } .mt-sm-4 { margin-top: 1.5rem !important; } .mt-sm-5 { margin-top: 3rem !important; } .mt-sm-auto { margin-top: auto !important; } .me-sm-0 { margin-right: 0 !important; } .me-sm-1 { margin-right: 0.25rem !important; } .me-sm-2 { margin-right: 0.5rem !important; } .me-sm-3 { margin-right: 1rem !important; } .me-sm-4 { margin-right: 1.5rem !important; } .me-sm-5 { margin-right: 3rem !important; } .me-sm-auto { margin-right: auto !important; } .mb-sm-0 { margin-bottom: 0 !important; } .mb-sm-1 { margin-bottom: 0.25rem !important; } .mb-sm-2 { margin-bottom: 0.5rem !important; } .mb-sm-3 { margin-bottom: 1rem !important; } .mb-sm-4 { margin-bottom: 1.5rem !important; } .mb-sm-5 { margin-bottom: 3rem !important; } .mb-sm-auto { margin-bottom: auto !important; } .ms-sm-0 { margin-left: 0 !important; } .ms-sm-1 { margin-left: 0.25rem !important; } .ms-sm-2 { margin-left: 0.5rem !important; } .ms-sm-3 { margin-left: 1rem !important; } .ms-sm-4 { margin-left: 1.5rem !important; } .ms-sm-5 { margin-left: 3rem !important; } .ms-sm-auto { margin-left: auto !important; } .p-sm-0 { padding: 0 !important; } .p-sm-1 { padding: 0.25rem !important; } .p-sm-2 { padding: 0.5rem !important; } .p-sm-3 { padding: 1rem !important; } .p-sm-4 { padding: 1.5rem !important; } .p-sm-5 { padding: 3rem !important; } .px-sm-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-sm-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-sm-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-sm-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-sm-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-sm-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-sm-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-sm-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-sm-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-sm-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-sm-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-sm-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-sm-0 { padding-top: 0 !important; } .pt-sm-1 { padding-top: 0.25rem !important; } .pt-sm-2 { padding-top: 0.5rem !important; } .pt-sm-3 { padding-top: 1rem !important; } .pt-sm-4 { padding-top: 1.5rem !important; } .pt-sm-5 { padding-top: 3rem !important; } .pe-sm-0 { padding-right: 0 !important; } .pe-sm-1 { padding-right: 0.25rem !important; } .pe-sm-2 { padding-right: 0.5rem !important; } .pe-sm-3 { padding-right: 1rem !important; } .pe-sm-4 { padding-right: 1.5rem !important; } .pe-sm-5 { padding-right: 3rem !important; } .pb-sm-0 { padding-bottom: 0 !important; } .pb-sm-1 { padding-bottom: 0.25rem !important; } .pb-sm-2 { padding-bottom: 0.5rem !important; } .pb-sm-3 { padding-bottom: 1rem !important; } .pb-sm-4 { padding-bottom: 1.5rem !important; } .pb-sm-5 { padding-bottom: 3rem !important; } .ps-sm-0 { padding-left: 0 !important; } .ps-sm-1 { padding-left: 0.25rem !important; } .ps-sm-2 { padding-left: 0.5rem !important; } .ps-sm-3 { padding-left: 1rem !important; } .ps-sm-4 { padding-left: 1.5rem !important; } .ps-sm-5 { padding-left: 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: 0.25rem !important; } .gap-md-2 { gap: 0.5rem !important; } .gap-md-3 { gap: 1rem !important; } .gap-md-4 { gap: 1.5rem !important; } .gap-md-5 { gap: 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: 0.25rem !important; } .m-md-2 { margin: 0.5rem !important; } .m-md-3 { margin: 1rem !important; } .m-md-4 { margin: 1.5rem !important; } .m-md-5 { margin: 3rem !important; } .m-md-auto { margin: auto !important; } .mx-md-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-md-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-md-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-md-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-md-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-md-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-md-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-md-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-md-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-md-5 { margin-top: 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: 0.25rem !important; } .mt-md-2 { margin-top: 0.5rem !important; } .mt-md-3 { margin-top: 1rem !important; } .mt-md-4 { margin-top: 1.5rem !important; } .mt-md-5 { margin-top: 3rem !important; } .mt-md-auto { margin-top: auto !important; } .me-md-0 { margin-right: 0 !important; } .me-md-1 { margin-right: 0.25rem !important; } .me-md-2 { margin-right: 0.5rem !important; } .me-md-3 { margin-right: 1rem !important; } .me-md-4 { margin-right: 1.5rem !important; } .me-md-5 { margin-right: 3rem !important; } .me-md-auto { margin-right: auto !important; } .mb-md-0 { margin-bottom: 0 !important; } .mb-md-1 { margin-bottom: 0.25rem !important; } .mb-md-2 { margin-bottom: 0.5rem !important; } .mb-md-3 { margin-bottom: 1rem !important; } .mb-md-4 { margin-bottom: 1.5rem !important; } .mb-md-5 { margin-bottom: 3rem !important; } .mb-md-auto { margin-bottom: auto !important; } .ms-md-0 { margin-left: 0 !important; } .ms-md-1 { margin-left: 0.25rem !important; } .ms-md-2 { margin-left: 0.5rem !important; } .ms-md-3 { margin-left: 1rem !important; } .ms-md-4 { margin-left: 1.5rem !important; } .ms-md-5 { margin-left: 3rem !important; } .ms-md-auto { margin-left: auto !important; } .p-md-0 { padding: 0 !important; } .p-md-1 { padding: 0.25rem !important; } .p-md-2 { padding: 0.5rem !important; } .p-md-3 { padding: 1rem !important; } .p-md-4 { padding: 1.5rem !important; } .p-md-5 { padding: 3rem !important; } .px-md-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-md-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-md-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-md-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-md-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-md-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-md-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-md-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-md-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-md-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-md-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-md-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-md-0 { padding-top: 0 !important; } .pt-md-1 { padding-top: 0.25rem !important; } .pt-md-2 { padding-top: 0.5rem !important; } .pt-md-3 { padding-top: 1rem !important; } .pt-md-4 { padding-top: 1.5rem !important; } .pt-md-5 { padding-top: 3rem !important; } .pe-md-0 { padding-right: 0 !important; } .pe-md-1 { padding-right: 0.25rem !important; } .pe-md-2 { padding-right: 0.5rem !important; } .pe-md-3 { padding-right: 1rem !important; } .pe-md-4 { padding-right: 1.5rem !important; } .pe-md-5 { padding-right: 3rem !important; } .pb-md-0 { padding-bottom: 0 !important; } .pb-md-1 { padding-bottom: 0.25rem !important; } .pb-md-2 { padding-bottom: 0.5rem !important; } .pb-md-3 { padding-bottom: 1rem !important; } .pb-md-4 { padding-bottom: 1.5rem !important; } .pb-md-5 { padding-bottom: 3rem !important; } .ps-md-0 { padding-left: 0 !important; } .ps-md-1 { padding-left: 0.25rem !important; } .ps-md-2 { padding-left: 0.5rem !important; } .ps-md-3 { padding-left: 1rem !important; } .ps-md-4 { padding-left: 1.5rem !important; } .ps-md-5 { padding-left: 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: 0.25rem !important; } .gap-lg-2 { gap: 0.5rem !important; } .gap-lg-3 { gap: 1rem !important; } .gap-lg-4 { gap: 1.5rem !important; } .gap-lg-5 { gap: 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: 0.25rem !important; } .m-lg-2 { margin: 0.5rem !important; } .m-lg-3 { margin: 1rem !important; } .m-lg-4 { margin: 1.5rem !important; } .m-lg-5 { margin: 3rem !important; } .m-lg-auto { margin: auto !important; } .mx-lg-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-lg-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-lg-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-lg-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-lg-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-lg-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-lg-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-lg-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-lg-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-lg-5 { margin-top: 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: 0.25rem !important; } .mt-lg-2 { margin-top: 0.5rem !important; } .mt-lg-3 { margin-top: 1rem !important; } .mt-lg-4 { margin-top: 1.5rem !important; } .mt-lg-5 { margin-top: 3rem !important; } .mt-lg-auto { margin-top: auto !important; } .me-lg-0 { margin-right: 0 !important; } .me-lg-1 { margin-right: 0.25rem !important; } .me-lg-2 { margin-right: 0.5rem !important; } .me-lg-3 { margin-right: 1rem !important; } .me-lg-4 { margin-right: 1.5rem !important; } .me-lg-5 { margin-right: 3rem !important; } .me-lg-auto { margin-right: auto !important; } .mb-lg-0 { margin-bottom: 0 !important; } .mb-lg-1 { margin-bottom: 0.25rem !important; } .mb-lg-2 { margin-bottom: 0.5rem !important; } .mb-lg-3 { margin-bottom: 1rem !important; } .mb-lg-4 { margin-bottom: 1.5rem !important; } .mb-lg-5 { margin-bottom: 3rem !important; } .mb-lg-auto { margin-bottom: auto !important; } .ms-lg-0 { margin-left: 0 !important; } .ms-lg-1 { margin-left: 0.25rem !important; } .ms-lg-2 { margin-left: 0.5rem !important; } .ms-lg-3 { margin-left: 1rem !important; } .ms-lg-4 { margin-left: 1.5rem !important; } .ms-lg-5 { margin-left: 3rem !important; } .ms-lg-auto { margin-left: auto !important; } .p-lg-0 { padding: 0 !important; } .p-lg-1 { padding: 0.25rem !important; } .p-lg-2 { padding: 0.5rem !important; } .p-lg-3 { padding: 1rem !important; } .p-lg-4 { padding: 1.5rem !important; } .p-lg-5 { padding: 3rem !important; } .px-lg-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-lg-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-lg-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-lg-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-lg-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-lg-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-lg-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-lg-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-lg-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-lg-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-lg-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-lg-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-lg-0 { padding-top: 0 !important; } .pt-lg-1 { padding-top: 0.25rem !important; } .pt-lg-2 { padding-top: 0.5rem !important; } .pt-lg-3 { padding-top: 1rem !important; } .pt-lg-4 { padding-top: 1.5rem !important; } .pt-lg-5 { padding-top: 3rem !important; } .pe-lg-0 { padding-right: 0 !important; } .pe-lg-1 { padding-right: 0.25rem !important; } .pe-lg-2 { padding-right: 0.5rem !important; } .pe-lg-3 { padding-right: 1rem !important; } .pe-lg-4 { padding-right: 1.5rem !important; } .pe-lg-5 { padding-right: 3rem !important; } .pb-lg-0 { padding-bottom: 0 !important; } .pb-lg-1 { padding-bottom: 0.25rem !important; } .pb-lg-2 { padding-bottom: 0.5rem !important; } .pb-lg-3 { padding-bottom: 1rem !important; } .pb-lg-4 { padding-bottom: 1.5rem !important; } .pb-lg-5 { padding-bottom: 3rem !important; } .ps-lg-0 { padding-left: 0 !important; } .ps-lg-1 { padding-left: 0.25rem !important; } .ps-lg-2 { padding-left: 0.5rem !important; } .ps-lg-3 { padding-left: 1rem !important; } .ps-lg-4 { padding-left: 1.5rem !important; } .ps-lg-5 { padding-left: 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: 0.25rem !important; } .gap-xl-2 { gap: 0.5rem !important; } .gap-xl-3 { gap: 1rem !important; } .gap-xl-4 { gap: 1.5rem !important; } .gap-xl-5 { gap: 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: 0.25rem !important; } .m-xl-2 { margin: 0.5rem !important; } .m-xl-3 { margin: 1rem !important; } .m-xl-4 { margin: 1.5rem !important; } .m-xl-5 { margin: 3rem !important; } .m-xl-auto { margin: auto !important; } .mx-xl-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-xl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-xl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-xl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-xl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-xl-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xl-5 { margin-top: 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: 0.25rem !important; } .mt-xl-2 { margin-top: 0.5rem !important; } .mt-xl-3 { margin-top: 1rem !important; } .mt-xl-4 { margin-top: 1.5rem !important; } .mt-xl-5 { margin-top: 3rem !important; } .mt-xl-auto { margin-top: auto !important; } .me-xl-0 { margin-right: 0 !important; } .me-xl-1 { margin-right: 0.25rem !important; } .me-xl-2 { margin-right: 0.5rem !important; } .me-xl-3 { margin-right: 1rem !important; } .me-xl-4 { margin-right: 1.5rem !important; } .me-xl-5 { margin-right: 3rem !important; } .me-xl-auto { margin-right: auto !important; } .mb-xl-0 { margin-bottom: 0 !important; } .mb-xl-1 { margin-bottom: 0.25rem !important; } .mb-xl-2 { margin-bottom: 0.5rem !important; } .mb-xl-3 { margin-bottom: 1rem !important; } .mb-xl-4 { margin-bottom: 1.5rem !important; } .mb-xl-5 { margin-bottom: 3rem !important; } .mb-xl-auto { margin-bottom: auto !important; } .ms-xl-0 { margin-left: 0 !important; } .ms-xl-1 { margin-left: 0.25rem !important; } .ms-xl-2 { margin-left: 0.5rem !important; } .ms-xl-3 { margin-left: 1rem !important; } .ms-xl-4 { margin-left: 1.5rem !important; } .ms-xl-5 { margin-left: 3rem !important; } .ms-xl-auto { margin-left: auto !important; } .p-xl-0 { padding: 0 !important; } .p-xl-1 { padding: 0.25rem !important; } .p-xl-2 { padding: 0.5rem !important; } .p-xl-3 { padding: 1rem !important; } .p-xl-4 { padding: 1.5rem !important; } .p-xl-5 { padding: 3rem !important; } .px-xl-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-xl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-xl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-xl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-xl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-xl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-xl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xl-0 { padding-top: 0 !important; } .pt-xl-1 { padding-top: 0.25rem !important; } .pt-xl-2 { padding-top: 0.5rem !important; } .pt-xl-3 { padding-top: 1rem !important; } .pt-xl-4 { padding-top: 1.5rem !important; } .pt-xl-5 { padding-top: 3rem !important; } .pe-xl-0 { padding-right: 0 !important; } .pe-xl-1 { padding-right: 0.25rem !important; } .pe-xl-2 { padding-right: 0.5rem !important; } .pe-xl-3 { padding-right: 1rem !important; } .pe-xl-4 { padding-right: 1.5rem !important; } .pe-xl-5 { padding-right: 3rem !important; } .pb-xl-0 { padding-bottom: 0 !important; } .pb-xl-1 { padding-bottom: 0.25rem !important; } .pb-xl-2 { padding-bottom: 0.5rem !important; } .pb-xl-3 { padding-bottom: 1rem !important; } .pb-xl-4 { padding-bottom: 1.5rem !important; } .pb-xl-5 { padding-bottom: 3rem !important; } .ps-xl-0 { padding-left: 0 !important; } .ps-xl-1 { padding-left: 0.25rem !important; } .ps-xl-2 { padding-left: 0.5rem !important; } .ps-xl-3 { padding-left: 1rem !important; } .ps-xl-4 { padding-left: 1.5rem !important; } .ps-xl-5 { padding-left: 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: 0.25rem !important; } .gap-xxl-2 { gap: 0.5rem !important; } .gap-xxl-3 { gap: 1rem !important; } .gap-xxl-4 { gap: 1.5rem !important; } .gap-xxl-5 { gap: 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: 0.25rem !important; } .m-xxl-2 { margin: 0.5rem !important; } .m-xxl-3 { margin: 1rem !important; } .m-xxl-4 { margin: 1.5rem !important; } .m-xxl-5 { margin: 3rem !important; } .m-xxl-auto { margin: auto !important; } .mx-xxl-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-xxl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-xxl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-xxl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-xxl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-xxl-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xxl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xxl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xxl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xxl-5 { margin-top: 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: 0.25rem !important; } .mt-xxl-2 { margin-top: 0.5rem !important; } .mt-xxl-3 { margin-top: 1rem !important; } .mt-xxl-4 { margin-top: 1.5rem !important; } .mt-xxl-5 { margin-top: 3rem !important; } .mt-xxl-auto { margin-top: auto !important; } .me-xxl-0 { margin-right: 0 !important; } .me-xxl-1 { margin-right: 0.25rem !important; } .me-xxl-2 { margin-right: 0.5rem !important; } .me-xxl-3 { margin-right: 1rem !important; } .me-xxl-4 { margin-right: 1.5rem !important; } .me-xxl-5 { margin-right: 3rem !important; } .me-xxl-auto { margin-right: auto !important; } .mb-xxl-0 { margin-bottom: 0 !important; } .mb-xxl-1 { margin-bottom: 0.25rem !important; } .mb-xxl-2 { margin-bottom: 0.5rem !important; } .mb-xxl-3 { margin-bottom: 1rem !important; } .mb-xxl-4 { margin-bottom: 1.5rem !important; } .mb-xxl-5 { margin-bottom: 3rem !important; } .mb-xxl-auto { margin-bottom: auto !important; } .ms-xxl-0 { margin-left: 0 !important; } .ms-xxl-1 { margin-left: 0.25rem !important; } .ms-xxl-2 { margin-left: 0.5rem !important; } .ms-xxl-3 { margin-left: 1rem !important; } .ms-xxl-4 { margin-left: 1.5rem !important; } .ms-xxl-5 { margin-left: 3rem !important; } .ms-xxl-auto { margin-left: auto !important; } .p-xxl-0 { padding: 0 !important; } .p-xxl-1 { padding: 0.25rem !important; } .p-xxl-2 { padding: 0.5rem !important; } .p-xxl-3 { padding: 1rem !important; } .p-xxl-4 { padding: 1.5rem !important; } .p-xxl-5 { padding: 3rem !important; } .px-xxl-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-xxl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-xxl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-xxl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-xxl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-xxl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-xxl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xxl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xxl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xxl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xxl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xxl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xxl-0 { padding-top: 0 !important; } .pt-xxl-1 { padding-top: 0.25rem !important; } .pt-xxl-2 { padding-top: 0.5rem !important; } .pt-xxl-3 { padding-top: 1rem !important; } .pt-xxl-4 { padding-top: 1.5rem !important; } .pt-xxl-5 { padding-top: 3rem !important; } .pe-xxl-0 { padding-right: 0 !important; } .pe-xxl-1 { padding-right: 0.25rem !important; } .pe-xxl-2 { padding-right: 0.5rem !important; } .pe-xxl-3 { padding-right: 1rem !important; } .pe-xxl-4 { padding-right: 1.5rem !important; } .pe-xxl-5 { padding-right: 3rem !important; } .pb-xxl-0 { padding-bottom: 0 !important; } .pb-xxl-1 { padding-bottom: 0.25rem !important; } .pb-xxl-2 { padding-bottom: 0.5rem !important; } .pb-xxl-3 { padding-bottom: 1rem !important; } .pb-xxl-4 { padding-bottom: 1.5rem !important; } .pb-xxl-5 { padding-bottom: 3rem !important; } .ps-xxl-0 { padding-left: 0 !important; } .ps-xxl-1 { padding-left: 0.25rem !important; } .ps-xxl-2 { padding-left: 0.5rem !important; } .ps-xxl-3 { padding-left: 1rem !important; } .ps-xxl-4 { padding-left: 1.5rem !important; } .ps-xxl-5 { padding-left: 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-utilities.css.map */ ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/css/bootstrap-utilities.rtl.css ================================================ /*! * Bootstrap Utilities 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) */ .clearfix::after { display: block; clear: both; content: ""; } .link-primary { color: #0d6efd; } .link-primary:hover, .link-primary:focus { color: #0a58ca; } .link-secondary { color: #6c757d; } .link-secondary:hover, .link-secondary:focus { color: #565e64; } .link-success { color: #198754; } .link-success:hover, .link-success:focus { color: #146c43; } .link-info { color: #0dcaf0; } .link-info:hover, .link-info:focus { color: #3dd5f3; } .link-warning { color: #ffc107; } .link-warning:hover, .link-warning:focus { color: #ffcd39; } .link-danger { color: #dc3545; } .link-danger:hover, .link-danger:focus { color: #b02a37; } .link-light { color: #f8f9fa; } .link-light:hover, .link-light:focus { color: #f9fafb; } .link-dark { color: #212529; } .link-dark:hover, .link-dark:focus { color: #1a1e21; } .ratio { position: relative; width: 100%; } .ratio::before { display: block; padding-top: var(--bs-aspect-ratio); content: ""; } .ratio > * { position: absolute; top: 0; right: 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; left: 0; right: 0; z-index: 1030; } .fixed-bottom { position: fixed; left: 0; bottom: 0; right: 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; left: 0; bottom: 0; right: 0; z-index: 1; content: ""; } .text-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .vr { display: inline-block; align-self: stretch; width: 1px; min-height: 1em; background-color: currentColor; opacity: 0.25; } .align-baseline { vertical-align: baseline !important; } .align-top { vertical-align: top !important; } .align-middle { vertical-align: middle !important; } .align-bottom { vertical-align: bottom !important; } .align-text-bottom { vertical-align: text-bottom !important; } .align-text-top { vertical-align: text-top !important; } .float-start { float: right !important; } .float-end { float: left !important; } .float-none { float: none !important; } .opacity-0 { opacity: 0 !important; } .opacity-25 { opacity: 0.25 !important; } .opacity-50 { opacity: 0.5 !important; } .opacity-75 { opacity: 0.75 !important; } .opacity-100 { opacity: 1 !important; } .overflow-auto { overflow: auto !important; } .overflow-hidden { overflow: hidden !important; } .overflow-visible { overflow: visible !important; } .overflow-scroll { overflow: scroll !important; } .d-inline { display: inline !important; } .d-inline-block { display: inline-block !important; } .d-block { display: block !important; } .d-grid { display: grid !important; } .d-table { display: table !important; } .d-table-row { display: table-row !important; } .d-table-cell { display: table-cell !important; } .d-flex { display: flex !important; } .d-inline-flex { display: inline-flex !important; } .d-none { display: none !important; } .shadow { box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; } .shadow-sm { box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; } .shadow-lg { box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; } .shadow-none { box-shadow: none !important; } .position-static { position: static !important; } .position-relative { position: relative !important; } .position-absolute { position: absolute !important; } .position-fixed { position: fixed !important; } .position-sticky { position: -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 { right: 0 !important; } .start-50 { right: 50% !important; } .start-100 { right: 100% !important; } .end-0 { left: 0 !important; } .end-50 { left: 50% !important; } .end-100 { left: 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-left: 1px solid #dee2e6 !important; } .border-end-0 { border-left: 0 !important; } .border-bottom { border-bottom: 1px solid #dee2e6 !important; } .border-bottom-0 { border-bottom: 0 !important; } .border-start { border-right: 1px solid #dee2e6 !important; } .border-start-0 { border-right: 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: 0.25rem !important; } .gap-2 { gap: 0.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: 0.25rem !important; } .m-2 { margin: 0.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-left: 0 !important; margin-right: 0 !important; } .mx-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-auto { margin-left: auto !important; margin-right: auto !important; } .my-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-5 { margin-top: 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: 0.25rem !important; } .mt-2 { margin-top: 0.5rem !important; } .mt-3 { margin-top: 1rem !important; } .mt-4 { margin-top: 1.5rem !important; } .mt-5 { margin-top: 3rem !important; } .mt-auto { margin-top: auto !important; } .me-0 { margin-left: 0 !important; } .me-1 { margin-left: 0.25rem !important; } .me-2 { margin-left: 0.5rem !important; } .me-3 { margin-left: 1rem !important; } .me-4 { margin-left: 1.5rem !important; } .me-5 { margin-left: 3rem !important; } .me-auto { margin-left: auto !important; } .mb-0 { margin-bottom: 0 !important; } .mb-1 { margin-bottom: 0.25rem !important; } .mb-2 { margin-bottom: 0.5rem !important; } .mb-3 { margin-bottom: 1rem !important; } .mb-4 { margin-bottom: 1.5rem !important; } .mb-5 { margin-bottom: 3rem !important; } .mb-auto { margin-bottom: auto !important; } .ms-0 { margin-right: 0 !important; } .ms-1 { margin-right: 0.25rem !important; } .ms-2 { margin-right: 0.5rem !important; } .ms-3 { margin-right: 1rem !important; } .ms-4 { margin-right: 1.5rem !important; } .ms-5 { margin-right: 3rem !important; } .ms-auto { margin-right: auto !important; } .p-0 { padding: 0 !important; } .p-1 { padding: 0.25rem !important; } .p-2 { padding: 0.5rem !important; } .p-3 { padding: 1rem !important; } .p-4 { padding: 1.5rem !important; } .p-5 { padding: 3rem !important; } .px-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-0 { padding-top: 0 !important; } .pt-1 { padding-top: 0.25rem !important; } .pt-2 { padding-top: 0.5rem !important; } .pt-3 { padding-top: 1rem !important; } .pt-4 { padding-top: 1.5rem !important; } .pt-5 { padding-top: 3rem !important; } .pe-0 { padding-left: 0 !important; } .pe-1 { padding-left: 0.25rem !important; } .pe-2 { padding-left: 0.5rem !important; } .pe-3 { padding-left: 1rem !important; } .pe-4 { padding-left: 1.5rem !important; } .pe-5 { padding-left: 3rem !important; } .pb-0 { padding-bottom: 0 !important; } .pb-1 { padding-bottom: 0.25rem !important; } .pb-2 { padding-bottom: 0.5rem !important; } .pb-3 { padding-bottom: 1rem !important; } .pb-4 { padding-bottom: 1.5rem !important; } .pb-5 { padding-bottom: 3rem !important; } .ps-0 { padding-right: 0 !important; } .ps-1 { padding-right: 0.25rem !important; } .ps-2 { padding-right: 0.5rem !important; } .ps-3 { padding-right: 1rem !important; } .ps-4 { padding-right: 1.5rem !important; } .ps-5 { padding-right: 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 + 0.9vw) !important; } .fs-3 { font-size: calc(1.3rem + 0.6vw) !important; } .fs-4 { font-size: calc(1.275rem + 0.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: right !important; } .text-end { text-align: left !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-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, 0.5) !important; } .text-white-50 { --bs-text-opacity: 1; color: rgba(255, 255, 255, 0.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: 0.25rem !important; } .rounded-0 { border-radius: 0 !important; } .rounded-1 { border-radius: 0.2rem !important; } .rounded-2 { border-radius: 0.25rem !important; } .rounded-3 { border-radius: 0.3rem !important; } .rounded-circle { border-radius: 50% !important; } .rounded-pill { border-radius: 50rem !important; } .rounded-top { border-top-right-radius: 0.25rem !important; border-top-left-radius: 0.25rem !important; } .rounded-end { border-top-left-radius: 0.25rem !important; border-bottom-left-radius: 0.25rem !important; } .rounded-bottom { border-bottom-left-radius: 0.25rem !important; border-bottom-right-radius: 0.25rem !important; } .rounded-start { border-bottom-right-radius: 0.25rem !important; border-top-right-radius: 0.25rem !important; } .visible { visibility: visible !important; } .invisible { visibility: hidden !important; } @media (min-width: 576px) { .float-sm-start { float: right !important; } .float-sm-end { float: left !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: 0.25rem !important; } .gap-sm-2 { gap: 0.5rem !important; } .gap-sm-3 { gap: 1rem !important; } .gap-sm-4 { gap: 1.5rem !important; } .gap-sm-5 { gap: 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: 0.25rem !important; } .m-sm-2 { margin: 0.5rem !important; } .m-sm-3 { margin: 1rem !important; } .m-sm-4 { margin: 1.5rem !important; } .m-sm-5 { margin: 3rem !important; } .m-sm-auto { margin: auto !important; } .mx-sm-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-sm-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-sm-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-sm-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-sm-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-sm-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-sm-auto { margin-left: auto !important; margin-right: auto !important; } .my-sm-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-sm-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-sm-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-sm-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-sm-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-sm-5 { margin-top: 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: 0.25rem !important; } .mt-sm-2 { margin-top: 0.5rem !important; } .mt-sm-3 { margin-top: 1rem !important; } .mt-sm-4 { margin-top: 1.5rem !important; } .mt-sm-5 { margin-top: 3rem !important; } .mt-sm-auto { margin-top: auto !important; } .me-sm-0 { margin-left: 0 !important; } .me-sm-1 { margin-left: 0.25rem !important; } .me-sm-2 { margin-left: 0.5rem !important; } .me-sm-3 { margin-left: 1rem !important; } .me-sm-4 { margin-left: 1.5rem !important; } .me-sm-5 { margin-left: 3rem !important; } .me-sm-auto { margin-left: auto !important; } .mb-sm-0 { margin-bottom: 0 !important; } .mb-sm-1 { margin-bottom: 0.25rem !important; } .mb-sm-2 { margin-bottom: 0.5rem !important; } .mb-sm-3 { margin-bottom: 1rem !important; } .mb-sm-4 { margin-bottom: 1.5rem !important; } .mb-sm-5 { margin-bottom: 3rem !important; } .mb-sm-auto { margin-bottom: auto !important; } .ms-sm-0 { margin-right: 0 !important; } .ms-sm-1 { margin-right: 0.25rem !important; } .ms-sm-2 { margin-right: 0.5rem !important; } .ms-sm-3 { margin-right: 1rem !important; } .ms-sm-4 { margin-right: 1.5rem !important; } .ms-sm-5 { margin-right: 3rem !important; } .ms-sm-auto { margin-right: auto !important; } .p-sm-0 { padding: 0 !important; } .p-sm-1 { padding: 0.25rem !important; } .p-sm-2 { padding: 0.5rem !important; } .p-sm-3 { padding: 1rem !important; } .p-sm-4 { padding: 1.5rem !important; } .p-sm-5 { padding: 3rem !important; } .px-sm-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-sm-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-sm-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-sm-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-sm-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-sm-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-sm-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-sm-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-sm-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-sm-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-sm-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-sm-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-sm-0 { padding-top: 0 !important; } .pt-sm-1 { padding-top: 0.25rem !important; } .pt-sm-2 { padding-top: 0.5rem !important; } .pt-sm-3 { padding-top: 1rem !important; } .pt-sm-4 { padding-top: 1.5rem !important; } .pt-sm-5 { padding-top: 3rem !important; } .pe-sm-0 { padding-left: 0 !important; } .pe-sm-1 { padding-left: 0.25rem !important; } .pe-sm-2 { padding-left: 0.5rem !important; } .pe-sm-3 { padding-left: 1rem !important; } .pe-sm-4 { padding-left: 1.5rem !important; } .pe-sm-5 { padding-left: 3rem !important; } .pb-sm-0 { padding-bottom: 0 !important; } .pb-sm-1 { padding-bottom: 0.25rem !important; } .pb-sm-2 { padding-bottom: 0.5rem !important; } .pb-sm-3 { padding-bottom: 1rem !important; } .pb-sm-4 { padding-bottom: 1.5rem !important; } .pb-sm-5 { padding-bottom: 3rem !important; } .ps-sm-0 { padding-right: 0 !important; } .ps-sm-1 { padding-right: 0.25rem !important; } .ps-sm-2 { padding-right: 0.5rem !important; } .ps-sm-3 { padding-right: 1rem !important; } .ps-sm-4 { padding-right: 1.5rem !important; } .ps-sm-5 { padding-right: 3rem !important; } .text-sm-start { text-align: right !important; } .text-sm-end { text-align: left !important; } .text-sm-center { text-align: center !important; } } @media (min-width: 768px) { .float-md-start { float: right !important; } .float-md-end { float: left !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: 0.25rem !important; } .gap-md-2 { gap: 0.5rem !important; } .gap-md-3 { gap: 1rem !important; } .gap-md-4 { gap: 1.5rem !important; } .gap-md-5 { gap: 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: 0.25rem !important; } .m-md-2 { margin: 0.5rem !important; } .m-md-3 { margin: 1rem !important; } .m-md-4 { margin: 1.5rem !important; } .m-md-5 { margin: 3rem !important; } .m-md-auto { margin: auto !important; } .mx-md-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-md-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-md-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-md-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-md-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-md-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-md-auto { margin-left: auto !important; margin-right: auto !important; } .my-md-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-md-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-md-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-md-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-md-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-md-5 { margin-top: 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: 0.25rem !important; } .mt-md-2 { margin-top: 0.5rem !important; } .mt-md-3 { margin-top: 1rem !important; } .mt-md-4 { margin-top: 1.5rem !important; } .mt-md-5 { margin-top: 3rem !important; } .mt-md-auto { margin-top: auto !important; } .me-md-0 { margin-left: 0 !important; } .me-md-1 { margin-left: 0.25rem !important; } .me-md-2 { margin-left: 0.5rem !important; } .me-md-3 { margin-left: 1rem !important; } .me-md-4 { margin-left: 1.5rem !important; } .me-md-5 { margin-left: 3rem !important; } .me-md-auto { margin-left: auto !important; } .mb-md-0 { margin-bottom: 0 !important; } .mb-md-1 { margin-bottom: 0.25rem !important; } .mb-md-2 { margin-bottom: 0.5rem !important; } .mb-md-3 { margin-bottom: 1rem !important; } .mb-md-4 { margin-bottom: 1.5rem !important; } .mb-md-5 { margin-bottom: 3rem !important; } .mb-md-auto { margin-bottom: auto !important; } .ms-md-0 { margin-right: 0 !important; } .ms-md-1 { margin-right: 0.25rem !important; } .ms-md-2 { margin-right: 0.5rem !important; } .ms-md-3 { margin-right: 1rem !important; } .ms-md-4 { margin-right: 1.5rem !important; } .ms-md-5 { margin-right: 3rem !important; } .ms-md-auto { margin-right: auto !important; } .p-md-0 { padding: 0 !important; } .p-md-1 { padding: 0.25rem !important; } .p-md-2 { padding: 0.5rem !important; } .p-md-3 { padding: 1rem !important; } .p-md-4 { padding: 1.5rem !important; } .p-md-5 { padding: 3rem !important; } .px-md-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-md-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-md-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-md-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-md-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-md-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-md-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-md-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-md-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-md-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-md-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-md-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-md-0 { padding-top: 0 !important; } .pt-md-1 { padding-top: 0.25rem !important; } .pt-md-2 { padding-top: 0.5rem !important; } .pt-md-3 { padding-top: 1rem !important; } .pt-md-4 { padding-top: 1.5rem !important; } .pt-md-5 { padding-top: 3rem !important; } .pe-md-0 { padding-left: 0 !important; } .pe-md-1 { padding-left: 0.25rem !important; } .pe-md-2 { padding-left: 0.5rem !important; } .pe-md-3 { padding-left: 1rem !important; } .pe-md-4 { padding-left: 1.5rem !important; } .pe-md-5 { padding-left: 3rem !important; } .pb-md-0 { padding-bottom: 0 !important; } .pb-md-1 { padding-bottom: 0.25rem !important; } .pb-md-2 { padding-bottom: 0.5rem !important; } .pb-md-3 { padding-bottom: 1rem !important; } .pb-md-4 { padding-bottom: 1.5rem !important; } .pb-md-5 { padding-bottom: 3rem !important; } .ps-md-0 { padding-right: 0 !important; } .ps-md-1 { padding-right: 0.25rem !important; } .ps-md-2 { padding-right: 0.5rem !important; } .ps-md-3 { padding-right: 1rem !important; } .ps-md-4 { padding-right: 1.5rem !important; } .ps-md-5 { padding-right: 3rem !important; } .text-md-start { text-align: right !important; } .text-md-end { text-align: left !important; } .text-md-center { text-align: center !important; } } @media (min-width: 992px) { .float-lg-start { float: right !important; } .float-lg-end { float: left !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: 0.25rem !important; } .gap-lg-2 { gap: 0.5rem !important; } .gap-lg-3 { gap: 1rem !important; } .gap-lg-4 { gap: 1.5rem !important; } .gap-lg-5 { gap: 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: 0.25rem !important; } .m-lg-2 { margin: 0.5rem !important; } .m-lg-3 { margin: 1rem !important; } .m-lg-4 { margin: 1.5rem !important; } .m-lg-5 { margin: 3rem !important; } .m-lg-auto { margin: auto !important; } .mx-lg-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-lg-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-lg-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-lg-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-lg-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-lg-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-lg-auto { margin-left: auto !important; margin-right: auto !important; } .my-lg-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-lg-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-lg-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-lg-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-lg-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-lg-5 { margin-top: 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: 0.25rem !important; } .mt-lg-2 { margin-top: 0.5rem !important; } .mt-lg-3 { margin-top: 1rem !important; } .mt-lg-4 { margin-top: 1.5rem !important; } .mt-lg-5 { margin-top: 3rem !important; } .mt-lg-auto { margin-top: auto !important; } .me-lg-0 { margin-left: 0 !important; } .me-lg-1 { margin-left: 0.25rem !important; } .me-lg-2 { margin-left: 0.5rem !important; } .me-lg-3 { margin-left: 1rem !important; } .me-lg-4 { margin-left: 1.5rem !important; } .me-lg-5 { margin-left: 3rem !important; } .me-lg-auto { margin-left: auto !important; } .mb-lg-0 { margin-bottom: 0 !important; } .mb-lg-1 { margin-bottom: 0.25rem !important; } .mb-lg-2 { margin-bottom: 0.5rem !important; } .mb-lg-3 { margin-bottom: 1rem !important; } .mb-lg-4 { margin-bottom: 1.5rem !important; } .mb-lg-5 { margin-bottom: 3rem !important; } .mb-lg-auto { margin-bottom: auto !important; } .ms-lg-0 { margin-right: 0 !important; } .ms-lg-1 { margin-right: 0.25rem !important; } .ms-lg-2 { margin-right: 0.5rem !important; } .ms-lg-3 { margin-right: 1rem !important; } .ms-lg-4 { margin-right: 1.5rem !important; } .ms-lg-5 { margin-right: 3rem !important; } .ms-lg-auto { margin-right: auto !important; } .p-lg-0 { padding: 0 !important; } .p-lg-1 { padding: 0.25rem !important; } .p-lg-2 { padding: 0.5rem !important; } .p-lg-3 { padding: 1rem !important; } .p-lg-4 { padding: 1.5rem !important; } .p-lg-5 { padding: 3rem !important; } .px-lg-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-lg-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-lg-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-lg-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-lg-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-lg-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-lg-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-lg-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-lg-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-lg-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-lg-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-lg-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-lg-0 { padding-top: 0 !important; } .pt-lg-1 { padding-top: 0.25rem !important; } .pt-lg-2 { padding-top: 0.5rem !important; } .pt-lg-3 { padding-top: 1rem !important; } .pt-lg-4 { padding-top: 1.5rem !important; } .pt-lg-5 { padding-top: 3rem !important; } .pe-lg-0 { padding-left: 0 !important; } .pe-lg-1 { padding-left: 0.25rem !important; } .pe-lg-2 { padding-left: 0.5rem !important; } .pe-lg-3 { padding-left: 1rem !important; } .pe-lg-4 { padding-left: 1.5rem !important; } .pe-lg-5 { padding-left: 3rem !important; } .pb-lg-0 { padding-bottom: 0 !important; } .pb-lg-1 { padding-bottom: 0.25rem !important; } .pb-lg-2 { padding-bottom: 0.5rem !important; } .pb-lg-3 { padding-bottom: 1rem !important; } .pb-lg-4 { padding-bottom: 1.5rem !important; } .pb-lg-5 { padding-bottom: 3rem !important; } .ps-lg-0 { padding-right: 0 !important; } .ps-lg-1 { padding-right: 0.25rem !important; } .ps-lg-2 { padding-right: 0.5rem !important; } .ps-lg-3 { padding-right: 1rem !important; } .ps-lg-4 { padding-right: 1.5rem !important; } .ps-lg-5 { padding-right: 3rem !important; } .text-lg-start { text-align: right !important; } .text-lg-end { text-align: left !important; } .text-lg-center { text-align: center !important; } } @media (min-width: 1200px) { .float-xl-start { float: right !important; } .float-xl-end { float: left !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: 0.25rem !important; } .gap-xl-2 { gap: 0.5rem !important; } .gap-xl-3 { gap: 1rem !important; } .gap-xl-4 { gap: 1.5rem !important; } .gap-xl-5 { gap: 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: 0.25rem !important; } .m-xl-2 { margin: 0.5rem !important; } .m-xl-3 { margin: 1rem !important; } .m-xl-4 { margin: 1.5rem !important; } .m-xl-5 { margin: 3rem !important; } .m-xl-auto { margin: auto !important; } .mx-xl-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-xl-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-xl-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-xl-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-xl-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-xl-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-xl-auto { margin-left: auto !important; margin-right: auto !important; } .my-xl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-xl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xl-5 { margin-top: 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: 0.25rem !important; } .mt-xl-2 { margin-top: 0.5rem !important; } .mt-xl-3 { margin-top: 1rem !important; } .mt-xl-4 { margin-top: 1.5rem !important; } .mt-xl-5 { margin-top: 3rem !important; } .mt-xl-auto { margin-top: auto !important; } .me-xl-0 { margin-left: 0 !important; } .me-xl-1 { margin-left: 0.25rem !important; } .me-xl-2 { margin-left: 0.5rem !important; } .me-xl-3 { margin-left: 1rem !important; } .me-xl-4 { margin-left: 1.5rem !important; } .me-xl-5 { margin-left: 3rem !important; } .me-xl-auto { margin-left: auto !important; } .mb-xl-0 { margin-bottom: 0 !important; } .mb-xl-1 { margin-bottom: 0.25rem !important; } .mb-xl-2 { margin-bottom: 0.5rem !important; } .mb-xl-3 { margin-bottom: 1rem !important; } .mb-xl-4 { margin-bottom: 1.5rem !important; } .mb-xl-5 { margin-bottom: 3rem !important; } .mb-xl-auto { margin-bottom: auto !important; } .ms-xl-0 { margin-right: 0 !important; } .ms-xl-1 { margin-right: 0.25rem !important; } .ms-xl-2 { margin-right: 0.5rem !important; } .ms-xl-3 { margin-right: 1rem !important; } .ms-xl-4 { margin-right: 1.5rem !important; } .ms-xl-5 { margin-right: 3rem !important; } .ms-xl-auto { margin-right: auto !important; } .p-xl-0 { padding: 0 !important; } .p-xl-1 { padding: 0.25rem !important; } .p-xl-2 { padding: 0.5rem !important; } .p-xl-3 { padding: 1rem !important; } .p-xl-4 { padding: 1.5rem !important; } .p-xl-5 { padding: 3rem !important; } .px-xl-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-xl-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-xl-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-xl-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-xl-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-xl-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-xl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xl-0 { padding-top: 0 !important; } .pt-xl-1 { padding-top: 0.25rem !important; } .pt-xl-2 { padding-top: 0.5rem !important; } .pt-xl-3 { padding-top: 1rem !important; } .pt-xl-4 { padding-top: 1.5rem !important; } .pt-xl-5 { padding-top: 3rem !important; } .pe-xl-0 { padding-left: 0 !important; } .pe-xl-1 { padding-left: 0.25rem !important; } .pe-xl-2 { padding-left: 0.5rem !important; } .pe-xl-3 { padding-left: 1rem !important; } .pe-xl-4 { padding-left: 1.5rem !important; } .pe-xl-5 { padding-left: 3rem !important; } .pb-xl-0 { padding-bottom: 0 !important; } .pb-xl-1 { padding-bottom: 0.25rem !important; } .pb-xl-2 { padding-bottom: 0.5rem !important; } .pb-xl-3 { padding-bottom: 1rem !important; } .pb-xl-4 { padding-bottom: 1.5rem !important; } .pb-xl-5 { padding-bottom: 3rem !important; } .ps-xl-0 { padding-right: 0 !important; } .ps-xl-1 { padding-right: 0.25rem !important; } .ps-xl-2 { padding-right: 0.5rem !important; } .ps-xl-3 { padding-right: 1rem !important; } .ps-xl-4 { padding-right: 1.5rem !important; } .ps-xl-5 { padding-right: 3rem !important; } .text-xl-start { text-align: right !important; } .text-xl-end { text-align: left !important; } .text-xl-center { text-align: center !important; } } @media (min-width: 1400px) { .float-xxl-start { float: right !important; } .float-xxl-end { float: left !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: 0.25rem !important; } .gap-xxl-2 { gap: 0.5rem !important; } .gap-xxl-3 { gap: 1rem !important; } .gap-xxl-4 { gap: 1.5rem !important; } .gap-xxl-5 { gap: 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: 0.25rem !important; } .m-xxl-2 { margin: 0.5rem !important; } .m-xxl-3 { margin: 1rem !important; } .m-xxl-4 { margin: 1.5rem !important; } .m-xxl-5 { margin: 3rem !important; } .m-xxl-auto { margin: auto !important; } .mx-xxl-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-xxl-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-xxl-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-xxl-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-xxl-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-xxl-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-xxl-auto { margin-left: auto !important; margin-right: auto !important; } .my-xxl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-xxl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xxl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xxl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xxl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xxl-5 { margin-top: 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: 0.25rem !important; } .mt-xxl-2 { margin-top: 0.5rem !important; } .mt-xxl-3 { margin-top: 1rem !important; } .mt-xxl-4 { margin-top: 1.5rem !important; } .mt-xxl-5 { margin-top: 3rem !important; } .mt-xxl-auto { margin-top: auto !important; } .me-xxl-0 { margin-left: 0 !important; } .me-xxl-1 { margin-left: 0.25rem !important; } .me-xxl-2 { margin-left: 0.5rem !important; } .me-xxl-3 { margin-left: 1rem !important; } .me-xxl-4 { margin-left: 1.5rem !important; } .me-xxl-5 { margin-left: 3rem !important; } .me-xxl-auto { margin-left: auto !important; } .mb-xxl-0 { margin-bottom: 0 !important; } .mb-xxl-1 { margin-bottom: 0.25rem !important; } .mb-xxl-2 { margin-bottom: 0.5rem !important; } .mb-xxl-3 { margin-bottom: 1rem !important; } .mb-xxl-4 { margin-bottom: 1.5rem !important; } .mb-xxl-5 { margin-bottom: 3rem !important; } .mb-xxl-auto { margin-bottom: auto !important; } .ms-xxl-0 { margin-right: 0 !important; } .ms-xxl-1 { margin-right: 0.25rem !important; } .ms-xxl-2 { margin-right: 0.5rem !important; } .ms-xxl-3 { margin-right: 1rem !important; } .ms-xxl-4 { margin-right: 1.5rem !important; } .ms-xxl-5 { margin-right: 3rem !important; } .ms-xxl-auto { margin-right: auto !important; } .p-xxl-0 { padding: 0 !important; } .p-xxl-1 { padding: 0.25rem !important; } .p-xxl-2 { padding: 0.5rem !important; } .p-xxl-3 { padding: 1rem !important; } .p-xxl-4 { padding: 1.5rem !important; } .p-xxl-5 { padding: 3rem !important; } .px-xxl-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-xxl-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-xxl-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-xxl-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-xxl-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-xxl-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-xxl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xxl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xxl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xxl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xxl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xxl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xxl-0 { padding-top: 0 !important; } .pt-xxl-1 { padding-top: 0.25rem !important; } .pt-xxl-2 { padding-top: 0.5rem !important; } .pt-xxl-3 { padding-top: 1rem !important; } .pt-xxl-4 { padding-top: 1.5rem !important; } .pt-xxl-5 { padding-top: 3rem !important; } .pe-xxl-0 { padding-left: 0 !important; } .pe-xxl-1 { padding-left: 0.25rem !important; } .pe-xxl-2 { padding-left: 0.5rem !important; } .pe-xxl-3 { padding-left: 1rem !important; } .pe-xxl-4 { padding-left: 1.5rem !important; } .pe-xxl-5 { padding-left: 3rem !important; } .pb-xxl-0 { padding-bottom: 0 !important; } .pb-xxl-1 { padding-bottom: 0.25rem !important; } .pb-xxl-2 { padding-bottom: 0.5rem !important; } .pb-xxl-3 { padding-bottom: 1rem !important; } .pb-xxl-4 { padding-bottom: 1.5rem !important; } .pb-xxl-5 { padding-bottom: 3rem !important; } .ps-xxl-0 { padding-right: 0 !important; } .ps-xxl-1 { padding-right: 0.25rem !important; } .ps-xxl-2 { padding-right: 0.5rem !important; } .ps-xxl-3 { padding-right: 1rem !important; } .ps-xxl-4 { padding-right: 1.5rem !important; } .ps-xxl-5 { padding-right: 3rem !important; } .text-xxl-start { text-align: right !important; } .text-xxl-end { text-align: left !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-utilities.rtl.css.map */ ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/css/bootstrap.css ================================================ @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; } *, *::before, *::after { box-sizing: border-box; } @media (prefers-reduced-motion: no-preference) { :root { scroll-behavior: smooth; } } body { margin: 0; font-family: var(--bs-body-font-family); font-size: var(--bs-body-font-size); font-weight: var(--bs-body-font-weight); line-height: var(--bs-body-line-height); color: var(--bs-body-color); text-align: var(--bs-body-text-align); background-color: var(--bs-body-bg); -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } hr { margin: 1rem 0; color: inherit; background-color: currentColor; border: 0; opacity: 0.25; } hr:not([size]) { height: 1px; } h6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 { margin-top: 0; margin-bottom: 0.5rem; font-weight: 500; line-height: 1.2; } 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 + 0.9vw); } @media (min-width: 1200px) { h2, .h2 { font-size: 2rem; } } h3, .h3 { font-size: calc(1.3rem + 0.6vw); } @media (min-width: 1200px) { h3, .h3 { font-size: 1.75rem; } } h4, .h4 { font-size: calc(1.275rem + 0.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[title], abbr[data-bs-original-title] { -webkit-text-decoration: underline dotted; text-decoration: underline dotted; cursor: help; -webkit-text-decoration-skip-ink: none; text-decoration-skip-ink: none; } address { margin-bottom: 1rem; font-style: normal; line-height: inherit; } ol, ul { padding-left: 2rem; } ol, ul, dl { margin-top: 0; margin-bottom: 1rem; } ol ol, ul ul, ol ul, ul ol { margin-bottom: 0; } dt { font-weight: 700; } dd { margin-bottom: 0.5rem; margin-left: 0; } blockquote { margin: 0 0 1rem; } b, strong { font-weight: bolder; } small, .small { font-size: 0.875em; } mark, .mark { padding: 0.2em; background-color: #fcf8e3; } sub, sup { position: relative; font-size: 0.75em; line-height: 0; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.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; } pre, code, kbd, samp { font-family: var(--bs-font-monospace); font-size: 1em; direction: ltr /* rtl:ignore */; unicode-bidi: bidi-override; } pre { display: block; margin-top: 0; margin-bottom: 1rem; overflow: auto; font-size: 0.875em; } pre code { font-size: inherit; color: inherit; word-break: normal; } code { font-size: 0.875em; color: #d63384; word-wrap: break-word; } a > code { color: inherit; } kbd { padding: 0.2rem 0.4rem; font-size: 0.875em; color: #fff; background-color: #212529; border-radius: 0.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: 0.5rem; padding-bottom: 0.5rem; color: #6c757d; text-align: left; } th { text-align: inherit; text-align: -webkit-match-parent; } thead, tbody, tfoot, tr, td, th { border-color: inherit; border-style: solid; border-width: 0; } label { display: inline-block; } button { border-radius: 0; } button:focus:not(:focus-visible) { outline: 0; } input, button, select, optgroup, textarea { margin: 0; font-family: inherit; font-size: inherit; line-height: inherit; } button, select { text-transform: none; } [role=button] { cursor: pointer; } select { word-wrap: normal; } select:disabled { opacity: 1; } [list]::-webkit-calendar-picker-indicator { display: none; } button, [type=button], [type=reset], [type=submit] { -webkit-appearance: button; } button:not(:disabled), [type=button]:not(:disabled), [type=reset]:not(:disabled), [type=submit]:not(:disabled) { cursor: pointer; } ::-moz-focus-inner { padding: 0; border-style: none; } textarea { resize: vertical; } fieldset { min-width: 0; padding: 0; margin: 0; border: 0; } legend { float: left; width: 100%; padding: 0; margin-bottom: 0.5rem; font-size: calc(1.275rem + 0.3vw); line-height: inherit; } @media (min-width: 1200px) { legend { font-size: 1.5rem; } } legend + * { clear: left; } ::-webkit-datetime-edit-fields-wrapper, ::-webkit-datetime-edit-text, ::-webkit-datetime-edit-minute, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-year-field { padding: 0; } ::-webkit-inner-spin-button { height: auto; } [type=search] { outline-offset: -2px; -webkit-appearance: textfield; } /* rtl:raw: [type="tel"], [type="url"], [type="email"], [type="number"] { direction: ltr; } */ ::-webkit-search-decoration { -webkit-appearance: none; } ::-webkit-color-swatch-wrapper { padding: 0; } ::file-selector-button { font: inherit; } ::-webkit-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: 0.5rem; } .initialism { font-size: 0.875em; text-transform: uppercase; } .blockquote { margin-bottom: 1rem; font-size: 1.25rem; } .blockquote > :last-child { margin-bottom: 0; } .blockquote-footer { margin-top: -1rem; margin-bottom: 1rem; font-size: 0.875em; color: #6c757d; } .blockquote-footer::before { content: "— "; } .img-fluid { max-width: 100%; height: auto; } .img-thumbnail { padding: 0.25rem; background-color: #fff; border: 1px solid #dee2e6; border-radius: 0.25rem; max-width: 100%; height: auto; } .figure { display: inline-block; } .figure-img { margin-bottom: 0.5rem; line-height: 1; } .figure-caption { font-size: 0.875em; color: #6c757d; } .container, .container-fluid, .container-xxl, .container-xl, .container-lg, .container-md, .container-sm { width: 100%; padding-right: var(--bs-gutter-x, 0.75rem); padding-left: var(--bs-gutter-x, 0.75rem); margin-right: auto; margin-left: auto; } @media (min-width: 576px) { .container-sm, .container { max-width: 540px; } } @media (min-width: 768px) { .container-md, .container-sm, .container { max-width: 720px; } } @media (min-width: 992px) { .container-lg, .container-md, .container-sm, .container { max-width: 960px; } } @media (min-width: 1200px) { .container-xl, .container-lg, .container-md, .container-sm, .container { max-width: 1140px; } } @media (min-width: 1400px) { .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container { 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: 0.5rem 0.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: 0.25rem 0.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: 0.5rem; } .col-form-label { padding-top: calc(0.375rem + 1px); padding-bottom: calc(0.375rem + 1px); margin-bottom: 0; font-size: inherit; line-height: 1.5; } .col-form-label-lg { padding-top: calc(0.5rem + 1px); padding-bottom: calc(0.5rem + 1px); font-size: 1.25rem; } .col-form-label-sm { padding-top: calc(0.25rem + 1px); padding-bottom: calc(0.25rem + 1px); font-size: 0.875rem; } .form-text { margin-top: 0.25rem; font-size: 0.875em; color: #6c757d; } .form-control { display: block; width: 100%; padding: 0.375rem 0.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: 0.25rem; transition: border-color 0.15s ease-in-out, box-shadow 0.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 0.25rem rgba(13, 110, 253, 0.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: 0.375rem 0.75rem; margin: -0.375rem -0.75rem; -webkit-margin-end: 0.75rem; margin-inline-end: 0.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 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .form-control::file-selector-button { transition: none; } } .form-control:hover:not(:disabled):not([readonly])::file-selector-button { background-color: #dde0e3; } .form-control::-webkit-file-upload-button { padding: 0.375rem 0.75rem; margin: -0.375rem -0.75rem; -webkit-margin-end: 0.75rem; margin-inline-end: 0.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 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .form-control::-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: 0.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-sm, .form-control-plaintext.form-control-lg { padding-right: 0; padding-left: 0; } .form-control-sm { min-height: calc(1.5em + 0.5rem + 2px); padding: 0.25rem 0.5rem; font-size: 0.875rem; border-radius: 0.2rem; } .form-control-sm::file-selector-button { padding: 0.25rem 0.5rem; margin: -0.25rem -0.5rem; -webkit-margin-end: 0.5rem; margin-inline-end: 0.5rem; } .form-control-sm::-webkit-file-upload-button { padding: 0.25rem 0.5rem; margin: -0.25rem -0.5rem; -webkit-margin-end: 0.5rem; margin-inline-end: 0.5rem; } .form-control-lg { min-height: calc(1.5em + 1rem + 2px); padding: 0.5rem 1rem; font-size: 1.25rem; border-radius: 0.3rem; } .form-control-lg::file-selector-button { padding: 0.5rem 1rem; margin: -0.5rem -1rem; -webkit-margin-end: 1rem; margin-inline-end: 1rem; } .form-control-lg::-webkit-file-upload-button { padding: 0.5rem 1rem; margin: -0.5rem -1rem; -webkit-margin-end: 1rem; margin-inline-end: 1rem; } textarea.form-control { min-height: calc(1.5em + 0.75rem + 2px); } textarea.form-control-sm { min-height: calc(1.5em + 0.5rem + 2px); } textarea.form-control-lg { min-height: calc(1.5em + 1rem + 2px); } .form-control-color { width: 3rem; height: auto; padding: 0.375rem; } .form-control-color:not(:disabled):not([readonly]) { cursor: pointer; } .form-control-color::-moz-color-swatch { height: 1.5em; border-radius: 0.25rem; } .form-control-color::-webkit-color-swatch { height: 1.5em; border-radius: 0.25rem; } .form-select { display: block; width: 100%; padding: 0.375rem 2.25rem 0.375rem 0.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 0.75rem center; background-size: 16px 12px; border: 1px solid #ced4da; border-radius: 0.25rem; transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; -webkit-appearance: none; -moz-appearance: none; appearance: none; } @media (prefers-reduced-motion: reduce) { .form-select { transition: none; } } .form-select:focus { border-color: #86b7fe; outline: 0; box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); } .form-select[multiple], .form-select[size]:not([size="1"]) { padding-right: 0.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: 0.25rem; padding-bottom: 0.25rem; padding-left: 0.5rem; font-size: 0.875rem; } .form-select-lg { padding-top: 0.5rem; padding-bottom: 0.5rem; padding-left: 1rem; font-size: 1.25rem; } .form-check { display: block; min-height: 1.5rem; padding-left: 1.5em; margin-bottom: 0.125rem; } .form-check .form-check-input { float: left; margin-left: -1.5em; } .form-check-input { width: 1em; height: 1em; margin-top: 0.25em; vertical-align: top; background-color: #fff; background-repeat: no-repeat; background-position: center; background-size: contain; border: 1px solid rgba(0, 0, 0, 0.25); -webkit-appearance: none; -moz-appearance: none; appearance: none; -webkit-print-color-adjust: exact; color-adjust: exact; } .form-check-input[type=checkbox] { border-radius: 0.25em; } .form-check-input[type=radio] { border-radius: 50%; } .form-check-input:active { filter: brightness(90%); } .form-check-input:focus { border-color: #86b7fe; outline: 0; box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.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: 0.5; } .form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label { opacity: 0.5; } .form-switch { padding-left: 2.5em; } .form-switch .form-check-input { width: 2em; margin-left: -2.5em; background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e"); background-position: left center; border-radius: 2em; transition: background-position 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .form-switch .form-check-input { transition: none; } } .form-switch .form-check-input:focus { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%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: 0.65; } .form-range { width: 100%; height: 1.5rem; padding: 0; background-color: transparent; -webkit-appearance: none; -moz-appearance: none; appearance: none; } .form-range:focus { outline: 0; } .form-range:focus::-webkit-slider-thumb { box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25); } .form-range:focus::-moz-range-thumb { box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25); } .form-range::-moz-focus-outer { border: 0; } .form-range::-webkit-slider-thumb { width: 1rem; height: 1rem; margin-top: -0.25rem; background-color: #0d6efd; border: 0; border-radius: 1rem; -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; -webkit-appearance: none; appearance: none; } @media (prefers-reduced-motion: reduce) { .form-range::-webkit-slider-thumb { -webkit-transition: none; transition: none; } } .form-range::-webkit-slider-thumb:active { background-color: #b6d4fe; } .form-range::-webkit-slider-runnable-track { width: 100%; height: 0.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 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; -moz-appearance: none; appearance: none; } @media (prefers-reduced-motion: reduce) { .form-range::-moz-range-thumb { -moz-transition: none; transition: none; } } .form-range::-moz-range-thumb:active { background-color: #b6d4fe; } .form-range::-moz-range-track { width: 100%; height: 0.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 0.75rem; pointer-events: none; border: 1px solid transparent; transform-origin: 0 0; transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out; } @media (prefers-reduced-motion: reduce) { .form-floating > label { transition: none; } } .form-floating > .form-control { padding: 1rem 0.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: 0.625rem; } .form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown) { padding-top: 1.625rem; padding-bottom: 0.625rem; } .form-floating > .form-control:-webkit-autofill { padding-top: 1.625rem; padding-bottom: 0.625rem; } .form-floating > .form-select { padding-top: 1.625rem; padding-bottom: 0.625rem; } .form-floating > .form-control:not(:-moz-placeholder-shown) ~ label { opacity: 0.65; transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); } .form-floating > .form-control:focus ~ label, .form-floating > .form-control:not(:placeholder-shown) ~ label, .form-floating > .form-select ~ label { opacity: 0.65; transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); } .form-floating > .form-control:-webkit-autofill ~ label { opacity: 0.65; transform: scale(0.85) translateY(-0.5rem) translateX(0.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: 0.375rem 0.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: 0.25rem; } .input-group-lg > .form-control, .input-group-lg > .form-select, .input-group-lg > .input-group-text, .input-group-lg > .btn { padding: 0.5rem 1rem; font-size: 1.25rem; border-radius: 0.3rem; } .input-group-sm > .form-control, .input-group-sm > .form-select, .input-group-sm > .input-group-text, .input-group-sm > .btn { padding: 0.25rem 0.5rem; font-size: 0.875rem; border-radius: 0.2rem; } .input-group-lg > .form-select, .input-group-sm > .form-select { padding-right: 3rem; } .input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu), .input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3) { border-top-right-radius: 0; border-bottom-right-radius: 0; } .input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu), .input-group.has-validation > .dropdown-toggle:nth-last-child(n+4) { 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: 0.25rem; font-size: 0.875em; color: #198754; } .valid-tooltip { position: absolute; top: 100%; z-index: 5; display: none; max-width: 100%; padding: 0.25rem 0.5rem; margin-top: 0.1rem; font-size: 0.875rem; color: #fff; background-color: rgba(25, 135, 84, 0.9); border-radius: 0.25rem; } .was-validated :valid ~ .valid-feedback, .was-validated :valid ~ .valid-tooltip, .is-valid ~ .valid-feedback, .is-valid ~ .valid-tooltip { display: block; } .was-validated .form-control:valid, .form-control.is-valid { border-color: #198754; padding-right: calc(1.5em + 0.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(0.375em + 0.1875rem) center; background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } .was-validated .form-control:valid:focus, .form-control.is-valid:focus { border-color: #198754; box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25); } .was-validated textarea.form-control:valid, textarea.form-control.is-valid { padding-right: calc(1.5em + 0.75rem); background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); } .was-validated .form-select:valid, .form-select.is-valid { border-color: #198754; } .was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size="1"], .form-select.is-valid:not([multiple]):not([size]), .form-select.is-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 0.75rem center, center right 2.25rem; background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } .was-validated .form-select:valid:focus, .form-select.is-valid:focus { border-color: #198754; box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25); } .was-validated .form-check-input:valid, .form-check-input.is-valid { border-color: #198754; } .was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked { background-color: #198754; } .was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus { box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25); } .was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { color: #198754; } .form-check-inline .form-check-input ~ .valid-feedback { margin-left: 0.5em; } .was-validated .input-group .form-control:valid, .input-group .form-control.is-valid, .was-validated .input-group .form-select:valid, .input-group .form-select.is-valid { z-index: 1; } .was-validated .input-group .form-control:valid:focus, .input-group .form-control.is-valid:focus, .was-validated .input-group .form-select:valid:focus, .input-group .form-select.is-valid:focus { z-index: 3; } .invalid-feedback { display: none; width: 100%; margin-top: 0.25rem; font-size: 0.875em; color: #dc3545; } .invalid-tooltip { position: absolute; top: 100%; z-index: 5; display: none; max-width: 100%; padding: 0.25rem 0.5rem; margin-top: 0.1rem; font-size: 0.875rem; color: #fff; background-color: rgba(220, 53, 69, 0.9); border-radius: 0.25rem; } .was-validated :invalid ~ .invalid-feedback, .was-validated :invalid ~ .invalid-tooltip, .is-invalid ~ .invalid-feedback, .is-invalid ~ .invalid-tooltip { display: block; } .was-validated .form-control:invalid, .form-control.is-invalid { border-color: #dc3545; padding-right: calc(1.5em + 0.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(0.375em + 0.1875rem) center; background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } .was-validated .form-control:invalid:focus, .form-control.is-invalid:focus { border-color: #dc3545; box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); } .was-validated textarea.form-control:invalid, textarea.form-control.is-invalid { padding-right: calc(1.5em + 0.75rem); background-position: top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem); } .was-validated .form-select:invalid, .form-select.is-invalid { border-color: #dc3545; } .was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size="1"], .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-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 0.75rem center, center right 2.25rem; background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } .was-validated .form-select:invalid:focus, .form-select.is-invalid:focus { border-color: #dc3545; box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); } .was-validated .form-check-input:invalid, .form-check-input.is-invalid { border-color: #dc3545; } .was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked { background-color: #dc3545; } .was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus { box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); } .was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { color: #dc3545; } .form-check-inline .form-check-input ~ .invalid-feedback { margin-left: 0.5em; } .was-validated .input-group .form-control:invalid, .input-group .form-control.is-invalid, .was-validated .input-group .form-select:invalid, .input-group .form-select.is-invalid { z-index: 2; } .was-validated .input-group .form-control:invalid:focus, .input-group .form-control.is-invalid:focus, .was-validated .input-group .form-select:invalid:focus, .input-group .form-select.is-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: 0.375rem 0.75rem; font-size: 1rem; border-radius: 0.25rem; transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .btn { transition: none; } } .btn:hover { color: #212529; } .btn-check:focus + .btn, .btn:focus { outline: 0; box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); } .btn:disabled, .btn.disabled, fieldset:disabled .btn { pointer-events: none; opacity: 0.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 0.25rem rgba(49, 132, 253, 0.5); } .btn-check:checked + .btn-primary, .btn-check:active + .btn-primary, .btn-primary:active, .btn-primary.active, .show > .btn-primary.dropdown-toggle { color: #fff; background-color: #0a58ca; border-color: #0a53be; } .btn-check:checked + .btn-primary:focus, .btn-check:active + .btn-primary:focus, .btn-primary:active:focus, .btn-primary.active:focus, .show > .btn-primary.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(49, 132, 253, 0.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 0.25rem rgba(130, 138, 145, 0.5); } .btn-check:checked + .btn-secondary, .btn-check:active + .btn-secondary, .btn-secondary:active, .btn-secondary.active, .show > .btn-secondary.dropdown-toggle { color: #fff; background-color: #565e64; border-color: #51585e; } .btn-check:checked + .btn-secondary:focus, .btn-check:active + .btn-secondary:focus, .btn-secondary:active:focus, .btn-secondary.active:focus, .show > .btn-secondary.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(130, 138, 145, 0.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 0.25rem rgba(60, 153, 110, 0.5); } .btn-check:checked + .btn-success, .btn-check:active + .btn-success, .btn-success:active, .btn-success.active, .show > .btn-success.dropdown-toggle { color: #fff; background-color: #146c43; border-color: #13653f; } .btn-check:checked + .btn-success:focus, .btn-check:active + .btn-success:focus, .btn-success:active:focus, .btn-success.active:focus, .show > .btn-success.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(60, 153, 110, 0.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 0.25rem rgba(11, 172, 204, 0.5); } .btn-check:checked + .btn-info, .btn-check:active + .btn-info, .btn-info:active, .btn-info.active, .show > .btn-info.dropdown-toggle { color: #000; background-color: #3dd5f3; border-color: #25cff2; } .btn-check:checked + .btn-info:focus, .btn-check:active + .btn-info:focus, .btn-info:active:focus, .btn-info.active:focus, .show > .btn-info.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(11, 172, 204, 0.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 0.25rem rgba(217, 164, 6, 0.5); } .btn-check:checked + .btn-warning, .btn-check:active + .btn-warning, .btn-warning:active, .btn-warning.active, .show > .btn-warning.dropdown-toggle { color: #000; background-color: #ffcd39; border-color: #ffc720; } .btn-check:checked + .btn-warning:focus, .btn-check:active + .btn-warning:focus, .btn-warning:active:focus, .btn-warning.active:focus, .show > .btn-warning.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(217, 164, 6, 0.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 0.25rem rgba(225, 83, 97, 0.5); } .btn-check:checked + .btn-danger, .btn-check:active + .btn-danger, .btn-danger:active, .btn-danger.active, .show > .btn-danger.dropdown-toggle { color: #fff; background-color: #b02a37; border-color: #a52834; } .btn-check:checked + .btn-danger:focus, .btn-check:active + .btn-danger:focus, .btn-danger:active:focus, .btn-danger.active:focus, .show > .btn-danger.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(225, 83, 97, 0.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 0.25rem rgba(211, 212, 213, 0.5); } .btn-check:checked + .btn-light, .btn-check:active + .btn-light, .btn-light:active, .btn-light.active, .show > .btn-light.dropdown-toggle { color: #000; background-color: #f9fafb; border-color: #f9fafb; } .btn-check:checked + .btn-light:focus, .btn-check:active + .btn-light:focus, .btn-light:active:focus, .btn-light.active:focus, .show > .btn-light.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(211, 212, 213, 0.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 0.25rem rgba(66, 70, 73, 0.5); } .btn-check:checked + .btn-dark, .btn-check:active + .btn-dark, .btn-dark:active, .btn-dark.active, .show > .btn-dark.dropdown-toggle { color: #fff; background-color: #1a1e21; border-color: #191c1f; } .btn-check:checked + .btn-dark:focus, .btn-check:active + .btn-dark:focus, .btn-dark:active:focus, .btn-dark.active:focus, .show > .btn-dark.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(66, 70, 73, 0.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 0.25rem rgba(13, 110, 253, 0.5); } .btn-check:checked + .btn-outline-primary, .btn-check:active + .btn-outline-primary, .btn-outline-primary:active, .btn-outline-primary.active, .btn-outline-primary.dropdown-toggle.show { color: #fff; background-color: #0d6efd; border-color: #0d6efd; } .btn-check:checked + .btn-outline-primary:focus, .btn-check:active + .btn-outline-primary:focus, .btn-outline-primary:active:focus, .btn-outline-primary.active:focus, .btn-outline-primary.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.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 0.25rem rgba(108, 117, 125, 0.5); } .btn-check:checked + .btn-outline-secondary, .btn-check:active + .btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show { color: #fff; background-color: #6c757d; border-color: #6c757d; } .btn-check:checked + .btn-outline-secondary:focus, .btn-check:active + .btn-outline-secondary:focus, .btn-outline-secondary:active:focus, .btn-outline-secondary.active:focus, .btn-outline-secondary.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(108, 117, 125, 0.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 0.25rem rgba(25, 135, 84, 0.5); } .btn-check:checked + .btn-outline-success, .btn-check:active + .btn-outline-success, .btn-outline-success:active, .btn-outline-success.active, .btn-outline-success.dropdown-toggle.show { color: #fff; background-color: #198754; border-color: #198754; } .btn-check:checked + .btn-outline-success:focus, .btn-check:active + .btn-outline-success:focus, .btn-outline-success:active:focus, .btn-outline-success.active:focus, .btn-outline-success.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.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 0.25rem rgba(13, 202, 240, 0.5); } .btn-check:checked + .btn-outline-info, .btn-check:active + .btn-outline-info, .btn-outline-info:active, .btn-outline-info.active, .btn-outline-info.dropdown-toggle.show { color: #000; background-color: #0dcaf0; border-color: #0dcaf0; } .btn-check:checked + .btn-outline-info:focus, .btn-check:active + .btn-outline-info:focus, .btn-outline-info:active:focus, .btn-outline-info.active:focus, .btn-outline-info.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(13, 202, 240, 0.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 0.25rem rgba(255, 193, 7, 0.5); } .btn-check:checked + .btn-outline-warning, .btn-check:active + .btn-outline-warning, .btn-outline-warning:active, .btn-outline-warning.active, .btn-outline-warning.dropdown-toggle.show { color: #000; background-color: #ffc107; border-color: #ffc107; } .btn-check:checked + .btn-outline-warning:focus, .btn-check:active + .btn-outline-warning:focus, .btn-outline-warning:active:focus, .btn-outline-warning.active:focus, .btn-outline-warning.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(255, 193, 7, 0.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 0.25rem rgba(220, 53, 69, 0.5); } .btn-check:checked + .btn-outline-danger, .btn-check:active + .btn-outline-danger, .btn-outline-danger:active, .btn-outline-danger.active, .btn-outline-danger.dropdown-toggle.show { color: #fff; background-color: #dc3545; border-color: #dc3545; } .btn-check:checked + .btn-outline-danger:focus, .btn-check:active + .btn-outline-danger:focus, .btn-outline-danger:active:focus, .btn-outline-danger.active:focus, .btn-outline-danger.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.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 0.25rem rgba(248, 249, 250, 0.5); } .btn-check:checked + .btn-outline-light, .btn-check:active + .btn-outline-light, .btn-outline-light:active, .btn-outline-light.active, .btn-outline-light.dropdown-toggle.show { color: #000; background-color: #f8f9fa; border-color: #f8f9fa; } .btn-check:checked + .btn-outline-light:focus, .btn-check:active + .btn-outline-light:focus, .btn-outline-light:active:focus, .btn-outline-light.active:focus, .btn-outline-light.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(248, 249, 250, 0.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 0.25rem rgba(33, 37, 41, 0.5); } .btn-check:checked + .btn-outline-dark, .btn-check:active + .btn-outline-dark, .btn-outline-dark:active, .btn-outline-dark.active, .btn-outline-dark.dropdown-toggle.show { color: #fff; background-color: #212529; border-color: #212529; } .btn-check:checked + .btn-outline-dark:focus, .btn-check:active + .btn-outline-dark:focus, .btn-outline-dark:active:focus, .btn-outline-dark.active:focus, .btn-outline-dark.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(33, 37, 41, 0.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-lg, .btn-group-lg > .btn { padding: 0.5rem 1rem; font-size: 1.25rem; border-radius: 0.3rem; } .btn-sm, .btn-group-sm > .btn { padding: 0.25rem 0.5rem; font-size: 0.875rem; border-radius: 0.2rem; } .fade { transition: opacity 0.15s linear; } @media (prefers-reduced-motion: reduce) { .fade { transition: none; } } .fade:not(.show) { opacity: 0; } .collapse:not(.show) { display: none; } .collapsing { height: 0; overflow: hidden; transition: height 0.35s ease; } @media (prefers-reduced-motion: reduce) { .collapsing { transition: none; } } .collapsing.collapse-horizontal { width: 0; height: auto; transition: width 0.35s ease; } @media (prefers-reduced-motion: reduce) { .collapsing.collapse-horizontal { transition: none; } } .dropup, .dropend, .dropdown, .dropstart { position: relative; } .dropdown-toggle { white-space: nowrap; } .dropdown-toggle::after { display: inline-block; margin-left: 0.255em; vertical-align: 0.255em; content: ""; border-top: 0.3em solid; border-right: 0.3em solid transparent; border-bottom: 0; border-left: 0.3em solid transparent; } .dropdown-toggle:empty::after { margin-left: 0; } .dropdown-menu { position: absolute; z-index: 1000; display: none; min-width: 10rem; padding: 0.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, 0.15); border-radius: 0.25rem; } .dropdown-menu[data-bs-popper] { top: 100%; left: 0; margin-top: 0.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: 0.125rem; } .dropup .dropdown-toggle::after { display: inline-block; margin-left: 0.255em; vertical-align: 0.255em; content: ""; border-top: 0; border-right: 0.3em solid transparent; border-bottom: 0.3em solid; border-left: 0.3em solid transparent; } .dropup .dropdown-toggle:empty::after { margin-left: 0; } .dropend .dropdown-menu[data-bs-popper] { top: 0; right: auto; left: 100%; margin-top: 0; margin-left: 0.125rem; } .dropend .dropdown-toggle::after { display: inline-block; margin-left: 0.255em; vertical-align: 0.255em; content: ""; border-top: 0.3em solid transparent; border-right: 0; border-bottom: 0.3em solid transparent; border-left: 0.3em solid; } .dropend .dropdown-toggle:empty::after { margin-left: 0; } .dropend .dropdown-toggle::after { vertical-align: 0; } .dropstart .dropdown-menu[data-bs-popper] { top: 0; right: 100%; left: auto; margin-top: 0; margin-right: 0.125rem; } .dropstart .dropdown-toggle::after { display: inline-block; margin-left: 0.255em; vertical-align: 0.255em; content: ""; } .dropstart .dropdown-toggle::after { display: none; } .dropstart .dropdown-toggle::before { display: inline-block; margin-right: 0.255em; vertical-align: 0.255em; content: ""; border-top: 0.3em solid transparent; border-right: 0.3em solid; border-bottom: 0.3em solid transparent; } .dropstart .dropdown-toggle:empty::after { margin-left: 0; } .dropstart .dropdown-toggle::before { vertical-align: 0; } .dropdown-divider { height: 0; margin: 0.5rem 0; overflow: hidden; border-top: 1px solid rgba(0, 0, 0, 0.15); } .dropdown-item { display: block; width: 100%; padding: 0.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:hover, .dropdown-item:focus { 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: 0.5rem 1rem; margin-bottom: 0; font-size: 0.875rem; color: #6c757d; white-space: nowrap; } .dropdown-item-text { display: block; padding: 0.25rem 1rem; color: #212529; } .dropdown-menu-dark { color: #dee2e6; background-color: #343a40; border-color: rgba(0, 0, 0, 0.15); } .dropdown-menu-dark .dropdown-item { color: #dee2e6; } .dropdown-menu-dark .dropdown-item:hover, .dropdown-menu-dark .dropdown-item:focus { color: #fff; background-color: rgba(255, 255, 255, 0.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, 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 > .btn, .btn-group-vertical > .btn { position: relative; flex: 1 1 auto; } .btn-group > .btn-check:checked + .btn, .btn-group > .btn-check:focus + .btn, .btn-group > .btn:hover, .btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active, .btn-group-vertical > .btn-check:checked + .btn, .btn-group-vertical > .btn-check:focus + .btn, .btn-group-vertical > .btn:hover, .btn-group-vertical > .btn:focus, .btn-group-vertical > .btn:active, .btn-group-vertical > .btn.active { z-index: 1; } .btn-toolbar { display: flex; flex-wrap: wrap; justify-content: flex-start; } .btn-toolbar .input-group { width: auto; } .btn-group > .btn:not(:first-child), .btn-group > .btn-group:not(:first-child) { margin-left: -1px; } .btn-group > .btn:not(:last-child):not(.dropdown-toggle), .btn-group > .btn-group:not(:last-child) > .btn { border-top-right-radius: 0; border-bottom-right-radius: 0; } .btn-group > .btn:nth-child(n+3), .btn-group > :not(.btn-check) + .btn, .btn-group > .btn-group:not(:first-child) > .btn { border-top-left-radius: 0; border-bottom-left-radius: 0; } .dropdown-toggle-split { padding-right: 0.5625rem; padding-left: 0.5625rem; } .dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after { margin-left: 0; } .dropstart .dropdown-toggle-split::before { margin-right: 0; } .btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { padding-right: 0.375rem; padding-left: 0.375rem; } .btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { padding-right: 0.75rem; padding-left: 0.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:not(:first-child), .btn-group-vertical > .btn-group:not(:first-child) { margin-top: -1px; } .btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), .btn-group-vertical > .btn-group:not(:last-child) > .btn { border-bottom-right-radius: 0; border-bottom-left-radius: 0; } .btn-group-vertical > .btn ~ .btn, .btn-group-vertical > .btn-group:not(:first-child) > .btn { border-top-left-radius: 0; border-top-right-radius: 0; } .nav { display: flex; flex-wrap: wrap; padding-left: 0; margin-bottom: 0; list-style: none; } .nav-link { display: block; padding: 0.5rem 1rem; color: #0d6efd; text-decoration: none; transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .nav-link { transition: none; } } .nav-link:hover, .nav-link:focus { color: #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: none; border: 1px solid transparent; border-top-left-radius: 0.25rem; border-top-right-radius: 0.25rem; } .nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { border-color: #e9ecef #e9ecef #dee2e6; isolation: isolate; } .nav-tabs .nav-link.disabled { color: #6c757d; background-color: transparent; border-color: transparent; } .nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link { 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: none; border: 0; border-radius: 0.25rem; } .nav-pills .nav-link.active, .nav-pills .show > .nav-link { color: #fff; background-color: #0d6efd; } .nav-fill > .nav-link, .nav-fill .nav-item { flex: 1 1 auto; text-align: center; } .nav-justified > .nav-link, .nav-justified .nav-item { flex-basis: 0; flex-grow: 1; text-align: center; } .nav-fill .nav-item .nav-link, .nav-justified .nav-item .nav-link { width: 100%; } .tab-content > .tab-pane { display: none; } .tab-content > .active { display: block; } .navbar { position: relative; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; padding-top: 0.5rem; padding-bottom: 0.5rem; } .navbar > .container, .navbar > .container-fluid, .navbar > .container-sm, .navbar > .container-md, .navbar > .container-lg, .navbar > .container-xl, .navbar > .container-xxl { display: flex; flex-wrap: inherit; align-items: center; justify-content: space-between; } .navbar-brand { padding-top: 0.3125rem; padding-bottom: 0.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: 0.5rem; padding-bottom: 0.5rem; } .navbar-collapse { flex-basis: 100%; flex-grow: 1; align-items: center; } .navbar-toggler { padding: 0.25rem 0.75rem; font-size: 1.25rem; line-height: 1; background-color: transparent; border: 1px solid transparent; border-radius: 0.25rem; transition: box-shadow 0.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 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: 0.5rem; padding-left: 0.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-top, .navbar-expand-sm .offcanvas-bottom { 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: 0.5rem; padding-left: 0.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-top, .navbar-expand-md .offcanvas-bottom { 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: 0.5rem; padding-left: 0.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-top, .navbar-expand-lg .offcanvas-bottom { 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: 0.5rem; padding-left: 0.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-top, .navbar-expand-xl .offcanvas-bottom { 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: 0.5rem; padding-left: 0.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-top, .navbar-expand-xxl .offcanvas-bottom { 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: 0.5rem; padding-left: 0.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-top, .navbar-expand .offcanvas-bottom { 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, 0.9); } .navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus { color: rgba(0, 0, 0, 0.9); } .navbar-light .navbar-nav .nav-link { color: rgba(0, 0, 0, 0.55); } .navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus { color: rgba(0, 0, 0, 0.7); } .navbar-light .navbar-nav .nav-link.disabled { color: rgba(0, 0, 0, 0.3); } .navbar-light .navbar-nav .show > .nav-link, .navbar-light .navbar-nav .nav-link.active { color: rgba(0, 0, 0, 0.9); } .navbar-light .navbar-toggler { color: rgba(0, 0, 0, 0.55); border-color: rgba(0, 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, 0.55); } .navbar-light .navbar-text a, .navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus { color: rgba(0, 0, 0, 0.9); } .navbar-dark .navbar-brand { color: #fff; } .navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus { color: #fff; } .navbar-dark .navbar-nav .nav-link { color: rgba(255, 255, 255, 0.55); } .navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus { color: rgba(255, 255, 255, 0.75); } .navbar-dark .navbar-nav .nav-link.disabled { color: rgba(255, 255, 255, 0.25); } .navbar-dark .navbar-nav .show > .nav-link, .navbar-dark .navbar-nav .nav-link.active { color: #fff; } .navbar-dark .navbar-toggler { color: rgba(255, 255, 255, 0.55); border-color: rgba(255, 255, 255, 0.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, 0.55); } .navbar-dark .navbar-text a, .navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus { 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, 0.125); border-radius: 0.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(0.25rem - 1px); border-top-right-radius: calc(0.25rem - 1px); } .card > .list-group:last-child { border-bottom-width: 0; border-bottom-right-radius: calc(0.25rem - 1px); border-bottom-left-radius: calc(0.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: 0.5rem; } .card-subtitle { margin-top: -0.25rem; margin-bottom: 0; } .card-text:last-child { margin-bottom: 0; } .card-link + .card-link { margin-left: 1rem; } .card-header { padding: 0.5rem 1rem; margin-bottom: 0; background-color: rgba(0, 0, 0, 0.03); border-bottom: 1px solid rgba(0, 0, 0, 0.125); } .card-header:first-child { border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0; } .card-footer { padding: 0.5rem 1rem; background-color: rgba(0, 0, 0, 0.03); border-top: 1px solid rgba(0, 0, 0, 0.125); } .card-footer:last-child { border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px); } .card-header-tabs { margin-right: -0.5rem; margin-bottom: -0.5rem; margin-left: -0.5rem; border-bottom: 0; } .card-header-pills { margin-right: -0.5rem; margin-left: -0.5rem; } .card-img-overlay { position: absolute; top: 0; right: 0; bottom: 0; left: 0; padding: 1rem; border-radius: calc(0.25rem - 1px); } .card-img, .card-img-top, .card-img-bottom { width: 100%; } .card-img, .card-img-top { border-top-left-radius: calc(0.25rem - 1px); border-top-right-radius: calc(0.25rem - 1px); } .card-img, .card-img-bottom { border-bottom-right-radius: calc(0.25rem - 1px); border-bottom-left-radius: calc(0.25rem - 1px); } .card-group > .card { margin-bottom: 0.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-img-top, .card-group > .card:not(:last-child) .card-header { border-top-right-radius: 0; } .card-group > .card:not(:last-child) .card-img-bottom, .card-group > .card:not(:last-child) .card-footer { border-bottom-right-radius: 0; } .card-group > .card:not(:first-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; } .card-group > .card:not(:first-child) .card-img-top, .card-group > .card:not(:first-child) .card-header { border-top-left-radius: 0; } .card-group > .card:not(:first-child) .card-img-bottom, .card-group > .card:not(:first-child) .card-footer { border-bottom-left-radius: 0; } } .accordion-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 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease; } @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, 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 0.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 0.25rem rgba(13, 110, 253, 0.25); } .accordion-header { margin-bottom: 0; } .accordion-item { background-color: #fff; border: 1px solid rgba(0, 0, 0, 0.125); } .accordion-item:first-of-type { border-top-left-radius: 0.25rem; border-top-right-radius: 0.25rem; } .accordion-item:first-of-type .accordion-button { border-top-left-radius: calc(0.25rem - 1px); border-top-right-radius: calc(0.25rem - 1px); } .accordion-item:not(:first-of-type) { border-top: 0; } .accordion-item:last-of-type { border-bottom-right-radius: 0.25rem; border-bottom-left-radius: 0.25rem; } .accordion-item:last-of-type .accordion-button.collapsed { border-bottom-right-radius: calc(0.25rem - 1px); border-bottom-left-radius: calc(0.25rem - 1px); } .accordion-item:last-of-type .accordion-collapse { border-bottom-right-radius: 0.25rem; border-bottom-left-radius: 0.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: 0.5rem; } .breadcrumb-item + .breadcrumb-item::before { float: left; padding-right: 0.5rem; color: #6c757d; content: var(--bs-breadcrumb-divider, "/") /* rtl: 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 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .page-link { 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 0.25rem rgba(13, 110, 253, 0.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: 0.375rem 0.75rem; } .page-item:first-child .page-link { border-top-left-radius: 0.25rem; border-bottom-left-radius: 0.25rem; } .page-item:last-child .page-link { border-top-right-radius: 0.25rem; border-bottom-right-radius: 0.25rem; } .pagination-lg .page-link { padding: 0.75rem 1.5rem; font-size: 1.25rem; } .pagination-lg .page-item:first-child .page-link { border-top-left-radius: 0.3rem; border-bottom-left-radius: 0.3rem; } .pagination-lg .page-item:last-child .page-link { border-top-right-radius: 0.3rem; border-bottom-right-radius: 0.3rem; } .pagination-sm .page-link { padding: 0.25rem 0.5rem; font-size: 0.875rem; } .pagination-sm .page-item:first-child .page-link { border-top-left-radius: 0.2rem; border-bottom-left-radius: 0.2rem; } .pagination-sm .page-item:last-child .page-link { border-top-right-radius: 0.2rem; border-bottom-right-radius: 0.2rem; } .badge { display: inline-block; padding: 0.35em 0.65em; font-size: 0.75em; font-weight: 700; line-height: 1; color: #fff; text-align: center; white-space: nowrap; vertical-align: baseline; border-radius: 0.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: 0.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: 0.75rem; background-color: #e9ecef; border-radius: 0.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 0.6s ease; } @media (prefers-reduced-motion: reduce) { .progress-bar { transition: none; } } .progress-bar-striped { background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-size: 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: 0.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:hover, .list-group-item-action:focus { 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: 0.5rem 1rem; color: #212529; text-decoration: none; background-color: #fff; border: 1px solid rgba(0, 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: 0.25rem; border-top-right-radius: 0; } .list-group-horizontal > .list-group-item:last-child { border-top-right-radius: 0.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: 0.25rem; border-top-right-radius: 0; } .list-group-horizontal-sm > .list-group-item:last-child { border-top-right-radius: 0.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: 0.25rem; border-top-right-radius: 0; } .list-group-horizontal-md > .list-group-item:last-child { border-top-right-radius: 0.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: 0.25rem; border-top-right-radius: 0; } .list-group-horizontal-lg > .list-group-item:last-child { border-top-right-radius: 0.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: 0.25rem; border-top-right-radius: 0; } .list-group-horizontal-xl > .list-group-item:last-child { border-top-right-radius: 0.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: 0.25rem; border-top-right-radius: 0; } .list-group-horizontal-xxl > .list-group-item:last-child { border-top-right-radius: 0.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:hover, .list-group-item-primary.list-group-item-action:focus { 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:hover, .list-group-item-secondary.list-group-item-action:focus { 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:hover, .list-group-item-success.list-group-item-action:focus { 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:hover, .list-group-item-info.list-group-item-action:focus { 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:hover, .list-group-item-warning.list-group-item-action:focus { 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:hover, .list-group-item-danger.list-group-item-action:focus { 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:hover, .list-group-item-light.list-group-item-action:focus { 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:hover, .list-group-item-dark.list-group-item-action:focus { 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: 0.25em 0.25em; color: #000; background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 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: 0.25rem; opacity: 0.5; } .btn-close:hover { color: #000; text-decoration: none; opacity: 0.75; } .btn-close:focus { outline: 0; box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); opacity: 1; } .btn-close:disabled, .btn-close.disabled { pointer-events: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; opacity: 0.25; } .btn-close-white { filter: invert(1) grayscale(100%) brightness(200%); } .toast { width: 350px; max-width: 100%; font-size: 0.875rem; pointer-events: auto; background-color: rgba(255, 255, 255, 0.85); background-clip: padding-box; border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); border-radius: 0.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: 0.75rem; } .toast-header { display: flex; align-items: center; padding: 0.5rem 0.75rem; color: #6c757d; background-color: rgba(255, 255, 255, 0.85); background-clip: padding-box; border-bottom: 1px solid rgba(0, 0, 0, 0.05); border-top-left-radius: calc(0.25rem - 1px); border-top-right-radius: calc(0.25rem - 1px); } .toast-header .btn-close { margin-right: -0.375rem; margin-left: 0.75rem; } .toast-body { padding: 0.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: 0.5rem; pointer-events: none; } .modal.fade .modal-dialog { transition: transform 0.3s ease-out; transform: translate(0, -50px); } @media (prefers-reduced-motion: reduce) { .modal.fade .modal-dialog { transition: none; } } .modal.show .modal-dialog { transform: none; } .modal.modal-static .modal-dialog { transform: scale(1.02); } .modal-dialog-scrollable { height: calc(100% - 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, 0.2); border-radius: 0.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: 0.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(0.3rem - 1px); border-top-right-radius: calc(0.3rem - 1px); } .modal-header .btn-close { padding: 0.5rem 0.5rem; margin: -0.5rem -0.5rem -0.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: 0.75rem; border-top: 1px solid #dee2e6; border-bottom-right-radius: calc(0.3rem - 1px); border-bottom-left-radius: calc(0.3rem - 1px); } .modal-footer > * { margin: 0.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: 0.875rem; word-wrap: break-word; opacity: 0; } .tooltip.show { opacity: 0.9; } .tooltip .tooltip-arrow { position: absolute; display: block; width: 0.8rem; height: 0.4rem; } .tooltip .tooltip-arrow::before { position: absolute; content: ""; border-color: transparent; border-style: solid; } .bs-tooltip-top, .bs-tooltip-auto[data-popper-placement^=top] { padding: 0.4rem 0; } .bs-tooltip-top .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow { bottom: 0; } .bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before { top: -1px; border-width: 0.4rem 0.4rem 0; border-top-color: #000; } .bs-tooltip-end, .bs-tooltip-auto[data-popper-placement^=right] { padding: 0 0.4rem; } .bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow { left: 0; width: 0.4rem; height: 0.8rem; } .bs-tooltip-end .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before { right: -1px; border-width: 0.4rem 0.4rem 0.4rem 0; border-right-color: #000; } .bs-tooltip-bottom, .bs-tooltip-auto[data-popper-placement^=bottom] { padding: 0.4rem 0; } .bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow { top: 0; } .bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before { bottom: -1px; border-width: 0 0.4rem 0.4rem; border-bottom-color: #000; } .bs-tooltip-start, .bs-tooltip-auto[data-popper-placement^=left] { padding: 0 0.4rem; } .bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow { right: 0; width: 0.4rem; height: 0.8rem; } .bs-tooltip-start .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before { left: -1px; border-width: 0.4rem 0 0.4rem 0.4rem; border-left-color: #000; } .tooltip-inner { max-width: 200px; padding: 0.25rem 0.5rem; color: #fff; text-align: center; background-color: #000; border-radius: 0.25rem; } .popover { position: absolute; top: 0; left: 0 /* rtl:ignore */; 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: 0.875rem; word-wrap: break-word; background-color: #fff; background-clip: padding-box; border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 0.3rem; } .popover .popover-arrow { position: absolute; display: block; width: 1rem; height: 0.5rem; } .popover .popover-arrow::before, .popover .popover-arrow::after { position: absolute; display: block; content: ""; border-color: transparent; border-style: solid; } .bs-popover-top > .popover-arrow, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow { bottom: calc(-0.5rem - 1px); } .bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before { bottom: 0; border-width: 0.5rem 0.5rem 0; border-top-color: rgba(0, 0, 0, 0.25); } .bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after { bottom: 1px; border-width: 0.5rem 0.5rem 0; border-top-color: #fff; } .bs-popover-end > .popover-arrow, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow { left: calc(-0.5rem - 1px); width: 0.5rem; height: 1rem; } .bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before { left: 0; border-width: 0.5rem 0.5rem 0.5rem 0; border-right-color: rgba(0, 0, 0, 0.25); } .bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after { left: 1px; border-width: 0.5rem 0.5rem 0.5rem 0; border-right-color: #fff; } .bs-popover-bottom > .popover-arrow, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow { top: calc(-0.5rem - 1px); } .bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before { top: 0; border-width: 0 0.5rem 0.5rem 0.5rem; border-bottom-color: rgba(0, 0, 0, 0.25); } .bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after { top: 1px; border-width: 0 0.5rem 0.5rem 0.5rem; border-bottom-color: #fff; } .bs-popover-bottom .popover-header::before, .bs-popover-auto[data-popper-placement^=bottom] .popover-header::before { position: absolute; top: 0; left: 50%; display: block; width: 1rem; margin-left: -0.5rem; content: ""; border-bottom: 1px solid #f0f0f0; } .bs-popover-start > .popover-arrow, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow { right: calc(-0.5rem - 1px); width: 0.5rem; height: 1rem; } .bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before { right: 0; border-width: 0.5rem 0 0.5rem 0.5rem; border-left-color: rgba(0, 0, 0, 0.25); } .bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after { right: 1px; border-width: 0.5rem 0 0.5rem 0.5rem; border-left-color: #fff; } .popover-header { padding: 0.5rem 1rem; margin-bottom: 0; font-size: 1rem; background-color: #f0f0f0; border-bottom: 1px solid rgba(0, 0, 0, 0.2); border-top-left-radius: calc(0.3rem - 1px); border-top-right-radius: calc(0.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 0.6s ease-in-out; } @media (prefers-reduced-motion: reduce) { .carousel-item { transition: none; } } .carousel-item.active, .carousel-item-next, .carousel-item-prev { display: block; } /* rtl:begin:ignore */ .carousel-item-next:not(.carousel-item-start), .active.carousel-item-end { transform: translateX(100%); } .carousel-item-prev:not(.carousel-item-end), .active.carousel-item-start { transform: translateX(-100%); } /* rtl:end:ignore */ .carousel-fade .carousel-item { opacity: 0; transition-property: opacity; transform: none; } .carousel-fade .carousel-item.active, .carousel-fade .carousel-item-next.carousel-item-start, .carousel-fade .carousel-item-prev.carousel-item-end { z-index: 1; opacity: 1; } .carousel-fade .active.carousel-item-start, .carousel-fade .active.carousel-item-end { z-index: 0; opacity: 0; transition: opacity 0s 0.6s; } @media (prefers-reduced-motion: reduce) { .carousel-fade .active.carousel-item-start, .carousel-fade .active.carousel-item-end { transition: none; } } .carousel-control-prev, .carousel-control-next { position: absolute; top: 0; bottom: 0; z-index: 1; display: flex; align-items: center; justify-content: center; width: 15%; padding: 0; color: #fff; text-align: center; background: none; border: 0; opacity: 0.5; transition: opacity 0.15s ease; } @media (prefers-reduced-motion: reduce) { .carousel-control-prev, .carousel-control-next { transition: none; } } .carousel-control-prev:hover, .carousel-control-prev:focus, .carousel-control-next:hover, .carousel-control-next:focus { color: #fff; text-decoration: none; outline: 0; opacity: 0.9; } .carousel-control-prev { left: 0; } .carousel-control-next { right: 0; } .carousel-control-prev-icon, .carousel-control-next-icon { display: inline-block; width: 2rem; height: 2rem; background-repeat: no-repeat; background-position: 50%; background-size: 100% 100%; } /* rtl:options: { "autoRename": true, "stringMap":[ { "name" : "prev-next", "search" : "prev", "replace" : "next" } ] } */ .carousel-control-prev-icon { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e"); } .carousel-control-next-icon { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); } .carousel-indicators { position: absolute; right: 0; bottom: 0; left: 0; z-index: 2; display: flex; justify-content: center; padding: 0; margin-right: 15%; margin-bottom: 1rem; margin-left: 15%; list-style: none; } .carousel-indicators [data-bs-target] { box-sizing: content-box; flex: 0 1 auto; width: 30px; height: 3px; padding: 0; margin-right: 3px; margin-left: 3px; text-indent: -999px; cursor: pointer; background-color: #fff; background-clip: padding-box; border: 0; border-top: 10px solid transparent; border-bottom: 10px solid transparent; opacity: 0.5; transition: opacity 0.6s ease; } @media (prefers-reduced-motion: reduce) { .carousel-indicators [data-bs-target] { transition: none; } } .carousel-indicators .active { opacity: 1; } .carousel-caption { position: absolute; right: 15%; bottom: 1.25rem; left: 15%; padding-top: 1.25rem; padding-bottom: 1.25rem; color: #fff; text-align: center; } .carousel-dark .carousel-control-prev-icon, .carousel-dark .carousel-control-next-icon { filter: invert(1) grayscale(100); } .carousel-dark .carousel-indicators [data-bs-target] { background-color: #000; } .carousel-dark .carousel-caption { color: #000; } @-webkit-keyframes spinner-border { to { transform: rotate(360deg) /* rtl:ignore */; } } @keyframes spinner-border { to { transform: rotate(360deg) /* rtl:ignore */; } } .spinner-border { display: inline-block; width: 2rem; height: 2rem; vertical-align: -0.125em; border: 0.25em solid currentColor; border-right-color: transparent; border-radius: 50%; -webkit-animation: 0.75s linear infinite spinner-border; animation: 0.75s linear infinite spinner-border; } .spinner-border-sm { width: 1rem; height: 1rem; border-width: 0.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: -0.125em; background-color: currentColor; border-radius: 50%; opacity: 0; -webkit-animation: 0.75s linear infinite spinner-grow; animation: 0.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 0.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: 0.5; } .offcanvas-header { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1rem; } .offcanvas-header .btn-close { padding: 0.5rem 0.5rem; margin-top: -0.5rem; margin-right: -0.5rem; margin-bottom: -0.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, 0.2); transform: translateX(-100%); } .offcanvas-end { top: 0; right: 0; width: 400px; border-left: 1px solid rgba(0, 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, 0.2); transform: translateY(-100%); } .offcanvas-bottom { right: 0; left: 0; height: 30vh; max-height: 100%; border-top: 1px solid rgba(0, 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: 0.5; } .placeholder.btn::before { display: inline-block; content: ""; } .placeholder-xs { min-height: 0.6em; } .placeholder-sm { min-height: 0.8em; } .placeholder-lg { min-height: 1.2em; } .placeholder-glow .placeholder { -webkit-animation: placeholder-glow 2s ease-in-out infinite; animation: placeholder-glow 2s ease-in-out infinite; } @-webkit-keyframes placeholder-glow { 50% { opacity: 0.2; } } @keyframes placeholder-glow { 50% { opacity: 0.2; } } .placeholder-wave { -webkit-mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%); mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%); -webkit-mask-size: 200% 100%; mask-size: 200% 100%; -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:hover, .link-primary:focus { color: #0a58ca; } .link-secondary { color: #6c757d; } .link-secondary:hover, .link-secondary:focus { color: #565e64; } .link-success { color: #198754; } .link-success:hover, .link-success:focus { color: #146c43; } .link-info { color: #0dcaf0; } .link-info:hover, .link-info:focus { color: #3dd5f3; } .link-warning { color: #ffc107; } .link-warning:hover, .link-warning:focus { color: #ffcd39; } .link-danger { color: #dc3545; } .link-danger:hover, .link-danger:focus { color: #b02a37; } .link-light { color: #f8f9fa; } .link-light:hover, .link-light:focus { color: #f9fafb; } .link-dark { color: #212529; } .link-dark:hover, .link-dark:focus { 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: 0.25; } .align-baseline { vertical-align: baseline !important; } .align-top { vertical-align: top !important; } .align-middle { vertical-align: middle !important; } .align-bottom { vertical-align: bottom !important; } .align-text-bottom { vertical-align: text-bottom !important; } .align-text-top { vertical-align: text-top !important; } .float-start { float: left !important; } .float-end { float: right !important; } .float-none { float: none !important; } .opacity-0 { opacity: 0 !important; } .opacity-25 { opacity: 0.25 !important; } .opacity-50 { opacity: 0.5 !important; } .opacity-75 { opacity: 0.75 !important; } .opacity-100 { opacity: 1 !important; } .overflow-auto { overflow: auto !important; } .overflow-hidden { overflow: hidden !important; } .overflow-visible { overflow: visible !important; } .overflow-scroll { overflow: scroll !important; } .d-inline { display: inline !important; } .d-inline-block { display: inline-block !important; } .d-block { display: block !important; } .d-grid { display: grid !important; } .d-table { display: table !important; } .d-table-row { display: table-row !important; } .d-table-cell { display: table-cell !important; } .d-flex { display: flex !important; } .d-inline-flex { display: inline-flex !important; } .d-none { display: none !important; } .shadow { box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; } .shadow-sm { box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; } .shadow-lg { box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; } .shadow-none { box-shadow: none !important; } .position-static { position: static !important; } .position-relative { position: relative !important; } .position-absolute { position: absolute !important; } .position-fixed { position: fixed !important; } .position-sticky { position: -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: 0.25rem !important; } .gap-2 { gap: 0.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: 0.25rem !important; } .m-2 { margin: 0.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: 0.25rem !important; margin-left: 0.25rem !important; } .mx-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-5 { margin-top: 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: 0.25rem !important; } .mt-2 { margin-top: 0.5rem !important; } .mt-3 { margin-top: 1rem !important; } .mt-4 { margin-top: 1.5rem !important; } .mt-5 { margin-top: 3rem !important; } .mt-auto { margin-top: auto !important; } .me-0 { margin-right: 0 !important; } .me-1 { margin-right: 0.25rem !important; } .me-2 { margin-right: 0.5rem !important; } .me-3 { margin-right: 1rem !important; } .me-4 { margin-right: 1.5rem !important; } .me-5 { margin-right: 3rem !important; } .me-auto { margin-right: auto !important; } .mb-0 { margin-bottom: 0 !important; } .mb-1 { margin-bottom: 0.25rem !important; } .mb-2 { margin-bottom: 0.5rem !important; } .mb-3 { margin-bottom: 1rem !important; } .mb-4 { margin-bottom: 1.5rem !important; } .mb-5 { margin-bottom: 3rem !important; } .mb-auto { margin-bottom: auto !important; } .ms-0 { margin-left: 0 !important; } .ms-1 { margin-left: 0.25rem !important; } .ms-2 { margin-left: 0.5rem !important; } .ms-3 { margin-left: 1rem !important; } .ms-4 { margin-left: 1.5rem !important; } .ms-5 { margin-left: 3rem !important; } .ms-auto { margin-left: auto !important; } .p-0 { padding: 0 !important; } .p-1 { padding: 0.25rem !important; } .p-2 { padding: 0.5rem !important; } .p-3 { padding: 1rem !important; } .p-4 { padding: 1.5rem !important; } .p-5 { padding: 3rem !important; } .px-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-0 { padding-top: 0 !important; } .pt-1 { padding-top: 0.25rem !important; } .pt-2 { padding-top: 0.5rem !important; } .pt-3 { padding-top: 1rem !important; } .pt-4 { padding-top: 1.5rem !important; } .pt-5 { padding-top: 3rem !important; } .pe-0 { padding-right: 0 !important; } .pe-1 { padding-right: 0.25rem !important; } .pe-2 { padding-right: 0.5rem !important; } .pe-3 { padding-right: 1rem !important; } .pe-4 { padding-right: 1.5rem !important; } .pe-5 { padding-right: 3rem !important; } .pb-0 { padding-bottom: 0 !important; } .pb-1 { padding-bottom: 0.25rem !important; } .pb-2 { padding-bottom: 0.5rem !important; } .pb-3 { padding-bottom: 1rem !important; } .pb-4 { padding-bottom: 1.5rem !important; } .pb-5 { padding-bottom: 3rem !important; } .ps-0 { padding-left: 0 !important; } .ps-1 { padding-left: 0.25rem !important; } .ps-2 { padding-left: 0.5rem !important; } .ps-3 { padding-left: 1rem !important; } .ps-4 { padding-left: 1.5rem !important; } .ps-5 { padding-left: 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 + 0.9vw) !important; } .fs-3 { font-size: calc(1.3rem + 0.6vw) !important; } .fs-4 { font-size: calc(1.275rem + 0.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; } /* rtl:begin:remove */ .text-break { word-wrap: break-word !important; word-break: break-word !important; } /* rtl:end:remove */ .text-primary { --bs-text-opacity: 1; color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important; } .text-secondary { --bs-text-opacity: 1; color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important; } .text-success { --bs-text-opacity: 1; color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important; } .text-info { --bs-text-opacity: 1; color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important; } .text-warning { --bs-text-opacity: 1; color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important; } .text-danger { --bs-text-opacity: 1; color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important; } .text-light { --bs-text-opacity: 1; color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important; } .text-dark { --bs-text-opacity: 1; color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important; } .text-black { --bs-text-opacity: 1; color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important; } .text-white { --bs-text-opacity: 1; color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important; } .text-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, 0.5) !important; } .text-white-50 { --bs-text-opacity: 1; color: rgba(255, 255, 255, 0.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: 0.25rem !important; } .rounded-0 { border-radius: 0 !important; } .rounded-1 { border-radius: 0.2rem !important; } .rounded-2 { border-radius: 0.25rem !important; } .rounded-3 { border-radius: 0.3rem !important; } .rounded-circle { border-radius: 50% !important; } .rounded-pill { border-radius: 50rem !important; } .rounded-top { border-top-left-radius: 0.25rem !important; border-top-right-radius: 0.25rem !important; } .rounded-end { border-top-right-radius: 0.25rem !important; border-bottom-right-radius: 0.25rem !important; } .rounded-bottom { border-bottom-right-radius: 0.25rem !important; border-bottom-left-radius: 0.25rem !important; } .rounded-start { border-bottom-left-radius: 0.25rem !important; border-top-left-radius: 0.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: 0.25rem !important; } .gap-sm-2 { gap: 0.5rem !important; } .gap-sm-3 { gap: 1rem !important; } .gap-sm-4 { gap: 1.5rem !important; } .gap-sm-5 { gap: 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: 0.25rem !important; } .m-sm-2 { margin: 0.5rem !important; } .m-sm-3 { margin: 1rem !important; } .m-sm-4 { margin: 1.5rem !important; } .m-sm-5 { margin: 3rem !important; } .m-sm-auto { margin: auto !important; } .mx-sm-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-sm-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-sm-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-sm-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-sm-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-sm-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-sm-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-sm-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-sm-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-sm-5 { margin-top: 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: 0.25rem !important; } .mt-sm-2 { margin-top: 0.5rem !important; } .mt-sm-3 { margin-top: 1rem !important; } .mt-sm-4 { margin-top: 1.5rem !important; } .mt-sm-5 { margin-top: 3rem !important; } .mt-sm-auto { margin-top: auto !important; } .me-sm-0 { margin-right: 0 !important; } .me-sm-1 { margin-right: 0.25rem !important; } .me-sm-2 { margin-right: 0.5rem !important; } .me-sm-3 { margin-right: 1rem !important; } .me-sm-4 { margin-right: 1.5rem !important; } .me-sm-5 { margin-right: 3rem !important; } .me-sm-auto { margin-right: auto !important; } .mb-sm-0 { margin-bottom: 0 !important; } .mb-sm-1 { margin-bottom: 0.25rem !important; } .mb-sm-2 { margin-bottom: 0.5rem !important; } .mb-sm-3 { margin-bottom: 1rem !important; } .mb-sm-4 { margin-bottom: 1.5rem !important; } .mb-sm-5 { margin-bottom: 3rem !important; } .mb-sm-auto { margin-bottom: auto !important; } .ms-sm-0 { margin-left: 0 !important; } .ms-sm-1 { margin-left: 0.25rem !important; } .ms-sm-2 { margin-left: 0.5rem !important; } .ms-sm-3 { margin-left: 1rem !important; } .ms-sm-4 { margin-left: 1.5rem !important; } .ms-sm-5 { margin-left: 3rem !important; } .ms-sm-auto { margin-left: auto !important; } .p-sm-0 { padding: 0 !important; } .p-sm-1 { padding: 0.25rem !important; } .p-sm-2 { padding: 0.5rem !important; } .p-sm-3 { padding: 1rem !important; } .p-sm-4 { padding: 1.5rem !important; } .p-sm-5 { padding: 3rem !important; } .px-sm-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-sm-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-sm-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-sm-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-sm-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-sm-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-sm-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-sm-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-sm-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-sm-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-sm-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-sm-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-sm-0 { padding-top: 0 !important; } .pt-sm-1 { padding-top: 0.25rem !important; } .pt-sm-2 { padding-top: 0.5rem !important; } .pt-sm-3 { padding-top: 1rem !important; } .pt-sm-4 { padding-top: 1.5rem !important; } .pt-sm-5 { padding-top: 3rem !important; } .pe-sm-0 { padding-right: 0 !important; } .pe-sm-1 { padding-right: 0.25rem !important; } .pe-sm-2 { padding-right: 0.5rem !important; } .pe-sm-3 { padding-right: 1rem !important; } .pe-sm-4 { padding-right: 1.5rem !important; } .pe-sm-5 { padding-right: 3rem !important; } .pb-sm-0 { padding-bottom: 0 !important; } .pb-sm-1 { padding-bottom: 0.25rem !important; } .pb-sm-2 { padding-bottom: 0.5rem !important; } .pb-sm-3 { padding-bottom: 1rem !important; } .pb-sm-4 { padding-bottom: 1.5rem !important; } .pb-sm-5 { padding-bottom: 3rem !important; } .ps-sm-0 { padding-left: 0 !important; } .ps-sm-1 { padding-left: 0.25rem !important; } .ps-sm-2 { padding-left: 0.5rem !important; } .ps-sm-3 { padding-left: 1rem !important; } .ps-sm-4 { padding-left: 1.5rem !important; } .ps-sm-5 { padding-left: 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: 0.25rem !important; } .gap-md-2 { gap: 0.5rem !important; } .gap-md-3 { gap: 1rem !important; } .gap-md-4 { gap: 1.5rem !important; } .gap-md-5 { gap: 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: 0.25rem !important; } .m-md-2 { margin: 0.5rem !important; } .m-md-3 { margin: 1rem !important; } .m-md-4 { margin: 1.5rem !important; } .m-md-5 { margin: 3rem !important; } .m-md-auto { margin: auto !important; } .mx-md-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-md-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-md-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-md-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-md-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-md-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-md-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-md-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-md-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-md-5 { margin-top: 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: 0.25rem !important; } .mt-md-2 { margin-top: 0.5rem !important; } .mt-md-3 { margin-top: 1rem !important; } .mt-md-4 { margin-top: 1.5rem !important; } .mt-md-5 { margin-top: 3rem !important; } .mt-md-auto { margin-top: auto !important; } .me-md-0 { margin-right: 0 !important; } .me-md-1 { margin-right: 0.25rem !important; } .me-md-2 { margin-right: 0.5rem !important; } .me-md-3 { margin-right: 1rem !important; } .me-md-4 { margin-right: 1.5rem !important; } .me-md-5 { margin-right: 3rem !important; } .me-md-auto { margin-right: auto !important; } .mb-md-0 { margin-bottom: 0 !important; } .mb-md-1 { margin-bottom: 0.25rem !important; } .mb-md-2 { margin-bottom: 0.5rem !important; } .mb-md-3 { margin-bottom: 1rem !important; } .mb-md-4 { margin-bottom: 1.5rem !important; } .mb-md-5 { margin-bottom: 3rem !important; } .mb-md-auto { margin-bottom: auto !important; } .ms-md-0 { margin-left: 0 !important; } .ms-md-1 { margin-left: 0.25rem !important; } .ms-md-2 { margin-left: 0.5rem !important; } .ms-md-3 { margin-left: 1rem !important; } .ms-md-4 { margin-left: 1.5rem !important; } .ms-md-5 { margin-left: 3rem !important; } .ms-md-auto { margin-left: auto !important; } .p-md-0 { padding: 0 !important; } .p-md-1 { padding: 0.25rem !important; } .p-md-2 { padding: 0.5rem !important; } .p-md-3 { padding: 1rem !important; } .p-md-4 { padding: 1.5rem !important; } .p-md-5 { padding: 3rem !important; } .px-md-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-md-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-md-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-md-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-md-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-md-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-md-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-md-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-md-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-md-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-md-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-md-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-md-0 { padding-top: 0 !important; } .pt-md-1 { padding-top: 0.25rem !important; } .pt-md-2 { padding-top: 0.5rem !important; } .pt-md-3 { padding-top: 1rem !important; } .pt-md-4 { padding-top: 1.5rem !important; } .pt-md-5 { padding-top: 3rem !important; } .pe-md-0 { padding-right: 0 !important; } .pe-md-1 { padding-right: 0.25rem !important; } .pe-md-2 { padding-right: 0.5rem !important; } .pe-md-3 { padding-right: 1rem !important; } .pe-md-4 { padding-right: 1.5rem !important; } .pe-md-5 { padding-right: 3rem !important; } .pb-md-0 { padding-bottom: 0 !important; } .pb-md-1 { padding-bottom: 0.25rem !important; } .pb-md-2 { padding-bottom: 0.5rem !important; } .pb-md-3 { padding-bottom: 1rem !important; } .pb-md-4 { padding-bottom: 1.5rem !important; } .pb-md-5 { padding-bottom: 3rem !important; } .ps-md-0 { padding-left: 0 !important; } .ps-md-1 { padding-left: 0.25rem !important; } .ps-md-2 { padding-left: 0.5rem !important; } .ps-md-3 { padding-left: 1rem !important; } .ps-md-4 { padding-left: 1.5rem !important; } .ps-md-5 { padding-left: 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: 0.25rem !important; } .gap-lg-2 { gap: 0.5rem !important; } .gap-lg-3 { gap: 1rem !important; } .gap-lg-4 { gap: 1.5rem !important; } .gap-lg-5 { gap: 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: 0.25rem !important; } .m-lg-2 { margin: 0.5rem !important; } .m-lg-3 { margin: 1rem !important; } .m-lg-4 { margin: 1.5rem !important; } .m-lg-5 { margin: 3rem !important; } .m-lg-auto { margin: auto !important; } .mx-lg-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-lg-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-lg-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-lg-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-lg-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-lg-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-lg-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-lg-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-lg-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-lg-5 { margin-top: 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: 0.25rem !important; } .mt-lg-2 { margin-top: 0.5rem !important; } .mt-lg-3 { margin-top: 1rem !important; } .mt-lg-4 { margin-top: 1.5rem !important; } .mt-lg-5 { margin-top: 3rem !important; } .mt-lg-auto { margin-top: auto !important; } .me-lg-0 { margin-right: 0 !important; } .me-lg-1 { margin-right: 0.25rem !important; } .me-lg-2 { margin-right: 0.5rem !important; } .me-lg-3 { margin-right: 1rem !important; } .me-lg-4 { margin-right: 1.5rem !important; } .me-lg-5 { margin-right: 3rem !important; } .me-lg-auto { margin-right: auto !important; } .mb-lg-0 { margin-bottom: 0 !important; } .mb-lg-1 { margin-bottom: 0.25rem !important; } .mb-lg-2 { margin-bottom: 0.5rem !important; } .mb-lg-3 { margin-bottom: 1rem !important; } .mb-lg-4 { margin-bottom: 1.5rem !important; } .mb-lg-5 { margin-bottom: 3rem !important; } .mb-lg-auto { margin-bottom: auto !important; } .ms-lg-0 { margin-left: 0 !important; } .ms-lg-1 { margin-left: 0.25rem !important; } .ms-lg-2 { margin-left: 0.5rem !important; } .ms-lg-3 { margin-left: 1rem !important; } .ms-lg-4 { margin-left: 1.5rem !important; } .ms-lg-5 { margin-left: 3rem !important; } .ms-lg-auto { margin-left: auto !important; } .p-lg-0 { padding: 0 !important; } .p-lg-1 { padding: 0.25rem !important; } .p-lg-2 { padding: 0.5rem !important; } .p-lg-3 { padding: 1rem !important; } .p-lg-4 { padding: 1.5rem !important; } .p-lg-5 { padding: 3rem !important; } .px-lg-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-lg-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-lg-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-lg-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-lg-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-lg-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-lg-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-lg-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-lg-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-lg-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-lg-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-lg-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-lg-0 { padding-top: 0 !important; } .pt-lg-1 { padding-top: 0.25rem !important; } .pt-lg-2 { padding-top: 0.5rem !important; } .pt-lg-3 { padding-top: 1rem !important; } .pt-lg-4 { padding-top: 1.5rem !important; } .pt-lg-5 { padding-top: 3rem !important; } .pe-lg-0 { padding-right: 0 !important; } .pe-lg-1 { padding-right: 0.25rem !important; } .pe-lg-2 { padding-right: 0.5rem !important; } .pe-lg-3 { padding-right: 1rem !important; } .pe-lg-4 { padding-right: 1.5rem !important; } .pe-lg-5 { padding-right: 3rem !important; } .pb-lg-0 { padding-bottom: 0 !important; } .pb-lg-1 { padding-bottom: 0.25rem !important; } .pb-lg-2 { padding-bottom: 0.5rem !important; } .pb-lg-3 { padding-bottom: 1rem !important; } .pb-lg-4 { padding-bottom: 1.5rem !important; } .pb-lg-5 { padding-bottom: 3rem !important; } .ps-lg-0 { padding-left: 0 !important; } .ps-lg-1 { padding-left: 0.25rem !important; } .ps-lg-2 { padding-left: 0.5rem !important; } .ps-lg-3 { padding-left: 1rem !important; } .ps-lg-4 { padding-left: 1.5rem !important; } .ps-lg-5 { padding-left: 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: 0.25rem !important; } .gap-xl-2 { gap: 0.5rem !important; } .gap-xl-3 { gap: 1rem !important; } .gap-xl-4 { gap: 1.5rem !important; } .gap-xl-5 { gap: 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: 0.25rem !important; } .m-xl-2 { margin: 0.5rem !important; } .m-xl-3 { margin: 1rem !important; } .m-xl-4 { margin: 1.5rem !important; } .m-xl-5 { margin: 3rem !important; } .m-xl-auto { margin: auto !important; } .mx-xl-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-xl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-xl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-xl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-xl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-xl-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xl-5 { margin-top: 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: 0.25rem !important; } .mt-xl-2 { margin-top: 0.5rem !important; } .mt-xl-3 { margin-top: 1rem !important; } .mt-xl-4 { margin-top: 1.5rem !important; } .mt-xl-5 { margin-top: 3rem !important; } .mt-xl-auto { margin-top: auto !important; } .me-xl-0 { margin-right: 0 !important; } .me-xl-1 { margin-right: 0.25rem !important; } .me-xl-2 { margin-right: 0.5rem !important; } .me-xl-3 { margin-right: 1rem !important; } .me-xl-4 { margin-right: 1.5rem !important; } .me-xl-5 { margin-right: 3rem !important; } .me-xl-auto { margin-right: auto !important; } .mb-xl-0 { margin-bottom: 0 !important; } .mb-xl-1 { margin-bottom: 0.25rem !important; } .mb-xl-2 { margin-bottom: 0.5rem !important; } .mb-xl-3 { margin-bottom: 1rem !important; } .mb-xl-4 { margin-bottom: 1.5rem !important; } .mb-xl-5 { margin-bottom: 3rem !important; } .mb-xl-auto { margin-bottom: auto !important; } .ms-xl-0 { margin-left: 0 !important; } .ms-xl-1 { margin-left: 0.25rem !important; } .ms-xl-2 { margin-left: 0.5rem !important; } .ms-xl-3 { margin-left: 1rem !important; } .ms-xl-4 { margin-left: 1.5rem !important; } .ms-xl-5 { margin-left: 3rem !important; } .ms-xl-auto { margin-left: auto !important; } .p-xl-0 { padding: 0 !important; } .p-xl-1 { padding: 0.25rem !important; } .p-xl-2 { padding: 0.5rem !important; } .p-xl-3 { padding: 1rem !important; } .p-xl-4 { padding: 1.5rem !important; } .p-xl-5 { padding: 3rem !important; } .px-xl-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-xl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-xl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-xl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-xl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-xl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-xl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xl-0 { padding-top: 0 !important; } .pt-xl-1 { padding-top: 0.25rem !important; } .pt-xl-2 { padding-top: 0.5rem !important; } .pt-xl-3 { padding-top: 1rem !important; } .pt-xl-4 { padding-top: 1.5rem !important; } .pt-xl-5 { padding-top: 3rem !important; } .pe-xl-0 { padding-right: 0 !important; } .pe-xl-1 { padding-right: 0.25rem !important; } .pe-xl-2 { padding-right: 0.5rem !important; } .pe-xl-3 { padding-right: 1rem !important; } .pe-xl-4 { padding-right: 1.5rem !important; } .pe-xl-5 { padding-right: 3rem !important; } .pb-xl-0 { padding-bottom: 0 !important; } .pb-xl-1 { padding-bottom: 0.25rem !important; } .pb-xl-2 { padding-bottom: 0.5rem !important; } .pb-xl-3 { padding-bottom: 1rem !important; } .pb-xl-4 { padding-bottom: 1.5rem !important; } .pb-xl-5 { padding-bottom: 3rem !important; } .ps-xl-0 { padding-left: 0 !important; } .ps-xl-1 { padding-left: 0.25rem !important; } .ps-xl-2 { padding-left: 0.5rem !important; } .ps-xl-3 { padding-left: 1rem !important; } .ps-xl-4 { padding-left: 1.5rem !important; } .ps-xl-5 { padding-left: 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: 0.25rem !important; } .gap-xxl-2 { gap: 0.5rem !important; } .gap-xxl-3 { gap: 1rem !important; } .gap-xxl-4 { gap: 1.5rem !important; } .gap-xxl-5 { gap: 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: 0.25rem !important; } .m-xxl-2 { margin: 0.5rem !important; } .m-xxl-3 { margin: 1rem !important; } .m-xxl-4 { margin: 1.5rem !important; } .m-xxl-5 { margin: 3rem !important; } .m-xxl-auto { margin: auto !important; } .mx-xxl-0 { margin-right: 0 !important; margin-left: 0 !important; } .mx-xxl-1 { margin-right: 0.25rem !important; margin-left: 0.25rem !important; } .mx-xxl-2 { margin-right: 0.5rem !important; margin-left: 0.5rem !important; } .mx-xxl-3 { margin-right: 1rem !important; margin-left: 1rem !important; } .mx-xxl-4 { margin-right: 1.5rem !important; margin-left: 1.5rem !important; } .mx-xxl-5 { margin-right: 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: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xxl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xxl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xxl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xxl-5 { margin-top: 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: 0.25rem !important; } .mt-xxl-2 { margin-top: 0.5rem !important; } .mt-xxl-3 { margin-top: 1rem !important; } .mt-xxl-4 { margin-top: 1.5rem !important; } .mt-xxl-5 { margin-top: 3rem !important; } .mt-xxl-auto { margin-top: auto !important; } .me-xxl-0 { margin-right: 0 !important; } .me-xxl-1 { margin-right: 0.25rem !important; } .me-xxl-2 { margin-right: 0.5rem !important; } .me-xxl-3 { margin-right: 1rem !important; } .me-xxl-4 { margin-right: 1.5rem !important; } .me-xxl-5 { margin-right: 3rem !important; } .me-xxl-auto { margin-right: auto !important; } .mb-xxl-0 { margin-bottom: 0 !important; } .mb-xxl-1 { margin-bottom: 0.25rem !important; } .mb-xxl-2 { margin-bottom: 0.5rem !important; } .mb-xxl-3 { margin-bottom: 1rem !important; } .mb-xxl-4 { margin-bottom: 1.5rem !important; } .mb-xxl-5 { margin-bottom: 3rem !important; } .mb-xxl-auto { margin-bottom: auto !important; } .ms-xxl-0 { margin-left: 0 !important; } .ms-xxl-1 { margin-left: 0.25rem !important; } .ms-xxl-2 { margin-left: 0.5rem !important; } .ms-xxl-3 { margin-left: 1rem !important; } .ms-xxl-4 { margin-left: 1.5rem !important; } .ms-xxl-5 { margin-left: 3rem !important; } .ms-xxl-auto { margin-left: auto !important; } .p-xxl-0 { padding: 0 !important; } .p-xxl-1 { padding: 0.25rem !important; } .p-xxl-2 { padding: 0.5rem !important; } .p-xxl-3 { padding: 1rem !important; } .p-xxl-4 { padding: 1.5rem !important; } .p-xxl-5 { padding: 3rem !important; } .px-xxl-0 { padding-right: 0 !important; padding-left: 0 !important; } .px-xxl-1 { padding-right: 0.25rem !important; padding-left: 0.25rem !important; } .px-xxl-2 { padding-right: 0.5rem !important; padding-left: 0.5rem !important; } .px-xxl-3 { padding-right: 1rem !important; padding-left: 1rem !important; } .px-xxl-4 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-xxl-5 { padding-right: 3rem !important; padding-left: 3rem !important; } .py-xxl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xxl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xxl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xxl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xxl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xxl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xxl-0 { padding-top: 0 !important; } .pt-xxl-1 { padding-top: 0.25rem !important; } .pt-xxl-2 { padding-top: 0.5rem !important; } .pt-xxl-3 { padding-top: 1rem !important; } .pt-xxl-4 { padding-top: 1.5rem !important; } .pt-xxl-5 { padding-top: 3rem !important; } .pe-xxl-0 { padding-right: 0 !important; } .pe-xxl-1 { padding-right: 0.25rem !important; } .pe-xxl-2 { padding-right: 0.5rem !important; } .pe-xxl-3 { padding-right: 1rem !important; } .pe-xxl-4 { padding-right: 1.5rem !important; } .pe-xxl-5 { padding-right: 3rem !important; } .pb-xxl-0 { padding-bottom: 0 !important; } .pb-xxl-1 { padding-bottom: 0.25rem !important; } .pb-xxl-2 { padding-bottom: 0.5rem !important; } .pb-xxl-3 { padding-bottom: 1rem !important; } .pb-xxl-4 { padding-bottom: 1.5rem !important; } .pb-xxl-5 { padding-bottom: 3rem !important; } .ps-xxl-0 { padding-left: 0 !important; } .ps-xxl-1 { padding-left: 0.25rem !important; } .ps-xxl-2 { padding-left: 0.5rem !important; } .ps-xxl-3 { padding-left: 1rem !important; } .ps-xxl-4 { padding-left: 1.5rem !important; } .ps-xxl-5 { padding-left: 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.css.map */ ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/css/bootstrap.rtl.css ================================================ @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; } *, *::before, *::after { box-sizing: border-box; } @media (prefers-reduced-motion: no-preference) { :root { scroll-behavior: smooth; } } body { margin: 0; font-family: var(--bs-body-font-family); font-size: var(--bs-body-font-size); font-weight: var(--bs-body-font-weight); line-height: var(--bs-body-line-height); color: var(--bs-body-color); text-align: var(--bs-body-text-align); background-color: var(--bs-body-bg); -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } hr { margin: 1rem 0; color: inherit; background-color: currentColor; border: 0; opacity: 0.25; } hr:not([size]) { height: 1px; } h6, .h6, h5, .h5, h4, .h4, h3, .h3, h2, .h2, h1, .h1 { margin-top: 0; margin-bottom: 0.5rem; font-weight: 500; line-height: 1.2; } 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 + 0.9vw); } @media (min-width: 1200px) { h2, .h2 { font-size: 2rem; } } h3, .h3 { font-size: calc(1.3rem + 0.6vw); } @media (min-width: 1200px) { h3, .h3 { font-size: 1.75rem; } } h4, .h4 { font-size: calc(1.275rem + 0.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[title], abbr[data-bs-original-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-right: 2rem; } ol, ul, dl { margin-top: 0; margin-bottom: 1rem; } ol ol, ul ul, ol ul, ul ol { margin-bottom: 0; } dt { font-weight: 700; } dd { margin-bottom: 0.5rem; margin-right: 0; } blockquote { margin: 0 0 1rem; } b, strong { font-weight: bolder; } small, .small { font-size: 0.875em; } mark, .mark { padding: 0.2em; background-color: #fcf8e3; } sub, sup { position: relative; font-size: 0.75em; line-height: 0; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.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; } pre, code, kbd, 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: 0.875em; } pre code { font-size: inherit; color: inherit; word-break: normal; } code { font-size: 0.875em; color: #d63384; word-wrap: break-word; } a > code { color: inherit; } kbd { padding: 0.2rem 0.4rem; font-size: 0.875em; color: #fff; background-color: #212529; border-radius: 0.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: 0.5rem; padding-bottom: 0.5rem; color: #6c757d; text-align: right; } th { text-align: inherit; text-align: -webkit-match-parent; } thead, tbody, tfoot, tr, td, th { border-color: inherit; border-style: solid; border-width: 0; } label { display: inline-block; } button { border-radius: 0; } button:focus:not(:focus-visible) { outline: 0; } input, button, select, optgroup, textarea { margin: 0; font-family: inherit; font-size: inherit; line-height: inherit; } button, select { text-transform: none; } [role=button] { cursor: pointer; } select { word-wrap: normal; } select:disabled { opacity: 1; } [list]::-webkit-calendar-picker-indicator { display: none; } button, [type=button], [type=reset], [type=submit] { -webkit-appearance: button; } button:not(:disabled), [type=button]:not(:disabled), [type=reset]:not(:disabled), [type=submit]:not(:disabled) { cursor: pointer; } ::-moz-focus-inner { padding: 0; border-style: none; } textarea { resize: vertical; } fieldset { min-width: 0; padding: 0; margin: 0; border: 0; } legend { float: right; width: 100%; padding: 0; margin-bottom: 0.5rem; font-size: calc(1.275rem + 0.3vw); line-height: inherit; } @media (min-width: 1200px) { legend { font-size: 1.5rem; } } legend + * { clear: right; } ::-webkit-datetime-edit-fields-wrapper, ::-webkit-datetime-edit-text, ::-webkit-datetime-edit-minute, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-year-field { padding: 0; } ::-webkit-inner-spin-button { height: auto; } [type=search] { outline-offset: -2px; -webkit-appearance: textfield; } [type="tel"], [type="url"], [type="email"], [type="number"] { direction: ltr; } ::-webkit-search-decoration { -webkit-appearance: none; } ::-webkit-color-swatch-wrapper { padding: 0; } ::file-selector-button { font: inherit; } ::-webkit-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-right: 0; list-style: none; } .list-inline { padding-right: 0; list-style: none; } .list-inline-item { display: inline-block; } .list-inline-item:not(:last-child) { margin-left: 0.5rem; } .initialism { font-size: 0.875em; text-transform: uppercase; } .blockquote { margin-bottom: 1rem; font-size: 1.25rem; } .blockquote > :last-child { margin-bottom: 0; } .blockquote-footer { margin-top: -1rem; margin-bottom: 1rem; font-size: 0.875em; color: #6c757d; } .blockquote-footer::before { content: "— "; } .img-fluid { max-width: 100%; height: auto; } .img-thumbnail { padding: 0.25rem; background-color: #fff; border: 1px solid #dee2e6; border-radius: 0.25rem; max-width: 100%; height: auto; } .figure { display: inline-block; } .figure-img { margin-bottom: 0.5rem; line-height: 1; } .figure-caption { font-size: 0.875em; color: #6c757d; } .container, .container-fluid, .container-xxl, .container-xl, .container-lg, .container-md, .container-sm { width: 100%; padding-left: var(--bs-gutter-x, 0.75rem); padding-right: var(--bs-gutter-x, 0.75rem); margin-left: auto; margin-right: auto; } @media (min-width: 576px) { .container-sm, .container { max-width: 540px; } } @media (min-width: 768px) { .container-md, .container-sm, .container { max-width: 720px; } } @media (min-width: 992px) { .container-lg, .container-md, .container-sm, .container { max-width: 960px; } } @media (min-width: 1200px) { .container-xl, .container-lg, .container-md, .container-sm, .container { max-width: 1140px; } } @media (min-width: 1400px) { .container-xxl, .container-xl, .container-lg, .container-md, .container-sm, .container { 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-left: calc(var(--bs-gutter-x) * -.5); margin-right: calc(var(--bs-gutter-x) * -.5); } .row > * { flex-shrink: 0; width: 100%; max-width: 100%; padding-left: calc(var(--bs-gutter-x) * .5); padding-right: 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-right: 8.33333333%; } .offset-2 { margin-right: 16.66666667%; } .offset-3 { margin-right: 25%; } .offset-4 { margin-right: 33.33333333%; } .offset-5 { margin-right: 41.66666667%; } .offset-6 { margin-right: 50%; } .offset-7 { margin-right: 58.33333333%; } .offset-8 { margin-right: 66.66666667%; } .offset-9 { margin-right: 75%; } .offset-10 { margin-right: 83.33333333%; } .offset-11 { margin-right: 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-right: 0; } .offset-sm-1 { margin-right: 8.33333333%; } .offset-sm-2 { margin-right: 16.66666667%; } .offset-sm-3 { margin-right: 25%; } .offset-sm-4 { margin-right: 33.33333333%; } .offset-sm-5 { margin-right: 41.66666667%; } .offset-sm-6 { margin-right: 50%; } .offset-sm-7 { margin-right: 58.33333333%; } .offset-sm-8 { margin-right: 66.66666667%; } .offset-sm-9 { margin-right: 75%; } .offset-sm-10 { margin-right: 83.33333333%; } .offset-sm-11 { margin-right: 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-right: 0; } .offset-md-1 { margin-right: 8.33333333%; } .offset-md-2 { margin-right: 16.66666667%; } .offset-md-3 { margin-right: 25%; } .offset-md-4 { margin-right: 33.33333333%; } .offset-md-5 { margin-right: 41.66666667%; } .offset-md-6 { margin-right: 50%; } .offset-md-7 { margin-right: 58.33333333%; } .offset-md-8 { margin-right: 66.66666667%; } .offset-md-9 { margin-right: 75%; } .offset-md-10 { margin-right: 83.33333333%; } .offset-md-11 { margin-right: 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-right: 0; } .offset-lg-1 { margin-right: 8.33333333%; } .offset-lg-2 { margin-right: 16.66666667%; } .offset-lg-3 { margin-right: 25%; } .offset-lg-4 { margin-right: 33.33333333%; } .offset-lg-5 { margin-right: 41.66666667%; } .offset-lg-6 { margin-right: 50%; } .offset-lg-7 { margin-right: 58.33333333%; } .offset-lg-8 { margin-right: 66.66666667%; } .offset-lg-9 { margin-right: 75%; } .offset-lg-10 { margin-right: 83.33333333%; } .offset-lg-11 { margin-right: 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-right: 0; } .offset-xl-1 { margin-right: 8.33333333%; } .offset-xl-2 { margin-right: 16.66666667%; } .offset-xl-3 { margin-right: 25%; } .offset-xl-4 { margin-right: 33.33333333%; } .offset-xl-5 { margin-right: 41.66666667%; } .offset-xl-6 { margin-right: 50%; } .offset-xl-7 { margin-right: 58.33333333%; } .offset-xl-8 { margin-right: 66.66666667%; } .offset-xl-9 { margin-right: 75%; } .offset-xl-10 { margin-right: 83.33333333%; } .offset-xl-11 { margin-right: 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-right: 0; } .offset-xxl-1 { margin-right: 8.33333333%; } .offset-xxl-2 { margin-right: 16.66666667%; } .offset-xxl-3 { margin-right: 25%; } .offset-xxl-4 { margin-right: 33.33333333%; } .offset-xxl-5 { margin-right: 41.66666667%; } .offset-xxl-6 { margin-right: 50%; } .offset-xxl-7 { margin-right: 58.33333333%; } .offset-xxl-8 { margin-right: 66.66666667%; } .offset-xxl-9 { margin-right: 75%; } .offset-xxl-10 { margin-right: 83.33333333%; } .offset-xxl-11 { margin-right: 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: 0.5rem 0.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: 0.25rem 0.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: 0.5rem; } .col-form-label { padding-top: calc(0.375rem + 1px); padding-bottom: calc(0.375rem + 1px); margin-bottom: 0; font-size: inherit; line-height: 1.5; } .col-form-label-lg { padding-top: calc(0.5rem + 1px); padding-bottom: calc(0.5rem + 1px); font-size: 1.25rem; } .col-form-label-sm { padding-top: calc(0.25rem + 1px); padding-bottom: calc(0.25rem + 1px); font-size: 0.875rem; } .form-text { margin-top: 0.25rem; font-size: 0.875em; color: #6c757d; } .form-control { display: block; width: 100%; padding: 0.375rem 0.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: 0.25rem; transition: border-color 0.15s ease-in-out, box-shadow 0.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 0.25rem rgba(13, 110, 253, 0.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: 0.375rem 0.75rem; margin: -0.375rem -0.75rem; -webkit-margin-end: 0.75rem; margin-inline-end: 0.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 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .form-control::file-selector-button { transition: none; } } .form-control:hover:not(:disabled):not([readonly])::file-selector-button { background-color: #dde0e3; } .form-control::-webkit-file-upload-button { padding: 0.375rem 0.75rem; margin: -0.375rem -0.75rem; -webkit-margin-end: 0.75rem; margin-inline-end: 0.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 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .form-control::-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: 0.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-sm, .form-control-plaintext.form-control-lg { padding-left: 0; padding-right: 0; } .form-control-sm { min-height: calc(1.5em + 0.5rem + 2px); padding: 0.25rem 0.5rem; font-size: 0.875rem; border-radius: 0.2rem; } .form-control-sm::file-selector-button { padding: 0.25rem 0.5rem; margin: -0.25rem -0.5rem; -webkit-margin-end: 0.5rem; margin-inline-end: 0.5rem; } .form-control-sm::-webkit-file-upload-button { padding: 0.25rem 0.5rem; margin: -0.25rem -0.5rem; -webkit-margin-end: 0.5rem; margin-inline-end: 0.5rem; } .form-control-lg { min-height: calc(1.5em + 1rem + 2px); padding: 0.5rem 1rem; font-size: 1.25rem; border-radius: 0.3rem; } .form-control-lg::file-selector-button { padding: 0.5rem 1rem; margin: -0.5rem -1rem; -webkit-margin-end: 1rem; margin-inline-end: 1rem; } .form-control-lg::-webkit-file-upload-button { padding: 0.5rem 1rem; margin: -0.5rem -1rem; -webkit-margin-end: 1rem; margin-inline-end: 1rem; } textarea.form-control { min-height: calc(1.5em + 0.75rem + 2px); } textarea.form-control-sm { min-height: calc(1.5em + 0.5rem + 2px); } textarea.form-control-lg { min-height: calc(1.5em + 1rem + 2px); } .form-control-color { width: 3rem; height: auto; padding: 0.375rem; } .form-control-color:not(:disabled):not([readonly]) { cursor: pointer; } .form-control-color::-moz-color-swatch { height: 1.5em; border-radius: 0.25rem; } .form-control-color::-webkit-color-swatch { height: 1.5em; border-radius: 0.25rem; } .form-select { display: block; width: 100%; padding: 0.375rem 0.75rem 0.375rem 2.25rem; -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: left 0.75rem center; background-size: 16px 12px; border: 1px solid #ced4da; border-radius: 0.25rem; transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; -webkit-appearance: none; -moz-appearance: none; appearance: none; } @media (prefers-reduced-motion: reduce) { .form-select { transition: none; } } .form-select:focus { border-color: #86b7fe; outline: 0; box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); } .form-select[multiple], .form-select[size]:not([size="1"]) { padding-left: 0.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: 0.25rem; padding-bottom: 0.25rem; padding-right: 0.5rem; font-size: 0.875rem; } .form-select-lg { padding-top: 0.5rem; padding-bottom: 0.5rem; padding-right: 1rem; font-size: 1.25rem; } .form-check { display: block; min-height: 1.5rem; padding-right: 1.5em; margin-bottom: 0.125rem; } .form-check .form-check-input { float: right; margin-right: -1.5em; } .form-check-input { width: 1em; height: 1em; margin-top: 0.25em; vertical-align: top; background-color: #fff; background-repeat: no-repeat; background-position: center; background-size: contain; border: 1px solid rgba(0, 0, 0, 0.25); -webkit-appearance: none; -moz-appearance: none; appearance: none; -webkit-print-color-adjust: exact; color-adjust: exact; } .form-check-input[type=checkbox] { border-radius: 0.25em; } .form-check-input[type=radio] { border-radius: 50%; } .form-check-input:active { filter: brightness(90%); } .form-check-input:focus { border-color: #86b7fe; outline: 0; box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.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: 0.5; } .form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label { opacity: 0.5; } .form-switch { padding-right: 2.5em; } .form-switch .form-check-input { width: 2em; margin-right: -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: right center; border-radius: 2em; transition: background-position 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .form-switch .form-check-input { transition: none; } } .form-switch .form-check-input:focus { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e"); } .form-switch .form-check-input:checked { background-position: left 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-left: 1rem; } .btn-check { position: absolute; clip: rect(0, 0, 0, 0); pointer-events: none; } .btn-check[disabled] + .btn, .btn-check:disabled + .btn { pointer-events: none; filter: none; opacity: 0.65; } .form-range { width: 100%; height: 1.5rem; padding: 0; background-color: transparent; -webkit-appearance: none; -moz-appearance: none; appearance: none; } .form-range:focus { outline: 0; } .form-range:focus::-webkit-slider-thumb { box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25); } .form-range:focus::-moz-range-thumb { box-shadow: 0 0 0 1px #fff, 0 0 0 0.25rem rgba(13, 110, 253, 0.25); } .form-range::-moz-focus-outer { border: 0; } .form-range::-webkit-slider-thumb { width: 1rem; height: 1rem; margin-top: -0.25rem; background-color: #0d6efd; border: 0; border-radius: 1rem; -webkit-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; -webkit-appearance: none; appearance: none; } @media (prefers-reduced-motion: reduce) { .form-range::-webkit-slider-thumb { -webkit-transition: none; transition: none; } } .form-range::-webkit-slider-thumb:active { background-color: #b6d4fe; } .form-range::-webkit-slider-runnable-track { width: 100%; height: 0.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 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; -moz-appearance: none; appearance: none; } @media (prefers-reduced-motion: reduce) { .form-range::-moz-range-thumb { -moz-transition: none; transition: none; } } .form-range::-moz-range-thumb:active { background-color: #b6d4fe; } .form-range::-moz-range-track { width: 100%; height: 0.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; right: 0; height: 100%; padding: 1rem 0.75rem; pointer-events: none; border: 1px solid transparent; transform-origin: 100% 0; transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out; } @media (prefers-reduced-motion: reduce) { .form-floating > label { transition: none; } } .form-floating > .form-control { padding: 1rem 0.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: 0.625rem; } .form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown) { padding-top: 1.625rem; padding-bottom: 0.625rem; } .form-floating > .form-control:-webkit-autofill { padding-top: 1.625rem; padding-bottom: 0.625rem; } .form-floating > .form-select { padding-top: 1.625rem; padding-bottom: 0.625rem; } .form-floating > .form-control:not(:-moz-placeholder-shown) ~ label { opacity: 0.65; transform: scale(0.85) translateY(-0.5rem) translateX(-0.15rem); } .form-floating > .form-control:focus ~ label, .form-floating > .form-control:not(:placeholder-shown) ~ label, .form-floating > .form-select ~ label { opacity: 0.65; transform: scale(0.85) translateY(-0.5rem) translateX(-0.15rem); } .form-floating > .form-control:-webkit-autofill ~ label { opacity: 0.65; transform: scale(0.85) translateY(-0.5rem) translateX(-0.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: 0.375rem 0.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: 0.25rem; } .input-group-lg > .form-control, .input-group-lg > .form-select, .input-group-lg > .input-group-text, .input-group-lg > .btn { padding: 0.5rem 1rem; font-size: 1.25rem; border-radius: 0.3rem; } .input-group-sm > .form-control, .input-group-sm > .form-select, .input-group-sm > .input-group-text, .input-group-sm > .btn { padding: 0.25rem 0.5rem; font-size: 0.875rem; border-radius: 0.2rem; } .input-group-lg > .form-select, .input-group-sm > .form-select { padding-left: 3rem; } .input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu), .input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n+3) { border-top-left-radius: 0; border-bottom-left-radius: 0; } .input-group.has-validation > :nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu), .input-group.has-validation > .dropdown-toggle:nth-last-child(n+4) { border-top-left-radius: 0; border-bottom-left-radius: 0; } .input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) { margin-right: -1px; border-top-right-radius: 0; border-bottom-right-radius: 0; } .valid-feedback { display: none; width: 100%; margin-top: 0.25rem; font-size: 0.875em; color: #198754; } .valid-tooltip { position: absolute; top: 100%; z-index: 5; display: none; max-width: 100%; padding: 0.25rem 0.5rem; margin-top: 0.1rem; font-size: 0.875rem; color: #fff; background-color: rgba(25, 135, 84, 0.9); border-radius: 0.25rem; } .was-validated :valid ~ .valid-feedback, .was-validated :valid ~ .valid-tooltip, .is-valid ~ .valid-feedback, .is-valid ~ .valid-tooltip { display: block; } .was-validated .form-control:valid, .form-control.is-valid { border-color: #198754; padding-left: calc(1.5em + 0.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: left calc(0.375em + 0.1875rem) center; background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } .was-validated .form-control:valid:focus, .form-control.is-valid:focus { border-color: #198754; box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25); } .was-validated textarea.form-control:valid, textarea.form-control.is-valid { padding-left: calc(1.5em + 0.75rem); background-position: top calc(0.375em + 0.1875rem) left calc(0.375em + 0.1875rem); } .was-validated .form-select:valid, .form-select.is-valid { border-color: #198754; } .was-validated .form-select:valid:not([multiple]):not([size]), .was-validated .form-select:valid:not([multiple])[size="1"], .form-select.is-valid:not([multiple]):not([size]), .form-select.is-valid:not([multiple])[size="1"] { padding-left: 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: left 0.75rem center, center left 2.25rem; background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } .was-validated .form-select:valid:focus, .form-select.is-valid:focus { border-color: #198754; box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25); } .was-validated .form-check-input:valid, .form-check-input.is-valid { border-color: #198754; } .was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked { background-color: #198754; } .was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus { box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25); } .was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { color: #198754; } .form-check-inline .form-check-input ~ .valid-feedback { margin-right: 0.5em; } .was-validated .input-group .form-control:valid, .input-group .form-control.is-valid, .was-validated .input-group .form-select:valid, .input-group .form-select.is-valid { z-index: 1; } .was-validated .input-group .form-control:valid:focus, .input-group .form-control.is-valid:focus, .was-validated .input-group .form-select:valid:focus, .input-group .form-select.is-valid:focus { z-index: 3; } .invalid-feedback { display: none; width: 100%; margin-top: 0.25rem; font-size: 0.875em; color: #dc3545; } .invalid-tooltip { position: absolute; top: 100%; z-index: 5; display: none; max-width: 100%; padding: 0.25rem 0.5rem; margin-top: 0.1rem; font-size: 0.875rem; color: #fff; background-color: rgba(220, 53, 69, 0.9); border-radius: 0.25rem; } .was-validated :invalid ~ .invalid-feedback, .was-validated :invalid ~ .invalid-tooltip, .is-invalid ~ .invalid-feedback, .is-invalid ~ .invalid-tooltip { display: block; } .was-validated .form-control:invalid, .form-control.is-invalid { border-color: #dc3545; padding-left: calc(1.5em + 0.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: left calc(0.375em + 0.1875rem) center; background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } .was-validated .form-control:invalid:focus, .form-control.is-invalid:focus { border-color: #dc3545; box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); } .was-validated textarea.form-control:invalid, textarea.form-control.is-invalid { padding-left: calc(1.5em + 0.75rem); background-position: top calc(0.375em + 0.1875rem) left calc(0.375em + 0.1875rem); } .was-validated .form-select:invalid, .form-select.is-invalid { border-color: #dc3545; } .was-validated .form-select:invalid:not([multiple]):not([size]), .was-validated .form-select:invalid:not([multiple])[size="1"], .form-select.is-invalid:not([multiple]):not([size]), .form-select.is-invalid:not([multiple])[size="1"] { padding-left: 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: left 0.75rem center, center left 2.25rem; background-size: 16px 12px, calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); } .was-validated .form-select:invalid:focus, .form-select.is-invalid:focus { border-color: #dc3545; box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); } .was-validated .form-check-input:invalid, .form-check-input.is-invalid { border-color: #dc3545; } .was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked { background-color: #dc3545; } .was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus { box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25); } .was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { color: #dc3545; } .form-check-inline .form-check-input ~ .invalid-feedback { margin-right: 0.5em; } .was-validated .input-group .form-control:invalid, .input-group .form-control.is-invalid, .was-validated .input-group .form-select:invalid, .input-group .form-select.is-invalid { z-index: 2; } .was-validated .input-group .form-control:invalid:focus, .input-group .form-control.is-invalid:focus, .was-validated .input-group .form-select:invalid:focus, .input-group .form-select.is-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: 0.375rem 0.75rem; font-size: 1rem; border-radius: 0.25rem; transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .btn { transition: none; } } .btn:hover { color: #212529; } .btn-check:focus + .btn, .btn:focus { outline: 0; box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); } .btn:disabled, .btn.disabled, fieldset:disabled .btn { pointer-events: none; opacity: 0.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 0.25rem rgba(49, 132, 253, 0.5); } .btn-check:checked + .btn-primary, .btn-check:active + .btn-primary, .btn-primary:active, .btn-primary.active, .show > .btn-primary.dropdown-toggle { color: #fff; background-color: #0a58ca; border-color: #0a53be; } .btn-check:checked + .btn-primary:focus, .btn-check:active + .btn-primary:focus, .btn-primary:active:focus, .btn-primary.active:focus, .show > .btn-primary.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(49, 132, 253, 0.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 0.25rem rgba(130, 138, 145, 0.5); } .btn-check:checked + .btn-secondary, .btn-check:active + .btn-secondary, .btn-secondary:active, .btn-secondary.active, .show > .btn-secondary.dropdown-toggle { color: #fff; background-color: #565e64; border-color: #51585e; } .btn-check:checked + .btn-secondary:focus, .btn-check:active + .btn-secondary:focus, .btn-secondary:active:focus, .btn-secondary.active:focus, .show > .btn-secondary.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(130, 138, 145, 0.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 0.25rem rgba(60, 153, 110, 0.5); } .btn-check:checked + .btn-success, .btn-check:active + .btn-success, .btn-success:active, .btn-success.active, .show > .btn-success.dropdown-toggle { color: #fff; background-color: #146c43; border-color: #13653f; } .btn-check:checked + .btn-success:focus, .btn-check:active + .btn-success:focus, .btn-success:active:focus, .btn-success.active:focus, .show > .btn-success.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(60, 153, 110, 0.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 0.25rem rgba(11, 172, 204, 0.5); } .btn-check:checked + .btn-info, .btn-check:active + .btn-info, .btn-info:active, .btn-info.active, .show > .btn-info.dropdown-toggle { color: #000; background-color: #3dd5f3; border-color: #25cff2; } .btn-check:checked + .btn-info:focus, .btn-check:active + .btn-info:focus, .btn-info:active:focus, .btn-info.active:focus, .show > .btn-info.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(11, 172, 204, 0.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 0.25rem rgba(217, 164, 6, 0.5); } .btn-check:checked + .btn-warning, .btn-check:active + .btn-warning, .btn-warning:active, .btn-warning.active, .show > .btn-warning.dropdown-toggle { color: #000; background-color: #ffcd39; border-color: #ffc720; } .btn-check:checked + .btn-warning:focus, .btn-check:active + .btn-warning:focus, .btn-warning:active:focus, .btn-warning.active:focus, .show > .btn-warning.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(217, 164, 6, 0.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 0.25rem rgba(225, 83, 97, 0.5); } .btn-check:checked + .btn-danger, .btn-check:active + .btn-danger, .btn-danger:active, .btn-danger.active, .show > .btn-danger.dropdown-toggle { color: #fff; background-color: #b02a37; border-color: #a52834; } .btn-check:checked + .btn-danger:focus, .btn-check:active + .btn-danger:focus, .btn-danger:active:focus, .btn-danger.active:focus, .show > .btn-danger.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(225, 83, 97, 0.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 0.25rem rgba(211, 212, 213, 0.5); } .btn-check:checked + .btn-light, .btn-check:active + .btn-light, .btn-light:active, .btn-light.active, .show > .btn-light.dropdown-toggle { color: #000; background-color: #f9fafb; border-color: #f9fafb; } .btn-check:checked + .btn-light:focus, .btn-check:active + .btn-light:focus, .btn-light:active:focus, .btn-light.active:focus, .show > .btn-light.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(211, 212, 213, 0.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 0.25rem rgba(66, 70, 73, 0.5); } .btn-check:checked + .btn-dark, .btn-check:active + .btn-dark, .btn-dark:active, .btn-dark.active, .show > .btn-dark.dropdown-toggle { color: #fff; background-color: #1a1e21; border-color: #191c1f; } .btn-check:checked + .btn-dark:focus, .btn-check:active + .btn-dark:focus, .btn-dark:active:focus, .btn-dark.active:focus, .show > .btn-dark.dropdown-toggle:focus { box-shadow: 0 0 0 0.25rem rgba(66, 70, 73, 0.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 0.25rem rgba(13, 110, 253, 0.5); } .btn-check:checked + .btn-outline-primary, .btn-check:active + .btn-outline-primary, .btn-outline-primary:active, .btn-outline-primary.active, .btn-outline-primary.dropdown-toggle.show { color: #fff; background-color: #0d6efd; border-color: #0d6efd; } .btn-check:checked + .btn-outline-primary:focus, .btn-check:active + .btn-outline-primary:focus, .btn-outline-primary:active:focus, .btn-outline-primary.active:focus, .btn-outline-primary.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.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 0.25rem rgba(108, 117, 125, 0.5); } .btn-check:checked + .btn-outline-secondary, .btn-check:active + .btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show { color: #fff; background-color: #6c757d; border-color: #6c757d; } .btn-check:checked + .btn-outline-secondary:focus, .btn-check:active + .btn-outline-secondary:focus, .btn-outline-secondary:active:focus, .btn-outline-secondary.active:focus, .btn-outline-secondary.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(108, 117, 125, 0.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 0.25rem rgba(25, 135, 84, 0.5); } .btn-check:checked + .btn-outline-success, .btn-check:active + .btn-outline-success, .btn-outline-success:active, .btn-outline-success.active, .btn-outline-success.dropdown-toggle.show { color: #fff; background-color: #198754; border-color: #198754; } .btn-check:checked + .btn-outline-success:focus, .btn-check:active + .btn-outline-success:focus, .btn-outline-success:active:focus, .btn-outline-success.active:focus, .btn-outline-success.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.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 0.25rem rgba(13, 202, 240, 0.5); } .btn-check:checked + .btn-outline-info, .btn-check:active + .btn-outline-info, .btn-outline-info:active, .btn-outline-info.active, .btn-outline-info.dropdown-toggle.show { color: #000; background-color: #0dcaf0; border-color: #0dcaf0; } .btn-check:checked + .btn-outline-info:focus, .btn-check:active + .btn-outline-info:focus, .btn-outline-info:active:focus, .btn-outline-info.active:focus, .btn-outline-info.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(13, 202, 240, 0.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 0.25rem rgba(255, 193, 7, 0.5); } .btn-check:checked + .btn-outline-warning, .btn-check:active + .btn-outline-warning, .btn-outline-warning:active, .btn-outline-warning.active, .btn-outline-warning.dropdown-toggle.show { color: #000; background-color: #ffc107; border-color: #ffc107; } .btn-check:checked + .btn-outline-warning:focus, .btn-check:active + .btn-outline-warning:focus, .btn-outline-warning:active:focus, .btn-outline-warning.active:focus, .btn-outline-warning.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(255, 193, 7, 0.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 0.25rem rgba(220, 53, 69, 0.5); } .btn-check:checked + .btn-outline-danger, .btn-check:active + .btn-outline-danger, .btn-outline-danger:active, .btn-outline-danger.active, .btn-outline-danger.dropdown-toggle.show { color: #fff; background-color: #dc3545; border-color: #dc3545; } .btn-check:checked + .btn-outline-danger:focus, .btn-check:active + .btn-outline-danger:focus, .btn-outline-danger:active:focus, .btn-outline-danger.active:focus, .btn-outline-danger.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.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 0.25rem rgba(248, 249, 250, 0.5); } .btn-check:checked + .btn-outline-light, .btn-check:active + .btn-outline-light, .btn-outline-light:active, .btn-outline-light.active, .btn-outline-light.dropdown-toggle.show { color: #000; background-color: #f8f9fa; border-color: #f8f9fa; } .btn-check:checked + .btn-outline-light:focus, .btn-check:active + .btn-outline-light:focus, .btn-outline-light:active:focus, .btn-outline-light.active:focus, .btn-outline-light.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(248, 249, 250, 0.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 0.25rem rgba(33, 37, 41, 0.5); } .btn-check:checked + .btn-outline-dark, .btn-check:active + .btn-outline-dark, .btn-outline-dark:active, .btn-outline-dark.active, .btn-outline-dark.dropdown-toggle.show { color: #fff; background-color: #212529; border-color: #212529; } .btn-check:checked + .btn-outline-dark:focus, .btn-check:active + .btn-outline-dark:focus, .btn-outline-dark:active:focus, .btn-outline-dark.active:focus, .btn-outline-dark.dropdown-toggle.show:focus { box-shadow: 0 0 0 0.25rem rgba(33, 37, 41, 0.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-lg, .btn-group-lg > .btn { padding: 0.5rem 1rem; font-size: 1.25rem; border-radius: 0.3rem; } .btn-sm, .btn-group-sm > .btn { padding: 0.25rem 0.5rem; font-size: 0.875rem; border-radius: 0.2rem; } .fade { transition: opacity 0.15s linear; } @media (prefers-reduced-motion: reduce) { .fade { transition: none; } } .fade:not(.show) { opacity: 0; } .collapse:not(.show) { display: none; } .collapsing { height: 0; overflow: hidden; transition: height 0.35s ease; } @media (prefers-reduced-motion: reduce) { .collapsing { transition: none; } } .collapsing.collapse-horizontal { width: 0; height: auto; transition: width 0.35s ease; } @media (prefers-reduced-motion: reduce) { .collapsing.collapse-horizontal { transition: none; } } .dropup, .dropend, .dropdown, .dropstart { position: relative; } .dropdown-toggle { white-space: nowrap; } .dropdown-toggle::after { display: inline-block; margin-right: 0.255em; vertical-align: 0.255em; content: ""; border-top: 0.3em solid; border-left: 0.3em solid transparent; border-bottom: 0; border-right: 0.3em solid transparent; } .dropdown-toggle:empty::after { margin-right: 0; } .dropdown-menu { position: absolute; z-index: 1000; display: none; min-width: 10rem; padding: 0.5rem 0; margin: 0; font-size: 1rem; color: #212529; text-align: right; list-style: none; background-color: #fff; background-clip: padding-box; border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 0.25rem; } .dropdown-menu[data-bs-popper] { top: 100%; right: 0; margin-top: 0.125rem; } .dropdown-menu-start { --bs-position: start; } .dropdown-menu-start[data-bs-popper] { left: auto; right: 0; } .dropdown-menu-end { --bs-position: end; } .dropdown-menu-end[data-bs-popper] { left: 0; right: auto; } @media (min-width: 576px) { .dropdown-menu-sm-start { --bs-position: start; } .dropdown-menu-sm-start[data-bs-popper] { left: auto; right: 0; } .dropdown-menu-sm-end { --bs-position: end; } .dropdown-menu-sm-end[data-bs-popper] { left: 0; right: auto; } } @media (min-width: 768px) { .dropdown-menu-md-start { --bs-position: start; } .dropdown-menu-md-start[data-bs-popper] { left: auto; right: 0; } .dropdown-menu-md-end { --bs-position: end; } .dropdown-menu-md-end[data-bs-popper] { left: 0; right: auto; } } @media (min-width: 992px) { .dropdown-menu-lg-start { --bs-position: start; } .dropdown-menu-lg-start[data-bs-popper] { left: auto; right: 0; } .dropdown-menu-lg-end { --bs-position: end; } .dropdown-menu-lg-end[data-bs-popper] { left: 0; right: auto; } } @media (min-width: 1200px) { .dropdown-menu-xl-start { --bs-position: start; } .dropdown-menu-xl-start[data-bs-popper] { left: auto; right: 0; } .dropdown-menu-xl-end { --bs-position: end; } .dropdown-menu-xl-end[data-bs-popper] { left: 0; right: auto; } } @media (min-width: 1400px) { .dropdown-menu-xxl-start { --bs-position: start; } .dropdown-menu-xxl-start[data-bs-popper] { left: auto; right: 0; } .dropdown-menu-xxl-end { --bs-position: end; } .dropdown-menu-xxl-end[data-bs-popper] { left: 0; right: auto; } } .dropup .dropdown-menu[data-bs-popper] { top: auto; bottom: 100%; margin-top: 0; margin-bottom: 0.125rem; } .dropup .dropdown-toggle::after { display: inline-block; margin-right: 0.255em; vertical-align: 0.255em; content: ""; border-top: 0; border-left: 0.3em solid transparent; border-bottom: 0.3em solid; border-right: 0.3em solid transparent; } .dropup .dropdown-toggle:empty::after { margin-right: 0; } .dropend .dropdown-menu[data-bs-popper] { top: 0; left: auto; right: 100%; margin-top: 0; margin-right: 0.125rem; } .dropend .dropdown-toggle::after { display: inline-block; margin-right: 0.255em; vertical-align: 0.255em; content: ""; border-top: 0.3em solid transparent; border-left: 0; border-bottom: 0.3em solid transparent; border-right: 0.3em solid; } .dropend .dropdown-toggle:empty::after { margin-right: 0; } .dropend .dropdown-toggle::after { vertical-align: 0; } .dropstart .dropdown-menu[data-bs-popper] { top: 0; left: 100%; right: auto; margin-top: 0; margin-left: 0.125rem; } .dropstart .dropdown-toggle::after { display: inline-block; margin-right: 0.255em; vertical-align: 0.255em; content: ""; } .dropstart .dropdown-toggle::after { display: none; } .dropstart .dropdown-toggle::before { display: inline-block; margin-left: 0.255em; vertical-align: 0.255em; content: ""; border-top: 0.3em solid transparent; border-left: 0.3em solid; border-bottom: 0.3em solid transparent; } .dropstart .dropdown-toggle:empty::after { margin-right: 0; } .dropstart .dropdown-toggle::before { vertical-align: 0; } .dropdown-divider { height: 0; margin: 0.5rem 0; overflow: hidden; border-top: 1px solid rgba(0, 0, 0, 0.15); } .dropdown-item { display: block; width: 100%; padding: 0.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:hover, .dropdown-item:focus { 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: 0.5rem 1rem; margin-bottom: 0; font-size: 0.875rem; color: #6c757d; white-space: nowrap; } .dropdown-item-text { display: block; padding: 0.25rem 1rem; color: #212529; } .dropdown-menu-dark { color: #dee2e6; background-color: #343a40; border-color: rgba(0, 0, 0, 0.15); } .dropdown-menu-dark .dropdown-item { color: #dee2e6; } .dropdown-menu-dark .dropdown-item:hover, .dropdown-menu-dark .dropdown-item:focus { color: #fff; background-color: rgba(255, 255, 255, 0.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, 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 > .btn, .btn-group-vertical > .btn { position: relative; flex: 1 1 auto; } .btn-group > .btn-check:checked + .btn, .btn-group > .btn-check:focus + .btn, .btn-group > .btn:hover, .btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active, .btn-group-vertical > .btn-check:checked + .btn, .btn-group-vertical > .btn-check:focus + .btn, .btn-group-vertical > .btn:hover, .btn-group-vertical > .btn:focus, .btn-group-vertical > .btn:active, .btn-group-vertical > .btn.active { z-index: 1; } .btn-toolbar { display: flex; flex-wrap: wrap; justify-content: flex-start; } .btn-toolbar .input-group { width: auto; } .btn-group > .btn:not(:first-child), .btn-group > .btn-group:not(:first-child) { margin-right: -1px; } .btn-group > .btn:not(:last-child):not(.dropdown-toggle), .btn-group > .btn-group:not(:last-child) > .btn { border-top-left-radius: 0; border-bottom-left-radius: 0; } .btn-group > .btn:nth-child(n+3), .btn-group > :not(.btn-check) + .btn, .btn-group > .btn-group:not(:first-child) > .btn { border-top-right-radius: 0; border-bottom-right-radius: 0; } .dropdown-toggle-split { padding-left: 0.5625rem; padding-right: 0.5625rem; } .dropdown-toggle-split::after, .dropup .dropdown-toggle-split::after, .dropend .dropdown-toggle-split::after { margin-right: 0; } .dropstart .dropdown-toggle-split::before { margin-left: 0; } .btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { padding-left: 0.375rem; padding-right: 0.375rem; } .btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { padding-left: 0.75rem; padding-right: 0.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:not(:first-child), .btn-group-vertical > .btn-group:not(:first-child) { margin-top: -1px; } .btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), .btn-group-vertical > .btn-group:not(:last-child) > .btn { border-bottom-left-radius: 0; border-bottom-right-radius: 0; } .btn-group-vertical > .btn ~ .btn, .btn-group-vertical > .btn-group:not(:first-child) > .btn { border-top-right-radius: 0; border-top-left-radius: 0; } .nav { display: flex; flex-wrap: wrap; padding-right: 0; margin-bottom: 0; list-style: none; } .nav-link { display: block; padding: 0.5rem 1rem; color: #0d6efd; text-decoration: none; transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .nav-link { transition: none; } } .nav-link:hover, .nav-link:focus { color: #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: none; border: 1px solid transparent; border-top-right-radius: 0.25rem; border-top-left-radius: 0.25rem; } .nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { border-color: #e9ecef #e9ecef #dee2e6; isolation: isolate; } .nav-tabs .nav-link.disabled { color: #6c757d; background-color: transparent; border-color: transparent; } .nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link { color: #495057; background-color: #fff; border-color: #dee2e6 #dee2e6 #fff; } .nav-tabs .dropdown-menu { margin-top: -1px; border-top-right-radius: 0; border-top-left-radius: 0; } .nav-pills .nav-link { background: none; border: 0; border-radius: 0.25rem; } .nav-pills .nav-link.active, .nav-pills .show > .nav-link { color: #fff; background-color: #0d6efd; } .nav-fill > .nav-link, .nav-fill .nav-item { flex: 1 1 auto; text-align: center; } .nav-justified > .nav-link, .nav-justified .nav-item { flex-basis: 0; flex-grow: 1; text-align: center; } .nav-fill .nav-item .nav-link, .nav-justified .nav-item .nav-link { width: 100%; } .tab-content > .tab-pane { display: none; } .tab-content > .active { display: block; } .navbar { position: relative; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; padding-top: 0.5rem; padding-bottom: 0.5rem; } .navbar > .container, .navbar > .container-fluid, .navbar > .container-sm, .navbar > .container-md, .navbar > .container-lg, .navbar > .container-xl, .navbar > .container-xxl { display: flex; flex-wrap: inherit; align-items: center; justify-content: space-between; } .navbar-brand { padding-top: 0.3125rem; padding-bottom: 0.3125rem; margin-left: 1rem; font-size: 1.25rem; text-decoration: none; white-space: nowrap; } .navbar-nav { display: flex; flex-direction: column; padding-right: 0; margin-bottom: 0; list-style: none; } .navbar-nav .nav-link { padding-left: 0; padding-right: 0; } .navbar-nav .dropdown-menu { position: static; } .navbar-text { padding-top: 0.5rem; padding-bottom: 0.5rem; } .navbar-collapse { flex-basis: 100%; flex-grow: 1; align-items: center; } .navbar-toggler { padding: 0.25rem 0.75rem; font-size: 1.25rem; line-height: 1; background-color: transparent; border: 1px solid transparent; border-radius: 0.25rem; transition: box-shadow 0.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 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-left: 0.5rem; padding-right: 0.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-left: 0; border-right: 0; transition: none; transform: none; } .navbar-expand-sm .offcanvas-top, .navbar-expand-sm .offcanvas-bottom { 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-left: 0.5rem; padding-right: 0.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-left: 0; border-right: 0; transition: none; transform: none; } .navbar-expand-md .offcanvas-top, .navbar-expand-md .offcanvas-bottom { 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-left: 0.5rem; padding-right: 0.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-left: 0; border-right: 0; transition: none; transform: none; } .navbar-expand-lg .offcanvas-top, .navbar-expand-lg .offcanvas-bottom { 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-left: 0.5rem; padding-right: 0.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-left: 0; border-right: 0; transition: none; transform: none; } .navbar-expand-xl .offcanvas-top, .navbar-expand-xl .offcanvas-bottom { 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-left: 0.5rem; padding-right: 0.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-left: 0; border-right: 0; transition: none; transform: none; } .navbar-expand-xxl .offcanvas-top, .navbar-expand-xxl .offcanvas-bottom { 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-left: 0.5rem; padding-right: 0.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-left: 0; border-right: 0; transition: none; transform: none; } .navbar-expand .offcanvas-top, .navbar-expand .offcanvas-bottom { 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, 0.9); } .navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus { color: rgba(0, 0, 0, 0.9); } .navbar-light .navbar-nav .nav-link { color: rgba(0, 0, 0, 0.55); } .navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus { color: rgba(0, 0, 0, 0.7); } .navbar-light .navbar-nav .nav-link.disabled { color: rgba(0, 0, 0, 0.3); } .navbar-light .navbar-nav .show > .nav-link, .navbar-light .navbar-nav .nav-link.active { color: rgba(0, 0, 0, 0.9); } .navbar-light .navbar-toggler { color: rgba(0, 0, 0, 0.55); border-color: rgba(0, 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, 0.55); } .navbar-light .navbar-text a, .navbar-light .navbar-text a:hover, .navbar-light .navbar-text a:focus { color: rgba(0, 0, 0, 0.9); } .navbar-dark .navbar-brand { color: #fff; } .navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus { color: #fff; } .navbar-dark .navbar-nav .nav-link { color: rgba(255, 255, 255, 0.55); } .navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus { color: rgba(255, 255, 255, 0.75); } .navbar-dark .navbar-nav .nav-link.disabled { color: rgba(255, 255, 255, 0.25); } .navbar-dark .navbar-nav .show > .nav-link, .navbar-dark .navbar-nav .nav-link.active { color: #fff; } .navbar-dark .navbar-toggler { color: rgba(255, 255, 255, 0.55); border-color: rgba(255, 255, 255, 0.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, 0.55); } .navbar-dark .navbar-text a, .navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus { 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, 0.125); border-radius: 0.25rem; } .card > hr { margin-left: 0; margin-right: 0; } .card > .list-group { border-top: inherit; border-bottom: inherit; } .card > .list-group:first-child { border-top-width: 0; border-top-right-radius: calc(0.25rem - 1px); border-top-left-radius: calc(0.25rem - 1px); } .card > .list-group:last-child { border-bottom-width: 0; border-bottom-left-radius: calc(0.25rem - 1px); border-bottom-right-radius: calc(0.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: 0.5rem; } .card-subtitle { margin-top: -0.25rem; margin-bottom: 0; } .card-text:last-child { margin-bottom: 0; } .card-link + .card-link { margin-right: 1rem; } .card-header { padding: 0.5rem 1rem; margin-bottom: 0; background-color: rgba(0, 0, 0, 0.03); border-bottom: 1px solid rgba(0, 0, 0, 0.125); } .card-header:first-child { border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0; } .card-footer { padding: 0.5rem 1rem; background-color: rgba(0, 0, 0, 0.03); border-top: 1px solid rgba(0, 0, 0, 0.125); } .card-footer:last-child { border-radius: 0 0 calc(0.25rem - 1px) calc(0.25rem - 1px); } .card-header-tabs { margin-left: -0.5rem; margin-bottom: -0.5rem; margin-right: -0.5rem; border-bottom: 0; } .card-header-pills { margin-left: -0.5rem; margin-right: -0.5rem; } .card-img-overlay { position: absolute; top: 0; left: 0; bottom: 0; right: 0; padding: 1rem; border-radius: calc(0.25rem - 1px); } .card-img, .card-img-top, .card-img-bottom { width: 100%; } .card-img, .card-img-top { border-top-right-radius: calc(0.25rem - 1px); border-top-left-radius: calc(0.25rem - 1px); } .card-img, .card-img-bottom { border-bottom-left-radius: calc(0.25rem - 1px); border-bottom-right-radius: calc(0.25rem - 1px); } .card-group > .card { margin-bottom: 0.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-right: 0; border-right: 0; } .card-group > .card:not(:last-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; } .card-group > .card:not(:last-child) .card-img-top, .card-group > .card:not(:last-child) .card-header { border-top-left-radius: 0; } .card-group > .card:not(:last-child) .card-img-bottom, .card-group > .card:not(:last-child) .card-footer { border-bottom-left-radius: 0; } .card-group > .card:not(:first-child) { border-top-right-radius: 0; border-bottom-right-radius: 0; } .card-group > .card:not(:first-child) .card-img-top, .card-group > .card:not(:first-child) .card-header { border-top-right-radius: 0; } .card-group > .card:not(:first-child) .card-img-bottom, .card-group > .card:not(:first-child) .card-footer { border-bottom-right-radius: 0; } } .accordion-button { position: relative; display: flex; align-items: center; width: 100%; padding: 1rem 1.25rem; font-size: 1rem; color: #212529; text-align: right; background-color: #fff; border: 0; border-radius: 0; overflow-anchor: none; transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease; } @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, 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-right: 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 0.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 0.25rem rgba(13, 110, 253, 0.25); } .accordion-header { margin-bottom: 0; } .accordion-item { background-color: #fff; border: 1px solid rgba(0, 0, 0, 0.125); } .accordion-item:first-of-type { border-top-right-radius: 0.25rem; border-top-left-radius: 0.25rem; } .accordion-item:first-of-type .accordion-button { border-top-right-radius: calc(0.25rem - 1px); border-top-left-radius: calc(0.25rem - 1px); } .accordion-item:not(:first-of-type) { border-top: 0; } .accordion-item:last-of-type { border-bottom-left-radius: 0.25rem; border-bottom-right-radius: 0.25rem; } .accordion-item:last-of-type .accordion-button.collapsed { border-bottom-left-radius: calc(0.25rem - 1px); border-bottom-right-radius: calc(0.25rem - 1px); } .accordion-item:last-of-type .accordion-collapse { border-bottom-left-radius: 0.25rem; border-bottom-right-radius: 0.25rem; } .accordion-body { padding: 1rem 1.25rem; } .accordion-flush .accordion-collapse { border-width: 0; } .accordion-flush .accordion-item { border-left: 0; border-right: 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-right: 0.5rem; } .breadcrumb-item + .breadcrumb-item::before { float: right; padding-left: 0.5rem; color: #6c757d; content: var(--bs-breadcrumb-divider, "/") ; } .breadcrumb-item.active { color: #6c757d; } .pagination { display: flex; padding-right: 0; list-style: none; } .page-link { position: relative; display: block; color: #0d6efd; text-decoration: none; background-color: #fff; border: 1px solid #dee2e6; transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } @media (prefers-reduced-motion: reduce) { .page-link { 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 0.25rem rgba(13, 110, 253, 0.25); } .page-item:not(:first-child) .page-link { margin-right: -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: 0.375rem 0.75rem; } .page-item:first-child .page-link { border-top-right-radius: 0.25rem; border-bottom-right-radius: 0.25rem; } .page-item:last-child .page-link { border-top-left-radius: 0.25rem; border-bottom-left-radius: 0.25rem; } .pagination-lg .page-link { padding: 0.75rem 1.5rem; font-size: 1.25rem; } .pagination-lg .page-item:first-child .page-link { border-top-right-radius: 0.3rem; border-bottom-right-radius: 0.3rem; } .pagination-lg .page-item:last-child .page-link { border-top-left-radius: 0.3rem; border-bottom-left-radius: 0.3rem; } .pagination-sm .page-link { padding: 0.25rem 0.5rem; font-size: 0.875rem; } .pagination-sm .page-item:first-child .page-link { border-top-right-radius: 0.2rem; border-bottom-right-radius: 0.2rem; } .pagination-sm .page-item:last-child .page-link { border-top-left-radius: 0.2rem; border-bottom-left-radius: 0.2rem; } .badge { display: inline-block; padding: 0.35em 0.65em; font-size: 0.75em; font-weight: 700; line-height: 1; color: #fff; text-align: center; white-space: nowrap; vertical-align: baseline; border-radius: 0.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: 0.25rem; } .alert-heading { color: inherit; } .alert-link { font-weight: 700; } .alert-dismissible { padding-left: 3rem; } .alert-dismissible .btn-close { position: absolute; top: 0; left: 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: 0.75rem; background-color: #e9ecef; border-radius: 0.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 0.6s ease; } @media (prefers-reduced-motion: reduce) { .progress-bar { transition: none; } } .progress-bar-striped { background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-size: 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-right: 0; margin-bottom: 0; border-radius: 0.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:hover, .list-group-item-action:focus { 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: 0.5rem 1rem; color: #212529; text-decoration: none; background-color: #fff; border: 1px solid rgba(0, 0, 0, 0.125); } .list-group-item:first-child { border-top-right-radius: inherit; border-top-left-radius: inherit; } .list-group-item:last-child { border-bottom-left-radius: inherit; border-bottom-right-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-right-radius: 0.25rem; border-top-left-radius: 0; } .list-group-horizontal > .list-group-item:last-child { border-top-left-radius: 0.25rem; border-bottom-right-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-right-width: 0; } .list-group-horizontal > .list-group-item + .list-group-item.active { margin-right: -1px; border-right-width: 1px; } @media (min-width: 576px) { .list-group-horizontal-sm { flex-direction: row; } .list-group-horizontal-sm > .list-group-item:first-child { border-bottom-right-radius: 0.25rem; border-top-left-radius: 0; } .list-group-horizontal-sm > .list-group-item:last-child { border-top-left-radius: 0.25rem; border-bottom-right-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-right-width: 0; } .list-group-horizontal-sm > .list-group-item + .list-group-item.active { margin-right: -1px; border-right-width: 1px; } } @media (min-width: 768px) { .list-group-horizontal-md { flex-direction: row; } .list-group-horizontal-md > .list-group-item:first-child { border-bottom-right-radius: 0.25rem; border-top-left-radius: 0; } .list-group-horizontal-md > .list-group-item:last-child { border-top-left-radius: 0.25rem; border-bottom-right-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-right-width: 0; } .list-group-horizontal-md > .list-group-item + .list-group-item.active { margin-right: -1px; border-right-width: 1px; } } @media (min-width: 992px) { .list-group-horizontal-lg { flex-direction: row; } .list-group-horizontal-lg > .list-group-item:first-child { border-bottom-right-radius: 0.25rem; border-top-left-radius: 0; } .list-group-horizontal-lg > .list-group-item:last-child { border-top-left-radius: 0.25rem; border-bottom-right-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-right-width: 0; } .list-group-horizontal-lg > .list-group-item + .list-group-item.active { margin-right: -1px; border-right-width: 1px; } } @media (min-width: 1200px) { .list-group-horizontal-xl { flex-direction: row; } .list-group-horizontal-xl > .list-group-item:first-child { border-bottom-right-radius: 0.25rem; border-top-left-radius: 0; } .list-group-horizontal-xl > .list-group-item:last-child { border-top-left-radius: 0.25rem; border-bottom-right-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-right-width: 0; } .list-group-horizontal-xl > .list-group-item + .list-group-item.active { margin-right: -1px; border-right-width: 1px; } } @media (min-width: 1400px) { .list-group-horizontal-xxl { flex-direction: row; } .list-group-horizontal-xxl > .list-group-item:first-child { border-bottom-right-radius: 0.25rem; border-top-left-radius: 0; } .list-group-horizontal-xxl > .list-group-item:last-child { border-top-left-radius: 0.25rem; border-bottom-right-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-right-width: 0; } .list-group-horizontal-xxl > .list-group-item + .list-group-item.active { margin-right: -1px; border-right-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:hover, .list-group-item-primary.list-group-item-action:focus { 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:hover, .list-group-item-secondary.list-group-item-action:focus { 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:hover, .list-group-item-success.list-group-item-action:focus { 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:hover, .list-group-item-info.list-group-item-action:focus { 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:hover, .list-group-item-warning.list-group-item-action:focus { 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:hover, .list-group-item-danger.list-group-item-action:focus { 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:hover, .list-group-item-light.list-group-item-action:focus { 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:hover, .list-group-item-dark.list-group-item-action:focus { 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: 0.25em 0.25em; color: #000; background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 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: 0.25rem; opacity: 0.5; } .btn-close:hover { color: #000; text-decoration: none; opacity: 0.75; } .btn-close:focus { outline: 0; box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); opacity: 1; } .btn-close:disabled, .btn-close.disabled { pointer-events: none; -webkit-user-select: none; -moz-user-select: none; user-select: none; opacity: 0.25; } .btn-close-white { filter: invert(1) grayscale(100%) brightness(200%); } .toast { width: 350px; max-width: 100%; font-size: 0.875rem; pointer-events: auto; background-color: rgba(255, 255, 255, 0.85); background-clip: padding-box; border: 1px solid rgba(0, 0, 0, 0.1); box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); border-radius: 0.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: 0.75rem; } .toast-header { display: flex; align-items: center; padding: 0.5rem 0.75rem; color: #6c757d; background-color: rgba(255, 255, 255, 0.85); background-clip: padding-box; border-bottom: 1px solid rgba(0, 0, 0, 0.05); border-top-right-radius: calc(0.25rem - 1px); border-top-left-radius: calc(0.25rem - 1px); } .toast-header .btn-close { margin-left: -0.375rem; margin-right: 0.75rem; } .toast-body { padding: 0.75rem; word-wrap: break-word; } .modal { position: fixed; top: 0; right: 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: 0.5rem; pointer-events: none; } .modal.fade .modal-dialog { transition: transform 0.3s ease-out; transform: translate(0, -50px); } @media (prefers-reduced-motion: reduce) { .modal.fade .modal-dialog { transition: none; } } .modal.show .modal-dialog { transform: none; } .modal.modal-static .modal-dialog { transform: scale(1.02); } .modal-dialog-scrollable { height: calc(100% - 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, 0.2); border-radius: 0.3rem; outline: 0; } .modal-backdrop { position: fixed; top: 0; right: 0; z-index: 1050; width: 100vw; height: 100vh; background-color: #000; } .modal-backdrop.fade { opacity: 0; } .modal-backdrop.show { opacity: 0.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-right-radius: calc(0.3rem - 1px); border-top-left-radius: calc(0.3rem - 1px); } .modal-header .btn-close { padding: 0.5rem 0.5rem; margin: -0.5rem auto -0.5rem -0.5rem; } .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: 0.75rem; border-top: 1px solid #dee2e6; border-bottom-left-radius: calc(0.3rem - 1px); border-bottom-right-radius: calc(0.3rem - 1px); } .modal-footer > * { margin: 0.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: right; 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: 0.875rem; word-wrap: break-word; opacity: 0; } .tooltip.show { opacity: 0.9; } .tooltip .tooltip-arrow { position: absolute; display: block; width: 0.8rem; height: 0.4rem; } .tooltip .tooltip-arrow::before { position: absolute; content: ""; border-color: transparent; border-style: solid; } .bs-tooltip-top, .bs-tooltip-auto[data-popper-placement^=top] { padding: 0.4rem 0; } .bs-tooltip-top .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow { bottom: 0; } .bs-tooltip-top .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before { top: -1px; border-width: 0.4rem 0.4rem 0; border-top-color: #000; } .bs-tooltip-end, .bs-tooltip-auto[data-popper-placement^=right] { padding: 0 0.4rem; } .bs-tooltip-end .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow { right: 0; width: 0.4rem; height: 0.8rem; } .bs-tooltip-end .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before { left: -1px; border-width: 0.4rem 0 0.4rem 0.4rem; border-left-color: #000; } .bs-tooltip-bottom, .bs-tooltip-auto[data-popper-placement^=bottom] { padding: 0.4rem 0; } .bs-tooltip-bottom .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow { top: 0; } .bs-tooltip-bottom .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before { bottom: -1px; border-width: 0 0.4rem 0.4rem; border-bottom-color: #000; } .bs-tooltip-start, .bs-tooltip-auto[data-popper-placement^=left] { padding: 0 0.4rem; } .bs-tooltip-start .tooltip-arrow, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow { left: 0; width: 0.4rem; height: 0.8rem; } .bs-tooltip-start .tooltip-arrow::before, .bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before { right: -1px; border-width: 0.4rem 0.4rem 0.4rem 0; border-right-color: #000; } .tooltip-inner { max-width: 200px; padding: 0.25rem 0.5rem; color: #fff; text-align: center; background-color: #000; border-radius: 0.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: right; 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: 0.875rem; word-wrap: break-word; background-color: #fff; background-clip: padding-box; border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 0.3rem; } .popover .popover-arrow { position: absolute; display: block; width: 1rem; height: 0.5rem; } .popover .popover-arrow::before, .popover .popover-arrow::after { position: absolute; display: block; content: ""; border-color: transparent; border-style: solid; } .bs-popover-top > .popover-arrow, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow { bottom: calc(-0.5rem - 1px); } .bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before { bottom: 0; border-width: 0.5rem 0.5rem 0; border-top-color: rgba(0, 0, 0, 0.25); } .bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after { bottom: 1px; border-width: 0.5rem 0.5rem 0; border-top-color: #fff; } .bs-popover-end > .popover-arrow, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow { right: calc(-0.5rem - 1px); width: 0.5rem; height: 1rem; } .bs-popover-end > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::before { right: 0; border-width: 0.5rem 0 0.5rem 0.5rem; border-left-color: rgba(0, 0, 0, 0.25); } .bs-popover-end > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow::after { right: 1px; border-width: 0.5rem 0 0.5rem 0.5rem; border-left-color: #fff; } .bs-popover-bottom > .popover-arrow, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow { top: calc(-0.5rem - 1px); } .bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before { top: 0; border-width: 0 0.5rem 0.5rem 0.5rem; border-bottom-color: rgba(0, 0, 0, 0.25); } .bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after { top: 1px; border-width: 0 0.5rem 0.5rem 0.5rem; border-bottom-color: #fff; } .bs-popover-bottom .popover-header::before, .bs-popover-auto[data-popper-placement^=bottom] .popover-header::before { position: absolute; top: 0; right: 50%; display: block; width: 1rem; margin-right: -0.5rem; content: ""; border-bottom: 1px solid #f0f0f0; } .bs-popover-start > .popover-arrow, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow { left: calc(-0.5rem - 1px); width: 0.5rem; height: 1rem; } .bs-popover-start > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::before { left: 0; border-width: 0.5rem 0.5rem 0.5rem 0; border-right-color: rgba(0, 0, 0, 0.25); } .bs-popover-start > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow::after { left: 1px; border-width: 0.5rem 0.5rem 0.5rem 0; border-right-color: #fff; } .popover-header { padding: 0.5rem 1rem; margin-bottom: 0; font-size: 1rem; background-color: #f0f0f0; border-bottom: 1px solid rgba(0, 0, 0, 0.2); border-top-right-radius: calc(0.3rem - 1px); border-top-left-radius: calc(0.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: right; width: 100%; margin-left: -100%; -webkit-backface-visibility: hidden; backface-visibility: hidden; transition: transform 0.6s ease-in-out; } @media (prefers-reduced-motion: reduce) { .carousel-item { transition: none; } } .carousel-item.active, .carousel-item-next, .carousel-item-prev { display: block; } .carousel-item-next:not(.carousel-item-start), .active.carousel-item-end { transform: translateX(100%); } .carousel-item-prev:not(.carousel-item-end), .active.carousel-item-start { transform: translateX(-100%); } .carousel-fade .carousel-item { opacity: 0; transition-property: opacity; transform: none; } .carousel-fade .carousel-item.active, .carousel-fade .carousel-item-next.carousel-item-start, .carousel-fade .carousel-item-prev.carousel-item-end { z-index: 1; opacity: 1; } .carousel-fade .active.carousel-item-start, .carousel-fade .active.carousel-item-end { z-index: 0; opacity: 0; transition: opacity 0s 0.6s; } @media (prefers-reduced-motion: reduce) { .carousel-fade .active.carousel-item-start, .carousel-fade .active.carousel-item-end { transition: none; } } .carousel-control-prev, .carousel-control-next { position: absolute; top: 0; bottom: 0; z-index: 1; display: flex; align-items: center; justify-content: center; width: 15%; padding: 0; color: #fff; text-align: center; background: none; border: 0; opacity: 0.5; transition: opacity 0.15s ease; } @media (prefers-reduced-motion: reduce) { .carousel-control-prev, .carousel-control-next { transition: none; } } .carousel-control-prev:hover, .carousel-control-prev:focus, .carousel-control-next:hover, .carousel-control-next:focus { color: #fff; text-decoration: none; outline: 0; opacity: 0.9; } .carousel-control-prev { right: 0; } .carousel-control-next { left: 0; } .carousel-control-prev-icon, .carousel-control-next-icon { display: inline-block; width: 2rem; height: 2rem; background-repeat: no-repeat; background-position: 50%; background-size: 100% 100%; } .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='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-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='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; left: 0; bottom: 0; right: 0; z-index: 2; display: flex; justify-content: center; padding: 0; margin-left: 15%; margin-bottom: 1rem; margin-right: 15%; list-style: none; } .carousel-indicators [data-bs-target] { box-sizing: content-box; flex: 0 1 auto; width: 30px; height: 3px; padding: 0; margin-left: 3px; margin-right: 3px; text-indent: -999px; cursor: pointer; background-color: #fff; background-clip: padding-box; border: 0; border-top: 10px solid transparent; border-bottom: 10px solid transparent; opacity: 0.5; transition: opacity 0.6s ease; } @media (prefers-reduced-motion: reduce) { .carousel-indicators [data-bs-target] { transition: none; } } .carousel-indicators .active { opacity: 1; } .carousel-caption { position: absolute; left: 15%; bottom: 1.25rem; right: 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: -0.125em; border: 0.25em solid currentColor; border-left-color: transparent; border-radius: 50%; -webkit-animation: 0.75s linear infinite spinner-border; animation: 0.75s linear infinite spinner-border; } .spinner-border-sm { width: 1rem; height: 1rem; border-width: 0.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: -0.125em; background-color: currentColor; border-radius: 50%; opacity: 0; -webkit-animation: 0.75s linear infinite spinner-grow; animation: 0.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 0.3s ease-in-out; } @media (prefers-reduced-motion: reduce) { .offcanvas { transition: none; } } .offcanvas-backdrop { position: fixed; top: 0; right: 0; z-index: 1040; width: 100vw; height: 100vh; background-color: #000; } .offcanvas-backdrop.fade { opacity: 0; } .offcanvas-backdrop.show { opacity: 0.5; } .offcanvas-header { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1rem; } .offcanvas-header .btn-close { padding: 0.5rem 0.5rem; margin-top: -0.5rem; margin-left: -0.5rem; margin-bottom: -0.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; right: 0; width: 400px; border-left: 1px solid rgba(0, 0, 0, 0.2); transform: translateX(100%); } .offcanvas-end { top: 0; left: 0; width: 400px; border-right: 1px solid rgba(0, 0, 0, 0.2); transform: translateX(-100%); } .offcanvas-top { top: 0; left: 0; right: 0; height: 30vh; max-height: 100%; border-bottom: 1px solid rgba(0, 0, 0, 0.2); transform: translateY(-100%); } .offcanvas-bottom { left: 0; right: 0; height: 30vh; max-height: 100%; border-top: 1px solid rgba(0, 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: 0.5; } .placeholder.btn::before { display: inline-block; content: ""; } .placeholder-xs { min-height: 0.6em; } .placeholder-sm { min-height: 0.8em; } .placeholder-lg { min-height: 1.2em; } .placeholder-glow .placeholder { -webkit-animation: placeholder-glow 2s ease-in-out infinite; animation: placeholder-glow 2s ease-in-out infinite; } @-webkit-keyframes placeholder-glow { 50% { opacity: 0.2; } } @keyframes placeholder-glow { 50% { opacity: 0.2; } } .placeholder-wave { -webkit-mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%); mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%); -webkit-mask-size: 200% 100%; mask-size: 200% 100%; -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:hover, .link-primary:focus { color: #0a58ca; } .link-secondary { color: #6c757d; } .link-secondary:hover, .link-secondary:focus { color: #565e64; } .link-success { color: #198754; } .link-success:hover, .link-success:focus { color: #146c43; } .link-info { color: #0dcaf0; } .link-info:hover, .link-info:focus { color: #3dd5f3; } .link-warning { color: #ffc107; } .link-warning:hover, .link-warning:focus { color: #ffcd39; } .link-danger { color: #dc3545; } .link-danger:hover, .link-danger:focus { color: #b02a37; } .link-light { color: #f8f9fa; } .link-light:hover, .link-light:focus { color: #f9fafb; } .link-dark { color: #212529; } .link-dark:hover, .link-dark:focus { color: #1a1e21; } .ratio { position: relative; width: 100%; } .ratio::before { display: block; padding-top: var(--bs-aspect-ratio); content: ""; } .ratio > * { position: absolute; top: 0; right: 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; left: 0; right: 0; z-index: 1030; } .fixed-bottom { position: fixed; left: 0; bottom: 0; right: 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; left: 0; bottom: 0; right: 0; z-index: 1; content: ""; } .text-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .vr { display: inline-block; align-self: stretch; width: 1px; min-height: 1em; background-color: currentColor; opacity: 0.25; } .align-baseline { vertical-align: baseline !important; } .align-top { vertical-align: top !important; } .align-middle { vertical-align: middle !important; } .align-bottom { vertical-align: bottom !important; } .align-text-bottom { vertical-align: text-bottom !important; } .align-text-top { vertical-align: text-top !important; } .float-start { float: right !important; } .float-end { float: left !important; } .float-none { float: none !important; } .opacity-0 { opacity: 0 !important; } .opacity-25 { opacity: 0.25 !important; } .opacity-50 { opacity: 0.5 !important; } .opacity-75 { opacity: 0.75 !important; } .opacity-100 { opacity: 1 !important; } .overflow-auto { overflow: auto !important; } .overflow-hidden { overflow: hidden !important; } .overflow-visible { overflow: visible !important; } .overflow-scroll { overflow: scroll !important; } .d-inline { display: inline !important; } .d-inline-block { display: inline-block !important; } .d-block { display: block !important; } .d-grid { display: grid !important; } .d-table { display: table !important; } .d-table-row { display: table-row !important; } .d-table-cell { display: table-cell !important; } .d-flex { display: flex !important; } .d-inline-flex { display: inline-flex !important; } .d-none { display: none !important; } .shadow { box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; } .shadow-sm { box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075) !important; } .shadow-lg { box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important; } .shadow-none { box-shadow: none !important; } .position-static { position: static !important; } .position-relative { position: relative !important; } .position-absolute { position: absolute !important; } .position-fixed { position: fixed !important; } .position-sticky { position: -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 { right: 0 !important; } .start-50 { right: 50% !important; } .start-100 { right: 100% !important; } .end-0 { left: 0 !important; } .end-50 { left: 50% !important; } .end-100 { left: 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-left: 1px solid #dee2e6 !important; } .border-end-0 { border-left: 0 !important; } .border-bottom { border-bottom: 1px solid #dee2e6 !important; } .border-bottom-0 { border-bottom: 0 !important; } .border-start { border-right: 1px solid #dee2e6 !important; } .border-start-0 { border-right: 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: 0.25rem !important; } .gap-2 { gap: 0.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: 0.25rem !important; } .m-2 { margin: 0.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-left: 0 !important; margin-right: 0 !important; } .mx-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-auto { margin-left: auto !important; margin-right: auto !important; } .my-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-5 { margin-top: 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: 0.25rem !important; } .mt-2 { margin-top: 0.5rem !important; } .mt-3 { margin-top: 1rem !important; } .mt-4 { margin-top: 1.5rem !important; } .mt-5 { margin-top: 3rem !important; } .mt-auto { margin-top: auto !important; } .me-0 { margin-left: 0 !important; } .me-1 { margin-left: 0.25rem !important; } .me-2 { margin-left: 0.5rem !important; } .me-3 { margin-left: 1rem !important; } .me-4 { margin-left: 1.5rem !important; } .me-5 { margin-left: 3rem !important; } .me-auto { margin-left: auto !important; } .mb-0 { margin-bottom: 0 !important; } .mb-1 { margin-bottom: 0.25rem !important; } .mb-2 { margin-bottom: 0.5rem !important; } .mb-3 { margin-bottom: 1rem !important; } .mb-4 { margin-bottom: 1.5rem !important; } .mb-5 { margin-bottom: 3rem !important; } .mb-auto { margin-bottom: auto !important; } .ms-0 { margin-right: 0 !important; } .ms-1 { margin-right: 0.25rem !important; } .ms-2 { margin-right: 0.5rem !important; } .ms-3 { margin-right: 1rem !important; } .ms-4 { margin-right: 1.5rem !important; } .ms-5 { margin-right: 3rem !important; } .ms-auto { margin-right: auto !important; } .p-0 { padding: 0 !important; } .p-1 { padding: 0.25rem !important; } .p-2 { padding: 0.5rem !important; } .p-3 { padding: 1rem !important; } .p-4 { padding: 1.5rem !important; } .p-5 { padding: 3rem !important; } .px-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-0 { padding-top: 0 !important; } .pt-1 { padding-top: 0.25rem !important; } .pt-2 { padding-top: 0.5rem !important; } .pt-3 { padding-top: 1rem !important; } .pt-4 { padding-top: 1.5rem !important; } .pt-5 { padding-top: 3rem !important; } .pe-0 { padding-left: 0 !important; } .pe-1 { padding-left: 0.25rem !important; } .pe-2 { padding-left: 0.5rem !important; } .pe-3 { padding-left: 1rem !important; } .pe-4 { padding-left: 1.5rem !important; } .pe-5 { padding-left: 3rem !important; } .pb-0 { padding-bottom: 0 !important; } .pb-1 { padding-bottom: 0.25rem !important; } .pb-2 { padding-bottom: 0.5rem !important; } .pb-3 { padding-bottom: 1rem !important; } .pb-4 { padding-bottom: 1.5rem !important; } .pb-5 { padding-bottom: 3rem !important; } .ps-0 { padding-right: 0 !important; } .ps-1 { padding-right: 0.25rem !important; } .ps-2 { padding-right: 0.5rem !important; } .ps-3 { padding-right: 1rem !important; } .ps-4 { padding-right: 1.5rem !important; } .ps-5 { padding-right: 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 + 0.9vw) !important; } .fs-3 { font-size: calc(1.3rem + 0.6vw) !important; } .fs-4 { font-size: calc(1.275rem + 0.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: right !important; } .text-end { text-align: left !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-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, 0.5) !important; } .text-white-50 { --bs-text-opacity: 1; color: rgba(255, 255, 255, 0.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: 0.25rem !important; } .rounded-0 { border-radius: 0 !important; } .rounded-1 { border-radius: 0.2rem !important; } .rounded-2 { border-radius: 0.25rem !important; } .rounded-3 { border-radius: 0.3rem !important; } .rounded-circle { border-radius: 50% !important; } .rounded-pill { border-radius: 50rem !important; } .rounded-top { border-top-right-radius: 0.25rem !important; border-top-left-radius: 0.25rem !important; } .rounded-end { border-top-left-radius: 0.25rem !important; border-bottom-left-radius: 0.25rem !important; } .rounded-bottom { border-bottom-left-radius: 0.25rem !important; border-bottom-right-radius: 0.25rem !important; } .rounded-start { border-bottom-right-radius: 0.25rem !important; border-top-right-radius: 0.25rem !important; } .visible { visibility: visible !important; } .invisible { visibility: hidden !important; } @media (min-width: 576px) { .float-sm-start { float: right !important; } .float-sm-end { float: left !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: 0.25rem !important; } .gap-sm-2 { gap: 0.5rem !important; } .gap-sm-3 { gap: 1rem !important; } .gap-sm-4 { gap: 1.5rem !important; } .gap-sm-5 { gap: 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: 0.25rem !important; } .m-sm-2 { margin: 0.5rem !important; } .m-sm-3 { margin: 1rem !important; } .m-sm-4 { margin: 1.5rem !important; } .m-sm-5 { margin: 3rem !important; } .m-sm-auto { margin: auto !important; } .mx-sm-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-sm-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-sm-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-sm-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-sm-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-sm-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-sm-auto { margin-left: auto !important; margin-right: auto !important; } .my-sm-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-sm-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-sm-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-sm-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-sm-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-sm-5 { margin-top: 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: 0.25rem !important; } .mt-sm-2 { margin-top: 0.5rem !important; } .mt-sm-3 { margin-top: 1rem !important; } .mt-sm-4 { margin-top: 1.5rem !important; } .mt-sm-5 { margin-top: 3rem !important; } .mt-sm-auto { margin-top: auto !important; } .me-sm-0 { margin-left: 0 !important; } .me-sm-1 { margin-left: 0.25rem !important; } .me-sm-2 { margin-left: 0.5rem !important; } .me-sm-3 { margin-left: 1rem !important; } .me-sm-4 { margin-left: 1.5rem !important; } .me-sm-5 { margin-left: 3rem !important; } .me-sm-auto { margin-left: auto !important; } .mb-sm-0 { margin-bottom: 0 !important; } .mb-sm-1 { margin-bottom: 0.25rem !important; } .mb-sm-2 { margin-bottom: 0.5rem !important; } .mb-sm-3 { margin-bottom: 1rem !important; } .mb-sm-4 { margin-bottom: 1.5rem !important; } .mb-sm-5 { margin-bottom: 3rem !important; } .mb-sm-auto { margin-bottom: auto !important; } .ms-sm-0 { margin-right: 0 !important; } .ms-sm-1 { margin-right: 0.25rem !important; } .ms-sm-2 { margin-right: 0.5rem !important; } .ms-sm-3 { margin-right: 1rem !important; } .ms-sm-4 { margin-right: 1.5rem !important; } .ms-sm-5 { margin-right: 3rem !important; } .ms-sm-auto { margin-right: auto !important; } .p-sm-0 { padding: 0 !important; } .p-sm-1 { padding: 0.25rem !important; } .p-sm-2 { padding: 0.5rem !important; } .p-sm-3 { padding: 1rem !important; } .p-sm-4 { padding: 1.5rem !important; } .p-sm-5 { padding: 3rem !important; } .px-sm-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-sm-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-sm-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-sm-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-sm-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-sm-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-sm-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-sm-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-sm-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-sm-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-sm-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-sm-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-sm-0 { padding-top: 0 !important; } .pt-sm-1 { padding-top: 0.25rem !important; } .pt-sm-2 { padding-top: 0.5rem !important; } .pt-sm-3 { padding-top: 1rem !important; } .pt-sm-4 { padding-top: 1.5rem !important; } .pt-sm-5 { padding-top: 3rem !important; } .pe-sm-0 { padding-left: 0 !important; } .pe-sm-1 { padding-left: 0.25rem !important; } .pe-sm-2 { padding-left: 0.5rem !important; } .pe-sm-3 { padding-left: 1rem !important; } .pe-sm-4 { padding-left: 1.5rem !important; } .pe-sm-5 { padding-left: 3rem !important; } .pb-sm-0 { padding-bottom: 0 !important; } .pb-sm-1 { padding-bottom: 0.25rem !important; } .pb-sm-2 { padding-bottom: 0.5rem !important; } .pb-sm-3 { padding-bottom: 1rem !important; } .pb-sm-4 { padding-bottom: 1.5rem !important; } .pb-sm-5 { padding-bottom: 3rem !important; } .ps-sm-0 { padding-right: 0 !important; } .ps-sm-1 { padding-right: 0.25rem !important; } .ps-sm-2 { padding-right: 0.5rem !important; } .ps-sm-3 { padding-right: 1rem !important; } .ps-sm-4 { padding-right: 1.5rem !important; } .ps-sm-5 { padding-right: 3rem !important; } .text-sm-start { text-align: right !important; } .text-sm-end { text-align: left !important; } .text-sm-center { text-align: center !important; } } @media (min-width: 768px) { .float-md-start { float: right !important; } .float-md-end { float: left !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: 0.25rem !important; } .gap-md-2 { gap: 0.5rem !important; } .gap-md-3 { gap: 1rem !important; } .gap-md-4 { gap: 1.5rem !important; } .gap-md-5 { gap: 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: 0.25rem !important; } .m-md-2 { margin: 0.5rem !important; } .m-md-3 { margin: 1rem !important; } .m-md-4 { margin: 1.5rem !important; } .m-md-5 { margin: 3rem !important; } .m-md-auto { margin: auto !important; } .mx-md-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-md-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-md-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-md-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-md-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-md-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-md-auto { margin-left: auto !important; margin-right: auto !important; } .my-md-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-md-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-md-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-md-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-md-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-md-5 { margin-top: 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: 0.25rem !important; } .mt-md-2 { margin-top: 0.5rem !important; } .mt-md-3 { margin-top: 1rem !important; } .mt-md-4 { margin-top: 1.5rem !important; } .mt-md-5 { margin-top: 3rem !important; } .mt-md-auto { margin-top: auto !important; } .me-md-0 { margin-left: 0 !important; } .me-md-1 { margin-left: 0.25rem !important; } .me-md-2 { margin-left: 0.5rem !important; } .me-md-3 { margin-left: 1rem !important; } .me-md-4 { margin-left: 1.5rem !important; } .me-md-5 { margin-left: 3rem !important; } .me-md-auto { margin-left: auto !important; } .mb-md-0 { margin-bottom: 0 !important; } .mb-md-1 { margin-bottom: 0.25rem !important; } .mb-md-2 { margin-bottom: 0.5rem !important; } .mb-md-3 { margin-bottom: 1rem !important; } .mb-md-4 { margin-bottom: 1.5rem !important; } .mb-md-5 { margin-bottom: 3rem !important; } .mb-md-auto { margin-bottom: auto !important; } .ms-md-0 { margin-right: 0 !important; } .ms-md-1 { margin-right: 0.25rem !important; } .ms-md-2 { margin-right: 0.5rem !important; } .ms-md-3 { margin-right: 1rem !important; } .ms-md-4 { margin-right: 1.5rem !important; } .ms-md-5 { margin-right: 3rem !important; } .ms-md-auto { margin-right: auto !important; } .p-md-0 { padding: 0 !important; } .p-md-1 { padding: 0.25rem !important; } .p-md-2 { padding: 0.5rem !important; } .p-md-3 { padding: 1rem !important; } .p-md-4 { padding: 1.5rem !important; } .p-md-5 { padding: 3rem !important; } .px-md-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-md-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-md-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-md-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-md-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-md-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-md-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-md-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-md-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-md-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-md-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-md-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-md-0 { padding-top: 0 !important; } .pt-md-1 { padding-top: 0.25rem !important; } .pt-md-2 { padding-top: 0.5rem !important; } .pt-md-3 { padding-top: 1rem !important; } .pt-md-4 { padding-top: 1.5rem !important; } .pt-md-5 { padding-top: 3rem !important; } .pe-md-0 { padding-left: 0 !important; } .pe-md-1 { padding-left: 0.25rem !important; } .pe-md-2 { padding-left: 0.5rem !important; } .pe-md-3 { padding-left: 1rem !important; } .pe-md-4 { padding-left: 1.5rem !important; } .pe-md-5 { padding-left: 3rem !important; } .pb-md-0 { padding-bottom: 0 !important; } .pb-md-1 { padding-bottom: 0.25rem !important; } .pb-md-2 { padding-bottom: 0.5rem !important; } .pb-md-3 { padding-bottom: 1rem !important; } .pb-md-4 { padding-bottom: 1.5rem !important; } .pb-md-5 { padding-bottom: 3rem !important; } .ps-md-0 { padding-right: 0 !important; } .ps-md-1 { padding-right: 0.25rem !important; } .ps-md-2 { padding-right: 0.5rem !important; } .ps-md-3 { padding-right: 1rem !important; } .ps-md-4 { padding-right: 1.5rem !important; } .ps-md-5 { padding-right: 3rem !important; } .text-md-start { text-align: right !important; } .text-md-end { text-align: left !important; } .text-md-center { text-align: center !important; } } @media (min-width: 992px) { .float-lg-start { float: right !important; } .float-lg-end { float: left !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: 0.25rem !important; } .gap-lg-2 { gap: 0.5rem !important; } .gap-lg-3 { gap: 1rem !important; } .gap-lg-4 { gap: 1.5rem !important; } .gap-lg-5 { gap: 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: 0.25rem !important; } .m-lg-2 { margin: 0.5rem !important; } .m-lg-3 { margin: 1rem !important; } .m-lg-4 { margin: 1.5rem !important; } .m-lg-5 { margin: 3rem !important; } .m-lg-auto { margin: auto !important; } .mx-lg-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-lg-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-lg-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-lg-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-lg-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-lg-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-lg-auto { margin-left: auto !important; margin-right: auto !important; } .my-lg-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-lg-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-lg-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-lg-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-lg-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-lg-5 { margin-top: 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: 0.25rem !important; } .mt-lg-2 { margin-top: 0.5rem !important; } .mt-lg-3 { margin-top: 1rem !important; } .mt-lg-4 { margin-top: 1.5rem !important; } .mt-lg-5 { margin-top: 3rem !important; } .mt-lg-auto { margin-top: auto !important; } .me-lg-0 { margin-left: 0 !important; } .me-lg-1 { margin-left: 0.25rem !important; } .me-lg-2 { margin-left: 0.5rem !important; } .me-lg-3 { margin-left: 1rem !important; } .me-lg-4 { margin-left: 1.5rem !important; } .me-lg-5 { margin-left: 3rem !important; } .me-lg-auto { margin-left: auto !important; } .mb-lg-0 { margin-bottom: 0 !important; } .mb-lg-1 { margin-bottom: 0.25rem !important; } .mb-lg-2 { margin-bottom: 0.5rem !important; } .mb-lg-3 { margin-bottom: 1rem !important; } .mb-lg-4 { margin-bottom: 1.5rem !important; } .mb-lg-5 { margin-bottom: 3rem !important; } .mb-lg-auto { margin-bottom: auto !important; } .ms-lg-0 { margin-right: 0 !important; } .ms-lg-1 { margin-right: 0.25rem !important; } .ms-lg-2 { margin-right: 0.5rem !important; } .ms-lg-3 { margin-right: 1rem !important; } .ms-lg-4 { margin-right: 1.5rem !important; } .ms-lg-5 { margin-right: 3rem !important; } .ms-lg-auto { margin-right: auto !important; } .p-lg-0 { padding: 0 !important; } .p-lg-1 { padding: 0.25rem !important; } .p-lg-2 { padding: 0.5rem !important; } .p-lg-3 { padding: 1rem !important; } .p-lg-4 { padding: 1.5rem !important; } .p-lg-5 { padding: 3rem !important; } .px-lg-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-lg-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-lg-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-lg-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-lg-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-lg-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-lg-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-lg-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-lg-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-lg-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-lg-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-lg-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-lg-0 { padding-top: 0 !important; } .pt-lg-1 { padding-top: 0.25rem !important; } .pt-lg-2 { padding-top: 0.5rem !important; } .pt-lg-3 { padding-top: 1rem !important; } .pt-lg-4 { padding-top: 1.5rem !important; } .pt-lg-5 { padding-top: 3rem !important; } .pe-lg-0 { padding-left: 0 !important; } .pe-lg-1 { padding-left: 0.25rem !important; } .pe-lg-2 { padding-left: 0.5rem !important; } .pe-lg-3 { padding-left: 1rem !important; } .pe-lg-4 { padding-left: 1.5rem !important; } .pe-lg-5 { padding-left: 3rem !important; } .pb-lg-0 { padding-bottom: 0 !important; } .pb-lg-1 { padding-bottom: 0.25rem !important; } .pb-lg-2 { padding-bottom: 0.5rem !important; } .pb-lg-3 { padding-bottom: 1rem !important; } .pb-lg-4 { padding-bottom: 1.5rem !important; } .pb-lg-5 { padding-bottom: 3rem !important; } .ps-lg-0 { padding-right: 0 !important; } .ps-lg-1 { padding-right: 0.25rem !important; } .ps-lg-2 { padding-right: 0.5rem !important; } .ps-lg-3 { padding-right: 1rem !important; } .ps-lg-4 { padding-right: 1.5rem !important; } .ps-lg-5 { padding-right: 3rem !important; } .text-lg-start { text-align: right !important; } .text-lg-end { text-align: left !important; } .text-lg-center { text-align: center !important; } } @media (min-width: 1200px) { .float-xl-start { float: right !important; } .float-xl-end { float: left !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: 0.25rem !important; } .gap-xl-2 { gap: 0.5rem !important; } .gap-xl-3 { gap: 1rem !important; } .gap-xl-4 { gap: 1.5rem !important; } .gap-xl-5 { gap: 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: 0.25rem !important; } .m-xl-2 { margin: 0.5rem !important; } .m-xl-3 { margin: 1rem !important; } .m-xl-4 { margin: 1.5rem !important; } .m-xl-5 { margin: 3rem !important; } .m-xl-auto { margin: auto !important; } .mx-xl-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-xl-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-xl-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-xl-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-xl-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-xl-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-xl-auto { margin-left: auto !important; margin-right: auto !important; } .my-xl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-xl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xl-5 { margin-top: 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: 0.25rem !important; } .mt-xl-2 { margin-top: 0.5rem !important; } .mt-xl-3 { margin-top: 1rem !important; } .mt-xl-4 { margin-top: 1.5rem !important; } .mt-xl-5 { margin-top: 3rem !important; } .mt-xl-auto { margin-top: auto !important; } .me-xl-0 { margin-left: 0 !important; } .me-xl-1 { margin-left: 0.25rem !important; } .me-xl-2 { margin-left: 0.5rem !important; } .me-xl-3 { margin-left: 1rem !important; } .me-xl-4 { margin-left: 1.5rem !important; } .me-xl-5 { margin-left: 3rem !important; } .me-xl-auto { margin-left: auto !important; } .mb-xl-0 { margin-bottom: 0 !important; } .mb-xl-1 { margin-bottom: 0.25rem !important; } .mb-xl-2 { margin-bottom: 0.5rem !important; } .mb-xl-3 { margin-bottom: 1rem !important; } .mb-xl-4 { margin-bottom: 1.5rem !important; } .mb-xl-5 { margin-bottom: 3rem !important; } .mb-xl-auto { margin-bottom: auto !important; } .ms-xl-0 { margin-right: 0 !important; } .ms-xl-1 { margin-right: 0.25rem !important; } .ms-xl-2 { margin-right: 0.5rem !important; } .ms-xl-3 { margin-right: 1rem !important; } .ms-xl-4 { margin-right: 1.5rem !important; } .ms-xl-5 { margin-right: 3rem !important; } .ms-xl-auto { margin-right: auto !important; } .p-xl-0 { padding: 0 !important; } .p-xl-1 { padding: 0.25rem !important; } .p-xl-2 { padding: 0.5rem !important; } .p-xl-3 { padding: 1rem !important; } .p-xl-4 { padding: 1.5rem !important; } .p-xl-5 { padding: 3rem !important; } .px-xl-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-xl-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-xl-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-xl-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-xl-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-xl-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-xl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xl-0 { padding-top: 0 !important; } .pt-xl-1 { padding-top: 0.25rem !important; } .pt-xl-2 { padding-top: 0.5rem !important; } .pt-xl-3 { padding-top: 1rem !important; } .pt-xl-4 { padding-top: 1.5rem !important; } .pt-xl-5 { padding-top: 3rem !important; } .pe-xl-0 { padding-left: 0 !important; } .pe-xl-1 { padding-left: 0.25rem !important; } .pe-xl-2 { padding-left: 0.5rem !important; } .pe-xl-3 { padding-left: 1rem !important; } .pe-xl-4 { padding-left: 1.5rem !important; } .pe-xl-5 { padding-left: 3rem !important; } .pb-xl-0 { padding-bottom: 0 !important; } .pb-xl-1 { padding-bottom: 0.25rem !important; } .pb-xl-2 { padding-bottom: 0.5rem !important; } .pb-xl-3 { padding-bottom: 1rem !important; } .pb-xl-4 { padding-bottom: 1.5rem !important; } .pb-xl-5 { padding-bottom: 3rem !important; } .ps-xl-0 { padding-right: 0 !important; } .ps-xl-1 { padding-right: 0.25rem !important; } .ps-xl-2 { padding-right: 0.5rem !important; } .ps-xl-3 { padding-right: 1rem !important; } .ps-xl-4 { padding-right: 1.5rem !important; } .ps-xl-5 { padding-right: 3rem !important; } .text-xl-start { text-align: right !important; } .text-xl-end { text-align: left !important; } .text-xl-center { text-align: center !important; } } @media (min-width: 1400px) { .float-xxl-start { float: right !important; } .float-xxl-end { float: left !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: 0.25rem !important; } .gap-xxl-2 { gap: 0.5rem !important; } .gap-xxl-3 { gap: 1rem !important; } .gap-xxl-4 { gap: 1.5rem !important; } .gap-xxl-5 { gap: 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: 0.25rem !important; } .m-xxl-2 { margin: 0.5rem !important; } .m-xxl-3 { margin: 1rem !important; } .m-xxl-4 { margin: 1.5rem !important; } .m-xxl-5 { margin: 3rem !important; } .m-xxl-auto { margin: auto !important; } .mx-xxl-0 { margin-left: 0 !important; margin-right: 0 !important; } .mx-xxl-1 { margin-left: 0.25rem !important; margin-right: 0.25rem !important; } .mx-xxl-2 { margin-left: 0.5rem !important; margin-right: 0.5rem !important; } .mx-xxl-3 { margin-left: 1rem !important; margin-right: 1rem !important; } .mx-xxl-4 { margin-left: 1.5rem !important; margin-right: 1.5rem !important; } .mx-xxl-5 { margin-left: 3rem !important; margin-right: 3rem !important; } .mx-xxl-auto { margin-left: auto !important; margin-right: auto !important; } .my-xxl-0 { margin-top: 0 !important; margin-bottom: 0 !important; } .my-xxl-1 { margin-top: 0.25rem !important; margin-bottom: 0.25rem !important; } .my-xxl-2 { margin-top: 0.5rem !important; margin-bottom: 0.5rem !important; } .my-xxl-3 { margin-top: 1rem !important; margin-bottom: 1rem !important; } .my-xxl-4 { margin-top: 1.5rem !important; margin-bottom: 1.5rem !important; } .my-xxl-5 { margin-top: 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: 0.25rem !important; } .mt-xxl-2 { margin-top: 0.5rem !important; } .mt-xxl-3 { margin-top: 1rem !important; } .mt-xxl-4 { margin-top: 1.5rem !important; } .mt-xxl-5 { margin-top: 3rem !important; } .mt-xxl-auto { margin-top: auto !important; } .me-xxl-0 { margin-left: 0 !important; } .me-xxl-1 { margin-left: 0.25rem !important; } .me-xxl-2 { margin-left: 0.5rem !important; } .me-xxl-3 { margin-left: 1rem !important; } .me-xxl-4 { margin-left: 1.5rem !important; } .me-xxl-5 { margin-left: 3rem !important; } .me-xxl-auto { margin-left: auto !important; } .mb-xxl-0 { margin-bottom: 0 !important; } .mb-xxl-1 { margin-bottom: 0.25rem !important; } .mb-xxl-2 { margin-bottom: 0.5rem !important; } .mb-xxl-3 { margin-bottom: 1rem !important; } .mb-xxl-4 { margin-bottom: 1.5rem !important; } .mb-xxl-5 { margin-bottom: 3rem !important; } .mb-xxl-auto { margin-bottom: auto !important; } .ms-xxl-0 { margin-right: 0 !important; } .ms-xxl-1 { margin-right: 0.25rem !important; } .ms-xxl-2 { margin-right: 0.5rem !important; } .ms-xxl-3 { margin-right: 1rem !important; } .ms-xxl-4 { margin-right: 1.5rem !important; } .ms-xxl-5 { margin-right: 3rem !important; } .ms-xxl-auto { margin-right: auto !important; } .p-xxl-0 { padding: 0 !important; } .p-xxl-1 { padding: 0.25rem !important; } .p-xxl-2 { padding: 0.5rem !important; } .p-xxl-3 { padding: 1rem !important; } .p-xxl-4 { padding: 1.5rem !important; } .p-xxl-5 { padding: 3rem !important; } .px-xxl-0 { padding-left: 0 !important; padding-right: 0 !important; } .px-xxl-1 { padding-left: 0.25rem !important; padding-right: 0.25rem !important; } .px-xxl-2 { padding-left: 0.5rem !important; padding-right: 0.5rem !important; } .px-xxl-3 { padding-left: 1rem !important; padding-right: 1rem !important; } .px-xxl-4 { padding-left: 1.5rem !important; padding-right: 1.5rem !important; } .px-xxl-5 { padding-left: 3rem !important; padding-right: 3rem !important; } .py-xxl-0 { padding-top: 0 !important; padding-bottom: 0 !important; } .py-xxl-1 { padding-top: 0.25rem !important; padding-bottom: 0.25rem !important; } .py-xxl-2 { padding-top: 0.5rem !important; padding-bottom: 0.5rem !important; } .py-xxl-3 { padding-top: 1rem !important; padding-bottom: 1rem !important; } .py-xxl-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; } .py-xxl-5 { padding-top: 3rem !important; padding-bottom: 3rem !important; } .pt-xxl-0 { padding-top: 0 !important; } .pt-xxl-1 { padding-top: 0.25rem !important; } .pt-xxl-2 { padding-top: 0.5rem !important; } .pt-xxl-3 { padding-top: 1rem !important; } .pt-xxl-4 { padding-top: 1.5rem !important; } .pt-xxl-5 { padding-top: 3rem !important; } .pe-xxl-0 { padding-left: 0 !important; } .pe-xxl-1 { padding-left: 0.25rem !important; } .pe-xxl-2 { padding-left: 0.5rem !important; } .pe-xxl-3 { padding-left: 1rem !important; } .pe-xxl-4 { padding-left: 1.5rem !important; } .pe-xxl-5 { padding-left: 3rem !important; } .pb-xxl-0 { padding-bottom: 0 !important; } .pb-xxl-1 { padding-bottom: 0.25rem !important; } .pb-xxl-2 { padding-bottom: 0.5rem !important; } .pb-xxl-3 { padding-bottom: 1rem !important; } .pb-xxl-4 { padding-bottom: 1.5rem !important; } .pb-xxl-5 { padding-bottom: 3rem !important; } .ps-xxl-0 { padding-right: 0 !important; } .ps-xxl-1 { padding-right: 0.25rem !important; } .ps-xxl-2 { padding-right: 0.5rem !important; } .ps-xxl-3 { padding-right: 1rem !important; } .ps-xxl-4 { padding-right: 1.5rem !important; } .ps-xxl-5 { padding-right: 3rem !important; } .text-xxl-start { text-align: right !important; } .text-xxl-end { text-align: left !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.rtl.css.map */ ================================================ FILE: sample/src/NimblePros.SampleToDo.Web/wwwroot/lib/bootstrap/dist/js/bootstrap.bundle.js ================================================ /*! * Bootstrap v5.1.0 (https://getbootstrap.com/) * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bootstrap = factory()); }(this, (function () { 'use strict'; /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): util/index.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ const MAX_UID = 1000000; const MILLISECONDS_MULTIPLIER = 1000; const TRANSITION_END = 'transitionend'; // Shoutout AngusCroll (https://goo.gl/pxwQGp) const toType = obj => { if (obj === null || obj === undefined) { return `${obj}`; } return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase(); }; /** * -------------------------------------------------------------------------- * Public Util Api * -------------------------------------------------------------------------- */ const getUID = prefix => { do { prefix += Math.floor(Math.random() * MAX_UID); } while (document.getElementById(prefix)); return prefix; }; const getSelector = element => { let selector = element.getAttribute('data-bs-target'); if (!selector || selector === '#') { let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes, // so everything starting with `#` or `.`. If a "real" URL is used as the selector, // `document.querySelector` will rightfully complain it is invalid. // See https://github.com/twbs/bootstrap/issues/32273 if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) { return null; } // Just in case some CMS puts out a full URL with the anchor appended if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) { hrefAttr = `#${hrefAttr.split('#')[1]}`; } selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null; } return selector; }; const getSelectorFromElement = element => { const selector = getSelector(element); if (selector) { return document.querySelector(selector) ? selector : null; } return null; }; const getElementFromSelector = element => { const selector = getSelector(element); return selector ? document.querySelector(selector) : null; }; const getTransitionDurationFromElement = element => { if (!element) { return 0; } // Get transition-duration of the element let { transitionDuration, transitionDelay } = window.getComputedStyle(element); const floatTransitionDuration = Number.parseFloat(transitionDuration); const floatTransitionDelay = Number.parseFloat(transitionDelay); // Return 0 if element or transition duration is not found if (!floatTransitionDuration && !floatTransitionDelay) { return 0; } // If multiple durations are defined, take the first transitionDuration = transitionDuration.split(',')[0]; transitionDelay = transitionDelay.split(',')[0]; return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER; }; const triggerTransitionEnd = element => { element.dispatchEvent(new Event(TRANSITION_END)); }; const isElement$1 = obj => { if (!obj || typeof obj !== 'object') { return false; } if (typeof obj.jquery !== 'undefined') { obj = obj[0]; } return typeof obj.nodeType !== 'undefined'; }; const getElement = obj => { if (isElement$1(obj)) { // it's a jQuery object or a node element return obj.jquery ? obj[0] : obj; } if (typeof obj === 'string' && obj.length > 0) { return document.querySelector(obj); } return null; }; const typeCheckConfig = (componentName, config, configTypes) => { Object.keys(configTypes).forEach(property => { const expectedTypes = configTypes[property]; const value = config[property]; const valueType = value && isElement$1(value) ? 'element' : toType(value); if (!new RegExp(expectedTypes).test(valueType)) { throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`); } }); }; const isVisible = element => { if (!isElement$1(element) || element.getClientRects().length === 0) { return false; } return getComputedStyle(element).getPropertyValue('visibility') === 'visible'; }; const isDisabled = element => { if (!element || element.nodeType !== Node.ELEMENT_NODE) { return true; } if (element.classList.contains('disabled')) { return true; } if (typeof element.disabled !== 'undefined') { return element.disabled; } return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'; }; const findShadowRoot = element => { if (!document.documentElement.attachShadow) { return null; } // Can find the shadow root otherwise it'll return the document if (typeof element.getRootNode === 'function') { const root = element.getRootNode(); return root instanceof ShadowRoot ? root : null; } if (element instanceof ShadowRoot) { return element; } // when we don't find a shadow root if (!element.parentNode) { return null; } return findShadowRoot(element.parentNode); }; const noop = () => {}; /** * Trick to restart an element's animation * * @param {HTMLElement} element * @return void * * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation */ const reflow = element => { // eslint-disable-next-line no-unused-expressions element.offsetHeight; }; const getjQuery = () => { const { jQuery } = window; if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) { return jQuery; } return null; }; const DOMContentLoadedCallbacks = []; const onDOMContentLoaded = callback => { if (document.readyState === 'loading') { // add listener on the first call when the document is in loading state if (!DOMContentLoadedCallbacks.length) { document.addEventListener('DOMContentLoaded', () => { DOMContentLoadedCallbacks.forEach(callback => callback()); }); } DOMContentLoadedCallbacks.push(callback); } else { callback(); } }; const isRTL = () => document.documentElement.dir === 'rtl'; const defineJQueryPlugin = plugin => { onDOMContentLoaded(() => { const $ = getjQuery(); /* istanbul ignore if */ if ($) { const name = plugin.NAME; const JQUERY_NO_CONFLICT = $.fn[name]; $.fn[name] = plugin.jQueryInterface; $.fn[name].Constructor = plugin; $.fn[name].noConflict = () => { $.fn[name] = JQUERY_NO_CONFLICT; return plugin.jQueryInterface; }; } }); }; const execute = callback => { if (typeof callback === 'function') { callback(); } }; const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => { if (!waitForTransition) { execute(callback); return; } const durationPadding = 5; const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding; let called = false; const handler = ({ target }) => { if (target !== transitionElement) { return; } called = true; transitionElement.removeEventListener(TRANSITION_END, handler); execute(callback); }; transitionElement.addEventListener(TRANSITION_END, handler); setTimeout(() => { if (!called) { triggerTransitionEnd(transitionElement); } }, emulatedDuration); }; /** * Return the previous/next element of a list. * * @param {array} list The list of elements * @param activeElement The active element * @param shouldGetNext Choose to get next or previous element * @param isCycleAllowed * @return {Element|elem} The proper element */ const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => { let index = list.indexOf(activeElement); // if the element does not exist in the list return an element depending on the direction and if cycle is allowed if (index === -1) { return list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0]; } const listLength = list.length; index += shouldGetNext ? 1 : -1; if (isCycleAllowed) { index = (index + listLength) % listLength; } return list[Math.max(0, Math.min(index, listLength - 1))]; }; /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): dom/event-handler.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const namespaceRegex = /[^.]*(?=\..*)\.|.*/; const stripNameRegex = /\..*/; const stripUidRegex = /::\d+$/; const eventRegistry = {}; // Events storage let uidEvent = 1; const customEvents = { mouseenter: 'mouseover', mouseleave: 'mouseout' }; const customEventsRegex = /^(mouseenter|mouseleave)/i; const nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']); /** * ------------------------------------------------------------------------ * Private methods * ------------------------------------------------------------------------ */ function getUidEvent(element, uid) { return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++; } function getEvent(element) { const uid = getUidEvent(element); element.uidEvent = uid; eventRegistry[uid] = eventRegistry[uid] || {}; return eventRegistry[uid]; } function bootstrapHandler(element, fn) { return function handler(event) { event.delegateTarget = element; if (handler.oneOff) { EventHandler.off(element, event.type, fn); } return fn.apply(element, [event]); }; } function bootstrapDelegationHandler(element, selector, fn) { return function handler(event) { const domElements = element.querySelectorAll(selector); for (let { target } = event; target && target !== this; target = target.parentNode) { for (let i = domElements.length; i--;) { if (domElements[i] === target) { event.delegateTarget = target; if (handler.oneOff) { // eslint-disable-next-line unicorn/consistent-destructuring EventHandler.off(element, event.type, selector, fn); } return fn.apply(target, [event]); } } } // To please ESLint return null; }; } function findHandler(events, handler, delegationSelector = null) { const uidEventList = Object.keys(events); for (let i = 0, len = uidEventList.length; i < len; i++) { const event = events[uidEventList[i]]; if (event.originalHandler === handler && event.delegationSelector === delegationSelector) { return event; } } return null; } function normalizeParams(originalTypeEvent, handler, delegationFn) { const delegation = typeof handler === 'string'; const originalHandler = delegation ? delegationFn : handler; let typeEvent = getTypeEvent(originalTypeEvent); const isNative = nativeEvents.has(typeEvent); if (!isNative) { typeEvent = originalTypeEvent; } return [delegation, originalHandler, typeEvent]; } function addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) { if (typeof originalTypeEvent !== 'string' || !element) { return; } if (!handler) { handler = delegationFn; delegationFn = null; } // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position // this prevents the handler from being dispatched the same way as mouseover or mouseout does if (customEventsRegex.test(originalTypeEvent)) { const wrapFn = fn => { return function (event) { if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) { return fn.call(this, event); } }; }; if (delegationFn) { delegationFn = wrapFn(delegationFn); } else { handler = wrapFn(handler); } } const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn); const events = getEvent(element); const handlers = events[typeEvent] || (events[typeEvent] = {}); const previousFn = findHandler(handlers, originalHandler, delegation ? handler : null); if (previousFn) { previousFn.oneOff = previousFn.oneOff && oneOff; return; } const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, '')); const fn = delegation ? bootstrapDelegationHandler(element, handler, delegationFn) : bootstrapHandler(element, handler); fn.delegationSelector = delegation ? handler : null; fn.originalHandler = originalHandler; fn.oneOff = oneOff; fn.uidEvent = uid; handlers[uid] = fn; element.addEventListener(typeEvent, fn, delegation); } function removeHandler(element, events, typeEvent, handler, delegationSelector) { const fn = findHandler(events[typeEvent], handler, delegationSelector); if (!fn) { return; } element.removeEventListener(typeEvent, fn, Boolean(delegationSelector)); delete events[typeEvent][fn.uidEvent]; } function removeNamespacedHandlers(element, events, typeEvent, namespace) { const storeElementEvent = events[typeEvent] || {}; Object.keys(storeElementEvent).forEach(handlerKey => { if (handlerKey.includes(namespace)) { const event = storeElementEvent[handlerKey]; removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector); } }); } function getTypeEvent(event) { // allow to get the native events from namespaced events ('click.bs.button' --> 'click') event = event.replace(stripNameRegex, ''); return customEvents[event] || event; } const EventHandler = { on(element, event, handler, delegationFn) { addHandler(element, event, handler, delegationFn, false); }, one(element, event, handler, delegationFn) { addHandler(element, event, handler, delegationFn, true); }, off(element, originalTypeEvent, handler, delegationFn) { if (typeof originalTypeEvent !== 'string' || !element) { return; } const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn); const inNamespace = typeEvent !== originalTypeEvent; const events = getEvent(element); const isNamespace = originalTypeEvent.startsWith('.'); if (typeof originalHandler !== 'undefined') { // Simplest case: handler is passed, remove that listener ONLY. if (!events || !events[typeEvent]) { return; } removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null); return; } if (isNamespace) { Object.keys(events).forEach(elementEvent => { removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1)); }); } const storeElementEvent = events[typeEvent] || {}; Object.keys(storeElementEvent).forEach(keyHandlers => { const handlerKey = keyHandlers.replace(stripUidRegex, ''); if (!inNamespace || originalTypeEvent.includes(handlerKey)) { const event = storeElementEvent[keyHandlers]; removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector); } }); }, trigger(element, event, args) { if (typeof event !== 'string' || !element) { return null; } const $ = getjQuery(); const typeEvent = getTypeEvent(event); const inNamespace = event !== typeEvent; const isNative = nativeEvents.has(typeEvent); let jQueryEvent; let bubbles = true; let nativeDispatch = true; let defaultPrevented = false; let evt = null; if (inNamespace && $) { jQueryEvent = $.Event(event, args); $(element).trigger(jQueryEvent); bubbles = !jQueryEvent.isPropagationStopped(); nativeDispatch = !jQueryEvent.isImmediatePropagationStopped(); defaultPrevented = jQueryEvent.isDefaultPrevented(); } if (isNative) { evt = document.createEvent('HTMLEvents'); evt.initEvent(typeEvent, bubbles, true); } else { evt = new CustomEvent(event, { bubbles, cancelable: true }); } // merge custom information in our event if (typeof args !== 'undefined') { Object.keys(args).forEach(key => { Object.defineProperty(evt, key, { get() { return args[key]; } }); }); } if (defaultPrevented) { evt.preventDefault(); } if (nativeDispatch) { element.dispatchEvent(evt); } if (evt.defaultPrevented && typeof jQueryEvent !== 'undefined') { jQueryEvent.preventDefault(); } return evt; } }; /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): dom/data.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const elementMap = new Map(); var Data = { set(element, key, instance) { if (!elementMap.has(element)) { elementMap.set(element, new Map()); } const instanceMap = elementMap.get(element); // make it clear we only want one instance per element // can be removed later when multiple key/instances are fine to be used if (!instanceMap.has(key) && instanceMap.size !== 0) { // eslint-disable-next-line no-console console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`); return; } instanceMap.set(key, instance); }, get(element, key) { if (elementMap.has(element)) { return elementMap.get(element).get(key) || null; } return null; }, remove(element, key) { if (!elementMap.has(element)) { return; } const instanceMap = elementMap.get(element); instanceMap.delete(key); // free up element references if there are no instances left for an element if (instanceMap.size === 0) { elementMap.delete(element); } } }; /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): base-component.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const VERSION = '5.1.0'; class BaseComponent { constructor(element) { element = getElement(element); if (!element) { return; } this._element = element; Data.set(this._element, this.constructor.DATA_KEY, this); } dispose() { Data.remove(this._element, this.constructor.DATA_KEY); EventHandler.off(this._element, this.constructor.EVENT_KEY); Object.getOwnPropertyNames(this).forEach(propertyName => { this[propertyName] = null; }); } _queueCallback(callback, element, isAnimated = true) { executeAfterTransition(callback, element, isAnimated); } /** Static */ static getInstance(element) { return Data.get(getElement(element), this.DATA_KEY); } static getOrCreateInstance(element, config = {}) { return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null); } static get VERSION() { return VERSION; } static get NAME() { throw new Error('You have to implement the static method "NAME", for each component!'); } static get DATA_KEY() { return `bs.${this.NAME}`; } static get EVENT_KEY() { return `.${this.DATA_KEY}`; } } /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): util/component-functions.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ const enableDismissTrigger = (component, method = 'hide') => { const clickEvent = `click.dismiss${component.EVENT_KEY}`; const name = component.NAME; EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) { if (['A', 'AREA'].includes(this.tagName)) { event.preventDefault(); } if (isDisabled(this)) { return; } const target = getElementFromSelector(this) || this.closest(`.${name}`); const instance = component.getOrCreateInstance(target); // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method instance[method](); }); }; /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): alert.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME$d = 'alert'; const DATA_KEY$c = 'bs.alert'; const EVENT_KEY$c = `.${DATA_KEY$c}`; const EVENT_CLOSE = `close${EVENT_KEY$c}`; const EVENT_CLOSED = `closed${EVENT_KEY$c}`; const CLASS_NAME_FADE$5 = 'fade'; const CLASS_NAME_SHOW$8 = 'show'; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Alert extends BaseComponent { // Getters static get NAME() { return NAME$d; } // Public close() { const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE); if (closeEvent.defaultPrevented) { return; } this._element.classList.remove(CLASS_NAME_SHOW$8); const isAnimated = this._element.classList.contains(CLASS_NAME_FADE$5); this._queueCallback(() => this._destroyElement(), this._element, isAnimated); } // Private _destroyElement() { this._element.remove(); EventHandler.trigger(this._element, EVENT_CLOSED); this.dispose(); } // Static static jQueryInterface(config) { return this.each(function () { const data = Alert.getOrCreateInstance(this); if (typeof config !== 'string') { return; } if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { throw new TypeError(`No method named "${config}"`); } data[config](this); }); } } /** * ------------------------------------------------------------------------ * Data Api implementation * ------------------------------------------------------------------------ */ enableDismissTrigger(Alert, 'close'); /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .Alert to jQuery only if jQuery is present */ defineJQueryPlugin(Alert); /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): button.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME$c = 'button'; const DATA_KEY$b = 'bs.button'; const EVENT_KEY$b = `.${DATA_KEY$b}`; const DATA_API_KEY$7 = '.data-api'; const CLASS_NAME_ACTIVE$3 = 'active'; const SELECTOR_DATA_TOGGLE$5 = '[data-bs-toggle="button"]'; const EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$b}${DATA_API_KEY$7}`; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Button extends BaseComponent { // Getters static get NAME() { return NAME$c; } // Public toggle() { // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE$3)); } // Static static jQueryInterface(config) { return this.each(function () { const data = Button.getOrCreateInstance(this); if (config === 'toggle') { data[config](); } }); } } /** * ------------------------------------------------------------------------ * Data Api implementation * ------------------------------------------------------------------------ */ EventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event => { event.preventDefault(); const button = event.target.closest(SELECTOR_DATA_TOGGLE$5); const data = Button.getOrCreateInstance(button); data.toggle(); }); /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .Button to jQuery only if jQuery is present */ defineJQueryPlugin(Button); /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): dom/manipulator.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ function normalizeData(val) { if (val === 'true') { return true; } if (val === 'false') { return false; } if (val === Number(val).toString()) { return Number(val); } if (val === '' || val === 'null') { return null; } return val; } function normalizeDataKey(key) { return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`); } const Manipulator = { setDataAttribute(element, key, value) { element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value); }, removeDataAttribute(element, key) { element.removeAttribute(`data-bs-${normalizeDataKey(key)}`); }, getDataAttributes(element) { if (!element) { return {}; } const attributes = {}; Object.keys(element.dataset).filter(key => key.startsWith('bs')).forEach(key => { let pureKey = key.replace(/^bs/, ''); pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length); attributes[pureKey] = normalizeData(element.dataset[key]); }); return attributes; }, getDataAttribute(element, key) { return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`)); }, offset(element) { const rect = element.getBoundingClientRect(); return { top: rect.top + window.pageYOffset, left: rect.left + window.pageXOffset }; }, position(element) { return { top: element.offsetTop, left: element.offsetLeft }; } }; /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): dom/selector-engine.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ const NODE_TEXT = 3; const SelectorEngine = { find(selector, element = document.documentElement) { return [].concat(...Element.prototype.querySelectorAll.call(element, selector)); }, findOne(selector, element = document.documentElement) { return Element.prototype.querySelector.call(element, selector); }, children(element, selector) { return [].concat(...element.children).filter(child => child.matches(selector)); }, parents(element, selector) { const parents = []; let ancestor = element.parentNode; while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) { if (ancestor.matches(selector)) { parents.push(ancestor); } ancestor = ancestor.parentNode; } return parents; }, prev(element, selector) { let previous = element.previousElementSibling; while (previous) { if (previous.matches(selector)) { return [previous]; } previous = previous.previousElementSibling; } return []; }, next(element, selector) { let next = element.nextElementSibling; while (next) { if (next.matches(selector)) { return [next]; } next = next.nextElementSibling; } return []; }, focusableChildren(element) { const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector => `${selector}:not([tabindex^="-"])`).join(', '); return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el)); } }; /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): carousel.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME$b = 'carousel'; const DATA_KEY$a = 'bs.carousel'; const EVENT_KEY$a = `.${DATA_KEY$a}`; const DATA_API_KEY$6 = '.data-api'; const ARROW_LEFT_KEY = 'ArrowLeft'; const ARROW_RIGHT_KEY = 'ArrowRight'; const TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch const SWIPE_THRESHOLD = 40; const Default$a = { interval: 5000, keyboard: true, slide: false, pause: 'hover', wrap: true, touch: true }; const DefaultType$a = { interval: '(number|boolean)', keyboard: 'boolean', slide: '(boolean|string)', pause: '(string|boolean)', wrap: 'boolean', touch: 'boolean' }; const ORDER_NEXT = 'next'; const ORDER_PREV = 'prev'; const DIRECTION_LEFT = 'left'; const DIRECTION_RIGHT = 'right'; const KEY_TO_DIRECTION = { [ARROW_LEFT_KEY]: DIRECTION_RIGHT, [ARROW_RIGHT_KEY]: DIRECTION_LEFT }; const EVENT_SLIDE = `slide${EVENT_KEY$a}`; const EVENT_SLID = `slid${EVENT_KEY$a}`; const EVENT_KEYDOWN = `keydown${EVENT_KEY$a}`; const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY$a}`; const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY$a}`; const EVENT_TOUCHSTART = `touchstart${EVENT_KEY$a}`; const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$a}`; const EVENT_TOUCHEND = `touchend${EVENT_KEY$a}`; const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$a}`; const EVENT_POINTERUP = `pointerup${EVENT_KEY$a}`; const EVENT_DRAG_START = `dragstart${EVENT_KEY$a}`; const EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$a}${DATA_API_KEY$6}`; const EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`; const CLASS_NAME_CAROUSEL = 'carousel'; const CLASS_NAME_ACTIVE$2 = 'active'; const CLASS_NAME_SLIDE = 'slide'; const CLASS_NAME_END = 'carousel-item-end'; const CLASS_NAME_START = 'carousel-item-start'; const CLASS_NAME_NEXT = 'carousel-item-next'; const CLASS_NAME_PREV = 'carousel-item-prev'; const CLASS_NAME_POINTER_EVENT = 'pointer-event'; const SELECTOR_ACTIVE$1 = '.active'; const SELECTOR_ACTIVE_ITEM = '.active.carousel-item'; const SELECTOR_ITEM = '.carousel-item'; const SELECTOR_ITEM_IMG = '.carousel-item img'; const SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev'; const SELECTOR_INDICATORS = '.carousel-indicators'; const SELECTOR_INDICATOR = '[data-bs-target]'; const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'; const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]'; const POINTER_TYPE_TOUCH = 'touch'; const POINTER_TYPE_PEN = 'pen'; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Carousel extends BaseComponent { constructor(element, config) { super(element); this._items = null; this._interval = null; this._activeElement = null; this._isPaused = false; this._isSliding = false; this.touchTimeout = null; this.touchStartX = 0; this.touchDeltaX = 0; this._config = this._getConfig(config); this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element); this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0; this._pointerEvent = Boolean(window.PointerEvent); this._addEventListeners(); } // Getters static get Default() { return Default$a; } static get NAME() { return NAME$b; } // Public next() { this._slide(ORDER_NEXT); } nextWhenVisible() { // Don't call next when the page isn't visible // or the carousel or its parent isn't visible if (!document.hidden && isVisible(this._element)) { this.next(); } } prev() { this._slide(ORDER_PREV); } pause(event) { if (!event) { this._isPaused = true; } if (SelectorEngine.findOne(SELECTOR_NEXT_PREV, this._element)) { triggerTransitionEnd(this._element); this.cycle(true); } clearInterval(this._interval); this._interval = null; } cycle(event) { if (!event) { this._isPaused = false; } if (this._interval) { clearInterval(this._interval); this._interval = null; } if (this._config && this._config.interval && !this._isPaused) { this._updateInterval(); this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval); } } to(index) { this._activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element); const activeIndex = this._getItemIndex(this._activeElement); if (index > this._items.length - 1 || index < 0) { return; } if (this._isSliding) { EventHandler.one(this._element, EVENT_SLID, () => this.to(index)); return; } if (activeIndex === index) { this.pause(); this.cycle(); return; } const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV; this._slide(order, this._items[index]); } // Private _getConfig(config) { config = { ...Default$a, ...Manipulator.getDataAttributes(this._element), ...(typeof config === 'object' ? config : {}) }; typeCheckConfig(NAME$b, config, DefaultType$a); return config; } _handleSwipe() { const absDeltax = Math.abs(this.touchDeltaX); if (absDeltax <= SWIPE_THRESHOLD) { return; } const direction = absDeltax / this.touchDeltaX; this.touchDeltaX = 0; if (!direction) { return; } this._slide(direction > 0 ? DIRECTION_RIGHT : DIRECTION_LEFT); } _addEventListeners() { if (this._config.keyboard) { EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event)); } if (this._config.pause === 'hover') { EventHandler.on(this._element, EVENT_MOUSEENTER, event => this.pause(event)); EventHandler.on(this._element, EVENT_MOUSELEAVE, event => this.cycle(event)); } if (this._config.touch && this._touchSupported) { this._addTouchEventListeners(); } } _addTouchEventListeners() { const start = event => { if (this._pointerEvent && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)) { this.touchStartX = event.clientX; } else if (!this._pointerEvent) { this.touchStartX = event.touches[0].clientX; } }; const move = event => { // ensure swiping with one touch and not pinching this.touchDeltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this.touchStartX; }; const end = event => { if (this._pointerEvent && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)) { this.touchDeltaX = event.clientX - this.touchStartX; } this._handleSwipe(); if (this._config.pause === 'hover') { // If it's a touch-enabled device, mouseenter/leave are fired as // part of the mouse compatibility events on first tap - the carousel // would stop cycling until user tapped out of it; // here, we listen for touchend, explicitly pause the carousel // (as if it's the second time we tap on it, mouseenter compat event // is NOT fired) and after a timeout (to allow for mouse compatibility // events to fire) we explicitly restart cycling this.pause(); if (this.touchTimeout) { clearTimeout(this.touchTimeout); } this.touchTimeout = setTimeout(event => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval); } }; SelectorEngine.find(SELECTOR_ITEM_IMG, this._element).forEach(itemImg => { EventHandler.on(itemImg, EVENT_DRAG_START, e => e.preventDefault()); }); if (this._pointerEvent) { EventHandler.on(this._element, EVENT_POINTERDOWN, event => start(event)); EventHandler.on(this._element, EVENT_POINTERUP, event => end(event)); this._element.classList.add(CLASS_NAME_POINTER_EVENT); } else { EventHandler.on(this._element, EVENT_TOUCHSTART, event => start(event)); EventHandler.on(this._element, EVENT_TOUCHMOVE, event => move(event)); EventHandler.on(this._element, EVENT_TOUCHEND, event => end(event)); } } _keydown(event) { if (/input|textarea/i.test(event.target.tagName)) { return; } const direction = KEY_TO_DIRECTION[event.key]; if (direction) { event.preventDefault(); this._slide(direction); } } _getItemIndex(element) { this._items = element && element.parentNode ? SelectorEngine.find(SELECTOR_ITEM, element.parentNode) : []; return this._items.indexOf(element); } _getItemByOrder(order, activeElement) { const isNext = order === ORDER_NEXT; return getNextActiveElement(this._items, activeElement, isNext, this._config.wrap); } _triggerSlideEvent(relatedTarget, eventDirectionName) { const targetIndex = this._getItemIndex(relatedTarget); const fromIndex = this._getItemIndex(SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)); return EventHandler.trigger(this._element, EVENT_SLIDE, { relatedTarget, direction: eventDirectionName, from: fromIndex, to: targetIndex }); } _setActiveIndicatorElement(element) { if (this._indicatorsElement) { const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE$1, this._indicatorsElement); activeIndicator.classList.remove(CLASS_NAME_ACTIVE$2); activeIndicator.removeAttribute('aria-current'); const indicators = SelectorEngine.find(SELECTOR_INDICATOR, this._indicatorsElement); for (let i = 0; i < indicators.length; i++) { if (Number.parseInt(indicators[i].getAttribute('data-bs-slide-to'), 10) === this._getItemIndex(element)) { indicators[i].classList.add(CLASS_NAME_ACTIVE$2); indicators[i].setAttribute('aria-current', 'true'); break; } } } } _updateInterval() { const element = this._activeElement || SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element); if (!element) { return; } const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10); if (elementInterval) { this._config.defaultInterval = this._config.defaultInterval || this._config.interval; this._config.interval = elementInterval; } else { this._config.interval = this._config.defaultInterval || this._config.interval; } } _slide(directionOrOrder, element) { const order = this._directionToOrder(directionOrOrder); const activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element); const activeElementIndex = this._getItemIndex(activeElement); const nextElement = element || this._getItemByOrder(order, activeElement); const nextElementIndex = this._getItemIndex(nextElement); const isCycling = Boolean(this._interval); const isNext = order === ORDER_NEXT; const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END; const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV; const eventDirectionName = this._orderToDirection(order); if (nextElement && nextElement.classList.contains(CLASS_NAME_ACTIVE$2)) { this._isSliding = false; return; } if (this._isSliding) { return; } const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName); if (slideEvent.defaultPrevented) { return; } if (!activeElement || !nextElement) { // Some weirdness is happening, so we bail return; } this._isSliding = true; if (isCycling) { this.pause(); } this._setActiveIndicatorElement(nextElement); this._activeElement = nextElement; const triggerSlidEvent = () => { EventHandler.trigger(this._element, EVENT_SLID, { relatedTarget: nextElement, direction: eventDirectionName, from: activeElementIndex, to: nextElementIndex }); }; if (this._element.classList.contains(CLASS_NAME_SLIDE)) { nextElement.classList.add(orderClassName); reflow(nextElement); activeElement.classList.add(directionalClassName); nextElement.classList.add(directionalClassName); const completeCallBack = () => { nextElement.classList.remove(directionalClassName, orderClassName); nextElement.classList.add(CLASS_NAME_ACTIVE$2); activeElement.classList.remove(CLASS_NAME_ACTIVE$2, orderClassName, directionalClassName); this._isSliding = false; setTimeout(triggerSlidEvent, 0); }; this._queueCallback(completeCallBack, activeElement, true); } else { activeElement.classList.remove(CLASS_NAME_ACTIVE$2); nextElement.classList.add(CLASS_NAME_ACTIVE$2); this._isSliding = false; triggerSlidEvent(); } if (isCycling) { this.cycle(); } } _directionToOrder(direction) { if (![DIRECTION_RIGHT, DIRECTION_LEFT].includes(direction)) { return direction; } if (isRTL()) { return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT; } return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV; } _orderToDirection(order) { if (![ORDER_NEXT, ORDER_PREV].includes(order)) { return order; } if (isRTL()) { return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT; } return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT; } // Static static carouselInterface(element, config) { const data = Carousel.getOrCreateInstance(element, config); let { _config } = data; if (typeof config === 'object') { _config = { ..._config, ...config }; } const action = typeof config === 'string' ? config : _config.slide; if (typeof config === 'number') { data.to(config); } else if (typeof action === 'string') { if (typeof data[action] === 'undefined') { throw new TypeError(`No method named "${action}"`); } data[action](); } else if (_config.interval && _config.ride) { data.pause(); data.cycle(); } } static jQueryInterface(config) { return this.each(function () { Carousel.carouselInterface(this, config); }); } static dataApiClickHandler(event) { const target = getElementFromSelector(this); if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) { return; } const config = { ...Manipulator.getDataAttributes(target), ...Manipulator.getDataAttributes(this) }; const slideIndex = this.getAttribute('data-bs-slide-to'); if (slideIndex) { config.interval = false; } Carousel.carouselInterface(target, config); if (slideIndex) { Carousel.getInstance(target).to(slideIndex); } event.preventDefault(); } } /** * ------------------------------------------------------------------------ * Data Api implementation * ------------------------------------------------------------------------ */ EventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_SLIDE, Carousel.dataApiClickHandler); EventHandler.on(window, EVENT_LOAD_DATA_API$2, () => { const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE); for (let i = 0, len = carousels.length; i < len; i++) { Carousel.carouselInterface(carousels[i], Carousel.getInstance(carousels[i])); } }); /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .Carousel to jQuery only if jQuery is present */ defineJQueryPlugin(Carousel); /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): collapse.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME$a = 'collapse'; const DATA_KEY$9 = 'bs.collapse'; const EVENT_KEY$9 = `.${DATA_KEY$9}`; const DATA_API_KEY$5 = '.data-api'; const Default$9 = { toggle: true, parent: null }; const DefaultType$9 = { toggle: 'boolean', parent: '(null|element)' }; const EVENT_SHOW$5 = `show${EVENT_KEY$9}`; const EVENT_SHOWN$5 = `shown${EVENT_KEY$9}`; const EVENT_HIDE$5 = `hide${EVENT_KEY$9}`; const EVENT_HIDDEN$5 = `hidden${EVENT_KEY$9}`; const EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$9}${DATA_API_KEY$5}`; const CLASS_NAME_SHOW$7 = 'show'; const CLASS_NAME_COLLAPSE = 'collapse'; const CLASS_NAME_COLLAPSING = 'collapsing'; const CLASS_NAME_COLLAPSED = 'collapsed'; const CLASS_NAME_HORIZONTAL = 'collapse-horizontal'; const WIDTH = 'width'; const HEIGHT = 'height'; const SELECTOR_ACTIVES = '.show, .collapsing'; const SELECTOR_DATA_TOGGLE$4 = '[data-bs-toggle="collapse"]'; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Collapse extends BaseComponent { constructor(element, config) { super(element); this._isTransitioning = false; this._config = this._getConfig(config); this._triggerArray = []; const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$4); for (let i = 0, len = toggleList.length; i < len; i++) { const elem = toggleList[i]; const selector = getSelectorFromElement(elem); const filterElement = SelectorEngine.find(selector).filter(foundElem => foundElem === this._element); if (selector !== null && filterElement.length) { this._selector = selector; this._triggerArray.push(elem); } } this._initializeChildren(); if (!this._config.parent) { this._addAriaAndCollapsedClass(this._triggerArray, this._isShown()); } if (this._config.toggle) { this.toggle(); } } // Getters static get Default() { return Default$9; } static get NAME() { return NAME$a; } // Public toggle() { if (this._isShown()) { this.hide(); } else { this.show(); } } show() { if (this._isTransitioning || this._isShown()) { return; } let actives = []; let activesData; if (this._config.parent) { const children = SelectorEngine.find(`.${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`, this._config.parent); actives = SelectorEngine.find(SELECTOR_ACTIVES, this._config.parent).filter(elem => !children.includes(elem)); // remove children if greater depth } const container = SelectorEngine.findOne(this._selector); if (actives.length) { const tempActiveData = actives.find(elem => container !== elem); activesData = tempActiveData ? Collapse.getInstance(tempActiveData) : null; if (activesData && activesData._isTransitioning) { return; } } const startEvent = EventHandler.trigger(this._element, EVENT_SHOW$5); if (startEvent.defaultPrevented) { return; } actives.forEach(elemActive => { if (container !== elemActive) { Collapse.getOrCreateInstance(elemActive, { toggle: false }).hide(); } if (!activesData) { Data.set(elemActive, DATA_KEY$9, null); } }); const dimension = this._getDimension(); this._element.classList.remove(CLASS_NAME_COLLAPSE); this._element.classList.add(CLASS_NAME_COLLAPSING); this._element.style[dimension] = 0; this._addAriaAndCollapsedClass(this._triggerArray, true); this._isTransitioning = true; const complete = () => { this._isTransitioning = false; this._element.classList.remove(CLASS_NAME_COLLAPSING); this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7); this._element.style[dimension] = ''; EventHandler.trigger(this._element, EVENT_SHOWN$5); }; const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); const scrollSize = `scroll${capitalizedDimension}`; this._queueCallback(complete, this._element, true); this._element.style[dimension] = `${this._element[scrollSize]}px`; } hide() { if (this._isTransitioning || !this._isShown()) { return; } const startEvent = EventHandler.trigger(this._element, EVENT_HIDE$5); if (startEvent.defaultPrevented) { return; } const dimension = this._getDimension(); this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`; reflow(this._element); this._element.classList.add(CLASS_NAME_COLLAPSING); this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7); const triggerArrayLength = this._triggerArray.length; for (let i = 0; i < triggerArrayLength; i++) { const trigger = this._triggerArray[i]; const elem = getElementFromSelector(trigger); if (elem && !this._isShown(elem)) { this._addAriaAndCollapsedClass([trigger], false); } } this._isTransitioning = true; const complete = () => { this._isTransitioning = false; this._element.classList.remove(CLASS_NAME_COLLAPSING); this._element.classList.add(CLASS_NAME_COLLAPSE); EventHandler.trigger(this._element, EVENT_HIDDEN$5); }; this._element.style[dimension] = ''; this._queueCallback(complete, this._element, true); } _isShown(element = this._element) { return element.classList.contains(CLASS_NAME_SHOW$7); } // Private _getConfig(config) { config = { ...Default$9, ...Manipulator.getDataAttributes(this._element), ...config }; config.toggle = Boolean(config.toggle); // Coerce string values config.parent = getElement(config.parent); typeCheckConfig(NAME$a, config, DefaultType$9); return config; } _getDimension() { return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT; } _initializeChildren() { if (!this._config.parent) { return; } const children = SelectorEngine.find(`.${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`, this._config.parent); SelectorEngine.find(SELECTOR_DATA_TOGGLE$4, this._config.parent).filter(elem => !children.includes(elem)).forEach(element => { const selected = getElementFromSelector(element); if (selected) { this._addAriaAndCollapsedClass([element], this._isShown(selected)); } }); } _addAriaAndCollapsedClass(triggerArray, isOpen) { if (!triggerArray.length) { return; } triggerArray.forEach(elem => { if (isOpen) { elem.classList.remove(CLASS_NAME_COLLAPSED); } else { elem.classList.add(CLASS_NAME_COLLAPSED); } elem.setAttribute('aria-expanded', isOpen); }); } // Static static jQueryInterface(config) { return this.each(function () { const _config = {}; if (typeof config === 'string' && /show|hide/.test(config)) { _config.toggle = false; } const data = Collapse.getOrCreateInstance(this, _config); if (typeof config === 'string') { if (typeof data[config] === 'undefined') { throw new TypeError(`No method named "${config}"`); } data[config](); } }); } } /** * ------------------------------------------------------------------------ * Data Api implementation * ------------------------------------------------------------------------ */ EventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, function (event) { // preventDefault only for elements (which change the URL) not inside the collapsible element if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') { event.preventDefault(); } const selector = getSelectorFromElement(this); const selectorElements = SelectorEngine.find(selector); selectorElements.forEach(element => { Collapse.getOrCreateInstance(element, { toggle: false }).toggle(); }); }); /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .Collapse to jQuery only if jQuery is present */ defineJQueryPlugin(Collapse); var top = 'top'; var bottom = 'bottom'; var right = 'right'; var left = 'left'; var auto = 'auto'; var basePlacements = [top, bottom, right, left]; var start = 'start'; var end = 'end'; var clippingParents = 'clippingParents'; var viewport = 'viewport'; var popper = 'popper'; var reference = 'reference'; var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) { return acc.concat([placement + "-" + start, placement + "-" + end]); }, []); var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) { return acc.concat([placement, placement + "-" + start, placement + "-" + end]); }, []); // modifiers that need to read the DOM var beforeRead = 'beforeRead'; var read = 'read'; var afterRead = 'afterRead'; // pure-logic modifiers var beforeMain = 'beforeMain'; var main = 'main'; var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state) var beforeWrite = 'beforeWrite'; var write = 'write'; var afterWrite = 'afterWrite'; var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite]; function getNodeName(element) { return element ? (element.nodeName || '').toLowerCase() : null; } function getWindow(node) { if (node == null) { return window; } if (node.toString() !== '[object Window]') { var ownerDocument = node.ownerDocument; return ownerDocument ? ownerDocument.defaultView || window : window; } return node; } function isElement(node) { var OwnElement = getWindow(node).Element; return node instanceof OwnElement || node instanceof Element; } function isHTMLElement(node) { var OwnElement = getWindow(node).HTMLElement; return node instanceof OwnElement || node instanceof HTMLElement; } function isShadowRoot(node) { // IE 11 has no ShadowRoot if (typeof ShadowRoot === 'undefined') { return false; } var OwnElement = getWindow(node).ShadowRoot; return node instanceof OwnElement || node instanceof ShadowRoot; } // and applies them to the HTMLElements such as popper and arrow function applyStyles(_ref) { var state = _ref.state; Object.keys(state.elements).forEach(function (name) { var style = state.styles[name] || {}; var attributes = state.attributes[name] || {}; var element = state.elements[name]; // arrow is optional + virtual elements if (!isHTMLElement(element) || !getNodeName(element)) { return; } // Flow doesn't support to extend this property, but it's the most // effective way to apply styles to an HTMLElement // $FlowFixMe[cannot-write] Object.assign(element.style, style); Object.keys(attributes).forEach(function (name) { var value = attributes[name]; if (value === false) { element.removeAttribute(name); } else { element.setAttribute(name, value === true ? '' : value); } }); }); } function effect$2(_ref2) { var state = _ref2.state; var initialStyles = { popper: { position: state.options.strategy, left: '0', top: '0', margin: '0' }, arrow: { position: 'absolute' }, reference: {} }; Object.assign(state.elements.popper.style, initialStyles.popper); state.styles = initialStyles; if (state.elements.arrow) { Object.assign(state.elements.arrow.style, initialStyles.arrow); } return function () { Object.keys(state.elements).forEach(function (name) { var element = state.elements[name]; var attributes = state.attributes[name] || {}; var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them var style = styleProperties.reduce(function (style, property) { style[property] = ''; return style; }, {}); // arrow is optional + virtual elements if (!isHTMLElement(element) || !getNodeName(element)) { return; } Object.assign(element.style, style); Object.keys(attributes).forEach(function (attribute) { element.removeAttribute(attribute); }); }); }; } // eslint-disable-next-line import/no-unused-modules var applyStyles$1 = { name: 'applyStyles', enabled: true, phase: 'write', fn: applyStyles, effect: effect$2, requires: ['computeStyles'] }; function getBasePlacement(placement) { return placement.split('-')[0]; } var round$1 = Math.round; function getBoundingClientRect(element, includeScale) { if (includeScale === void 0) { includeScale = false; } var rect = element.getBoundingClientRect(); var scaleX = 1; var scaleY = 1; if (isHTMLElement(element) && includeScale) { // Fallback to 1 in case both values are `0` scaleX = rect.width / element.offsetWidth || 1; scaleY = rect.height / element.offsetHeight || 1; } return { width: round$1(rect.width / scaleX), height: round$1(rect.height / scaleY), top: round$1(rect.top / scaleY), right: round$1(rect.right / scaleX), bottom: round$1(rect.bottom / scaleY), left: round$1(rect.left / scaleX), x: round$1(rect.left / scaleX), y: round$1(rect.top / scaleY) }; } // means it doesn't take into account transforms. function getLayoutRect(element) { var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed. // Fixes https://github.com/popperjs/popper-core/issues/1223 var width = element.offsetWidth; var height = element.offsetHeight; if (Math.abs(clientRect.width - width) <= 1) { width = clientRect.width; } if (Math.abs(clientRect.height - height) <= 1) { height = clientRect.height; } return { x: element.offsetLeft, y: element.offsetTop, width: width, height: height }; } function contains(parent, child) { var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method if (parent.contains(child)) { return true; } // then fallback to custom implementation with Shadow DOM support else if (rootNode && isShadowRoot(rootNode)) { var next = child; do { if (next && parent.isSameNode(next)) { return true; } // $FlowFixMe[prop-missing]: need a better way to handle this... next = next.parentNode || next.host; } while (next); } // Give up, the result is false return false; } function getComputedStyle$1(element) { return getWindow(element).getComputedStyle(element); } function isTableElement(element) { return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0; } function getDocumentElement(element) { // $FlowFixMe[incompatible-return]: assume body is always available return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing] element.document) || window.document).documentElement; } function getParentNode(element) { if (getNodeName(element) === 'html') { return element; } return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle // $FlowFixMe[incompatible-return] // $FlowFixMe[prop-missing] element.assignedSlot || // step into the shadow DOM of the parent of a slotted node element.parentNode || ( // DOM Element detected isShadowRoot(element) ? element.host : null) || // ShadowRoot detected // $FlowFixMe[incompatible-call]: HTMLElement is a Node getDocumentElement(element) // fallback ); } function getTrueOffsetParent(element) { if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837 getComputedStyle$1(element).position === 'fixed') { return null; } return element.offsetParent; } // `.offsetParent` reports `null` for fixed elements, while absolute elements // return the containing block function getContainingBlock(element) { var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') !== -1; var isIE = navigator.userAgent.indexOf('Trident') !== -1; if (isIE && isHTMLElement(element)) { // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport var elementCss = getComputedStyle$1(element); if (elementCss.position === 'fixed') { return null; } } var currentNode = getParentNode(element); while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) { var css = getComputedStyle$1(currentNode); // This is non-exhaustive but covers the most common CSS properties that // create a containing block. // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') { return currentNode; } else { currentNode = currentNode.parentNode; } } return null; } // Gets the closest ancestor positioned element. Handles some edge cases, // such as table ancestors and cross browser bugs. function getOffsetParent(element) { var window = getWindow(element); var offsetParent = getTrueOffsetParent(element); while (offsetParent && isTableElement(offsetParent) && getComputedStyle$1(offsetParent).position === 'static') { offsetParent = getTrueOffsetParent(offsetParent); } if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle$1(offsetParent).position === 'static')) { return window; } return offsetParent || getContainingBlock(element) || window; } function getMainAxisFromPlacement(placement) { return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y'; } var max = Math.max; var min = Math.min; var round = Math.round; function within(min$1, value, max$1) { return max(min$1, min(value, max$1)); } function getFreshSideObject() { return { top: 0, right: 0, bottom: 0, left: 0 }; } function mergePaddingObject(paddingObject) { return Object.assign({}, getFreshSideObject(), paddingObject); } function expandToHashMap(value, keys) { return keys.reduce(function (hashMap, key) { hashMap[key] = value; return hashMap; }, {}); } var toPaddingObject = function toPaddingObject(padding, state) { padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, { placement: state.placement })) : padding; return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements)); }; function arrow(_ref) { var _state$modifiersData$; var state = _ref.state, name = _ref.name, options = _ref.options; var arrowElement = state.elements.arrow; var popperOffsets = state.modifiersData.popperOffsets; var basePlacement = getBasePlacement(state.placement); var axis = getMainAxisFromPlacement(basePlacement); var isVertical = [left, right].indexOf(basePlacement) >= 0; var len = isVertical ? 'height' : 'width'; if (!arrowElement || !popperOffsets) { return; } var paddingObject = toPaddingObject(options.padding, state); var arrowRect = getLayoutRect(arrowElement); var minProp = axis === 'y' ? top : left; var maxProp = axis === 'y' ? bottom : right; var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len]; var startDiff = popperOffsets[axis] - state.rects.reference[axis]; var arrowOffsetParent = getOffsetParent(arrowElement); var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0; var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is // outside of the popper bounds var min = paddingObject[minProp]; var max = clientSize - arrowRect[len] - paddingObject[maxProp]; var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference; var offset = within(min, center, max); // Prevents breaking syntax highlighting... var axisProp = axis; state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$); } function effect$1(_ref2) { var state = _ref2.state, options = _ref2.options; var _options$element = options.element, arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element; if (arrowElement == null) { return; } // CSS selector if (typeof arrowElement === 'string') { arrowElement = state.elements.popper.querySelector(arrowElement); if (!arrowElement) { return; } } if (!contains(state.elements.popper, arrowElement)) { return; } state.elements.arrow = arrowElement; } // eslint-disable-next-line import/no-unused-modules var arrow$1 = { name: 'arrow', enabled: true, phase: 'main', fn: arrow, effect: effect$1, requires: ['popperOffsets'], requiresIfExists: ['preventOverflow'] }; var unsetSides = { top: 'auto', right: 'auto', bottom: 'auto', left: 'auto' }; // Round the offsets to the nearest suitable subpixel based on the DPR. // Zooming can change the DPR, but it seems to report a value that will // cleanly divide the values into the appropriate subpixels. function roundOffsetsByDPR(_ref) { var x = _ref.x, y = _ref.y; var win = window; var dpr = win.devicePixelRatio || 1; return { x: round(round(x * dpr) / dpr) || 0, y: round(round(y * dpr) / dpr) || 0 }; } function mapToStyles(_ref2) { var _Object$assign2; var popper = _ref2.popper, popperRect = _ref2.popperRect, placement = _ref2.placement, offsets = _ref2.offsets, position = _ref2.position, gpuAcceleration = _ref2.gpuAcceleration, adaptive = _ref2.adaptive, roundOffsets = _ref2.roundOffsets; var _ref3 = roundOffsets === true ? roundOffsetsByDPR(offsets) : typeof roundOffsets === 'function' ? roundOffsets(offsets) : offsets, _ref3$x = _ref3.x, x = _ref3$x === void 0 ? 0 : _ref3$x, _ref3$y = _ref3.y, y = _ref3$y === void 0 ? 0 : _ref3$y; var hasX = offsets.hasOwnProperty('x'); var hasY = offsets.hasOwnProperty('y'); var sideX = left; var sideY = top; var win = window; if (adaptive) { var offsetParent = getOffsetParent(popper); var heightProp = 'clientHeight'; var widthProp = 'clientWidth'; if (offsetParent === getWindow(popper)) { offsetParent = getDocumentElement(popper); if (getComputedStyle$1(offsetParent).position !== 'static') { heightProp = 'scrollHeight'; widthProp = 'scrollWidth'; } } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it offsetParent = offsetParent; if (placement === top) { sideY = bottom; // $FlowFixMe[prop-missing] y -= offsetParent[heightProp] - popperRect.height; y *= gpuAcceleration ? 1 : -1; } if (placement === left) { sideX = right; // $FlowFixMe[prop-missing] x -= offsetParent[widthProp] - popperRect.width; x *= gpuAcceleration ? 1 : -1; } } var commonStyles = Object.assign({ position: position }, adaptive && unsetSides); if (gpuAcceleration) { var _Object$assign; return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) < 2 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign)); } return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2)); } function computeStyles(_ref4) { var state = _ref4.state, options = _ref4.options; var _options$gpuAccelerat = options.gpuAcceleration, gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat, _options$adaptive = options.adaptive, adaptive = _options$adaptive === void 0 ? true : _options$adaptive, _options$roundOffsets = options.roundOffsets, roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets; var commonStyles = { placement: getBasePlacement(state.placement), popper: state.elements.popper, popperRect: state.rects.popper, gpuAcceleration: gpuAcceleration }; if (state.modifiersData.popperOffsets != null) { state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, { offsets: state.modifiersData.popperOffsets, position: state.options.strategy, adaptive: adaptive, roundOffsets: roundOffsets }))); } if (state.modifiersData.arrow != null) { state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, { offsets: state.modifiersData.arrow, position: 'absolute', adaptive: false, roundOffsets: roundOffsets }))); } state.attributes.popper = Object.assign({}, state.attributes.popper, { 'data-popper-placement': state.placement }); } // eslint-disable-next-line import/no-unused-modules var computeStyles$1 = { name: 'computeStyles', enabled: true, phase: 'beforeWrite', fn: computeStyles, data: {} }; var passive = { passive: true }; function effect(_ref) { var state = _ref.state, instance = _ref.instance, options = _ref.options; var _options$scroll = options.scroll, scroll = _options$scroll === void 0 ? true : _options$scroll, _options$resize = options.resize, resize = _options$resize === void 0 ? true : _options$resize; var window = getWindow(state.elements.popper); var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper); if (scroll) { scrollParents.forEach(function (scrollParent) { scrollParent.addEventListener('scroll', instance.update, passive); }); } if (resize) { window.addEventListener('resize', instance.update, passive); } return function () { if (scroll) { scrollParents.forEach(function (scrollParent) { scrollParent.removeEventListener('scroll', instance.update, passive); }); } if (resize) { window.removeEventListener('resize', instance.update, passive); } }; } // eslint-disable-next-line import/no-unused-modules var eventListeners = { name: 'eventListeners', enabled: true, phase: 'write', fn: function fn() {}, effect: effect, data: {} }; var hash$1 = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' }; function getOppositePlacement(placement) { return placement.replace(/left|right|bottom|top/g, function (matched) { return hash$1[matched]; }); } var hash = { start: 'end', end: 'start' }; function getOppositeVariationPlacement(placement) { return placement.replace(/start|end/g, function (matched) { return hash[matched]; }); } function getWindowScroll(node) { var win = getWindow(node); var scrollLeft = win.pageXOffset; var scrollTop = win.pageYOffset; return { scrollLeft: scrollLeft, scrollTop: scrollTop }; } function getWindowScrollBarX(element) { // If has a CSS width greater than the viewport, then this will be // incorrect for RTL. // Popper 1 is broken in this case and never had a bug report so let's assume // it's not an issue. I don't think anyone ever specifies width on // anyway. // Browsers where the left scrollbar doesn't cause an issue report `0` for // this (e.g. Edge 2019, IE11, Safari) return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft; } function getViewportRect(element) { var win = getWindow(element); var html = getDocumentElement(element); var visualViewport = win.visualViewport; var width = html.clientWidth; var height = html.clientHeight; var x = 0; var y = 0; // NB: This isn't supported on iOS <= 12. If the keyboard is open, the popper // can be obscured underneath it. // Also, `html.clientHeight` adds the bottom bar height in Safari iOS, even // if it isn't open, so if this isn't available, the popper will be detected // to overflow the bottom of the screen too early. if (visualViewport) { width = visualViewport.width; height = visualViewport.height; // Uses Layout Viewport (like Chrome; Safari does not currently) // In Chrome, it returns a value very close to 0 (+/-) but contains rounding // errors due to floating point numbers, so we need to check precision. // Safari returns a number <= 0, usually < -1 when pinch-zoomed // Feature detection fails in mobile emulation mode in Chrome. // Math.abs(win.innerWidth / visualViewport.scale - visualViewport.width) < // 0.001 // Fallback here: "Not Safari" userAgent if (!/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { x = visualViewport.offsetLeft; y = visualViewport.offsetTop; } } return { width: width, height: height, x: x + getWindowScrollBarX(element), y: y }; } // of the `` and `` rect bounds if horizontally scrollable function getDocumentRect(element) { var _element$ownerDocumen; var html = getDocumentElement(element); var winScroll = getWindowScroll(element); var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body; var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0); var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0); var x = -winScroll.scrollLeft + getWindowScrollBarX(element); var y = -winScroll.scrollTop; if (getComputedStyle$1(body || html).direction === 'rtl') { x += max(html.clientWidth, body ? body.clientWidth : 0) - width; } return { width: width, height: height, x: x, y: y }; } function isScrollParent(element) { // Firefox wants us to check `-x` and `-y` variations as well var _getComputedStyle = getComputedStyle$1(element), overflow = _getComputedStyle.overflow, overflowX = _getComputedStyle.overflowX, overflowY = _getComputedStyle.overflowY; return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX); } function getScrollParent(node) { if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) { // $FlowFixMe[incompatible-return]: assume body is always available return node.ownerDocument.body; } if (isHTMLElement(node) && isScrollParent(node)) { return node; } return getScrollParent(getParentNode(node)); } /* given a DOM element, return the list of all scroll parents, up the list of ancesors until we get to the top window object. This list is what we attach scroll listeners to, because if any of these parent elements scroll, we'll need to re-calculate the reference element's position. */ function listScrollParents(element, list) { var _element$ownerDocumen; if (list === void 0) { list = []; } var scrollParent = getScrollParent(element); var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body); var win = getWindow(scrollParent); var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent; var updatedList = list.concat(target); return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here updatedList.concat(listScrollParents(getParentNode(target))); } function rectToClientRect(rect) { return Object.assign({}, rect, { left: rect.x, top: rect.y, right: rect.x + rect.width, bottom: rect.y + rect.height }); } function getInnerBoundingClientRect(element) { var rect = getBoundingClientRect(element); rect.top = rect.top + element.clientTop; rect.left = rect.left + element.clientLeft; rect.bottom = rect.top + element.clientHeight; rect.right = rect.left + element.clientWidth; rect.width = element.clientWidth; rect.height = element.clientHeight; rect.x = rect.left; rect.y = rect.top; return rect; } function getClientRectFromMixedType(element, clippingParent) { return clippingParent === viewport ? rectToClientRect(getViewportRect(element)) : isHTMLElement(clippingParent) ? getInnerBoundingClientRect(clippingParent) : rectToClientRect(getDocumentRect(getDocumentElement(element))); } // A "clipping parent" is an overflowable container with the characteristic of // clipping (or hiding) overflowing elements with a position different from // `initial` function getClippingParents(element) { var clippingParents = listScrollParents(getParentNode(element)); var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle$1(element).position) >= 0; var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element; if (!isElement(clipperElement)) { return []; } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414 return clippingParents.filter(function (clippingParent) { return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body'; }); } // Gets the maximum area that the element is visible in due to any number of // clipping parents function getClippingRect(element, boundary, rootBoundary) { var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary); var clippingParents = [].concat(mainClippingParents, [rootBoundary]); var firstClippingParent = clippingParents[0]; var clippingRect = clippingParents.reduce(function (accRect, clippingParent) { var rect = getClientRectFromMixedType(element, clippingParent); accRect.top = max(rect.top, accRect.top); accRect.right = min(rect.right, accRect.right); accRect.bottom = min(rect.bottom, accRect.bottom); accRect.left = max(rect.left, accRect.left); return accRect; }, getClientRectFromMixedType(element, firstClippingParent)); clippingRect.width = clippingRect.right - clippingRect.left; clippingRect.height = clippingRect.bottom - clippingRect.top; clippingRect.x = clippingRect.left; clippingRect.y = clippingRect.top; return clippingRect; } function getVariation(placement) { return placement.split('-')[1]; } function computeOffsets(_ref) { var reference = _ref.reference, element = _ref.element, placement = _ref.placement; var basePlacement = placement ? getBasePlacement(placement) : null; var variation = placement ? getVariation(placement) : null; var commonX = reference.x + reference.width / 2 - element.width / 2; var commonY = reference.y + reference.height / 2 - element.height / 2; var offsets; switch (basePlacement) { case top: offsets = { x: commonX, y: reference.y - element.height }; break; case bottom: offsets = { x: commonX, y: reference.y + reference.height }; break; case right: offsets = { x: reference.x + reference.width, y: commonY }; break; case left: offsets = { x: reference.x - element.width, y: commonY }; break; default: offsets = { x: reference.x, y: reference.y }; } var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null; if (mainAxis != null) { var len = mainAxis === 'y' ? 'height' : 'width'; switch (variation) { case start: offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2); break; case end: offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2); break; } } return offsets; } function detectOverflow(state, options) { if (options === void 0) { options = {}; } var _options = options, _options$placement = _options.placement, placement = _options$placement === void 0 ? state.placement : _options$placement, _options$boundary = _options.boundary, boundary = _options$boundary === void 0 ? clippingParents : _options$boundary, _options$rootBoundary = _options.rootBoundary, rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary, _options$elementConte = _options.elementContext, elementContext = _options$elementConte === void 0 ? popper : _options$elementConte, _options$altBoundary = _options.altBoundary, altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary, _options$padding = _options.padding, padding = _options$padding === void 0 ? 0 : _options$padding; var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements)); var altContext = elementContext === popper ? reference : popper; var referenceElement = state.elements.reference; var popperRect = state.rects.popper; var element = state.elements[altBoundary ? altContext : elementContext]; var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary); var referenceClientRect = getBoundingClientRect(referenceElement); var popperOffsets = computeOffsets({ reference: referenceClientRect, element: popperRect, strategy: 'absolute', placement: placement }); var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets)); var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect // 0 or negative = within the clipping rect var overflowOffsets = { top: clippingClientRect.top - elementClientRect.top + paddingObject.top, bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom, left: clippingClientRect.left - elementClientRect.left + paddingObject.left, right: elementClientRect.right - clippingClientRect.right + paddingObject.right }; var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element if (elementContext === popper && offsetData) { var offset = offsetData[placement]; Object.keys(overflowOffsets).forEach(function (key) { var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1; var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x'; overflowOffsets[key] += offset[axis] * multiply; }); } return overflowOffsets; } function computeAutoPlacement(state, options) { if (options === void 0) { options = {}; } var _options = options, placement = _options.placement, boundary = _options.boundary, rootBoundary = _options.rootBoundary, padding = _options.padding, flipVariations = _options.flipVariations, _options$allowedAutoP = _options.allowedAutoPlacements, allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP; var variation = getVariation(placement); var placements$1 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) { return getVariation(placement) === variation; }) : basePlacements; var allowedPlacements = placements$1.filter(function (placement) { return allowedAutoPlacements.indexOf(placement) >= 0; }); if (allowedPlacements.length === 0) { allowedPlacements = placements$1; } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions... var overflows = allowedPlacements.reduce(function (acc, placement) { acc[placement] = detectOverflow(state, { placement: placement, boundary: boundary, rootBoundary: rootBoundary, padding: padding })[getBasePlacement(placement)]; return acc; }, {}); return Object.keys(overflows).sort(function (a, b) { return overflows[a] - overflows[b]; }); } function getExpandedFallbackPlacements(placement) { if (getBasePlacement(placement) === auto) { return []; } var oppositePlacement = getOppositePlacement(placement); return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)]; } function flip(_ref) { var state = _ref.state, options = _ref.options, name = _ref.name; if (state.modifiersData[name]._skip) { return; } var _options$mainAxis = options.mainAxis, checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, _options$altAxis = options.altAxis, checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis, specifiedFallbackPlacements = options.fallbackPlacements, padding = options.padding, boundary = options.boundary, rootBoundary = options.rootBoundary, altBoundary = options.altBoundary, _options$flipVariatio = options.flipVariations, flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio, allowedAutoPlacements = options.allowedAutoPlacements; var preferredPlacement = state.options.placement; var basePlacement = getBasePlacement(preferredPlacement); var isBasePlacement = basePlacement === preferredPlacement; var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement)); var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) { return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, { placement: placement, boundary: boundary, rootBoundary: rootBoundary, padding: padding, flipVariations: flipVariations, allowedAutoPlacements: allowedAutoPlacements }) : placement); }, []); var referenceRect = state.rects.reference; var popperRect = state.rects.popper; var checksMap = new Map(); var makeFallbackChecks = true; var firstFittingPlacement = placements[0]; for (var i = 0; i < placements.length; i++) { var placement = placements[i]; var _basePlacement = getBasePlacement(placement); var isStartVariation = getVariation(placement) === start; var isVertical = [top, bottom].indexOf(_basePlacement) >= 0; var len = isVertical ? 'width' : 'height'; var overflow = detectOverflow(state, { placement: placement, boundary: boundary, rootBoundary: rootBoundary, altBoundary: altBoundary, padding: padding }); var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top; if (referenceRect[len] > popperRect[len]) { mainVariationSide = getOppositePlacement(mainVariationSide); } var altVariationSide = getOppositePlacement(mainVariationSide); var checks = []; if (checkMainAxis) { checks.push(overflow[_basePlacement] <= 0); } if (checkAltAxis) { checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0); } if (checks.every(function (check) { return check; })) { firstFittingPlacement = placement; makeFallbackChecks = false; break; } checksMap.set(placement, checks); } if (makeFallbackChecks) { // `2` may be desired in some cases – research later var numberOfChecks = flipVariations ? 3 : 1; var _loop = function _loop(_i) { var fittingPlacement = placements.find(function (placement) { var checks = checksMap.get(placement); if (checks) { return checks.slice(0, _i).every(function (check) { return check; }); } }); if (fittingPlacement) { firstFittingPlacement = fittingPlacement; return "break"; } }; for (var _i = numberOfChecks; _i > 0; _i--) { var _ret = _loop(_i); if (_ret === "break") break; } } if (state.placement !== firstFittingPlacement) { state.modifiersData[name]._skip = true; state.placement = firstFittingPlacement; state.reset = true; } } // eslint-disable-next-line import/no-unused-modules var flip$1 = { name: 'flip', enabled: true, phase: 'main', fn: flip, requiresIfExists: ['offset'], data: { _skip: false } }; function getSideOffsets(overflow, rect, preventedOffsets) { if (preventedOffsets === void 0) { preventedOffsets = { x: 0, y: 0 }; } return { top: overflow.top - rect.height - preventedOffsets.y, right: overflow.right - rect.width + preventedOffsets.x, bottom: overflow.bottom - rect.height + preventedOffsets.y, left: overflow.left - rect.width - preventedOffsets.x }; } function isAnySideFullyClipped(overflow) { return [top, right, bottom, left].some(function (side) { return overflow[side] >= 0; }); } function hide(_ref) { var state = _ref.state, name = _ref.name; var referenceRect = state.rects.reference; var popperRect = state.rects.popper; var preventedOffsets = state.modifiersData.preventOverflow; var referenceOverflow = detectOverflow(state, { elementContext: 'reference' }); var popperAltOverflow = detectOverflow(state, { altBoundary: true }); var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect); var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets); var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets); var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets); state.modifiersData[name] = { referenceClippingOffsets: referenceClippingOffsets, popperEscapeOffsets: popperEscapeOffsets, isReferenceHidden: isReferenceHidden, hasPopperEscaped: hasPopperEscaped }; state.attributes.popper = Object.assign({}, state.attributes.popper, { 'data-popper-reference-hidden': isReferenceHidden, 'data-popper-escaped': hasPopperEscaped }); } // eslint-disable-next-line import/no-unused-modules var hide$1 = { name: 'hide', enabled: true, phase: 'main', requiresIfExists: ['preventOverflow'], fn: hide }; function distanceAndSkiddingToXY(placement, rects, offset) { var basePlacement = getBasePlacement(placement); var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1; var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, { placement: placement })) : offset, skidding = _ref[0], distance = _ref[1]; skidding = skidding || 0; distance = (distance || 0) * invertDistance; return [left, right].indexOf(basePlacement) >= 0 ? { x: distance, y: skidding } : { x: skidding, y: distance }; } function offset(_ref2) { var state = _ref2.state, options = _ref2.options, name = _ref2.name; var _options$offset = options.offset, offset = _options$offset === void 0 ? [0, 0] : _options$offset; var data = placements.reduce(function (acc, placement) { acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset); return acc; }, {}); var _data$state$placement = data[state.placement], x = _data$state$placement.x, y = _data$state$placement.y; if (state.modifiersData.popperOffsets != null) { state.modifiersData.popperOffsets.x += x; state.modifiersData.popperOffsets.y += y; } state.modifiersData[name] = data; } // eslint-disable-next-line import/no-unused-modules var offset$1 = { name: 'offset', enabled: true, phase: 'main', requires: ['popperOffsets'], fn: offset }; function popperOffsets(_ref) { var state = _ref.state, name = _ref.name; // Offsets are the actual position the popper needs to have to be // properly positioned near its reference element // This is the most basic placement, and will be adjusted by // the modifiers in the next step state.modifiersData[name] = computeOffsets({ reference: state.rects.reference, element: state.rects.popper, strategy: 'absolute', placement: state.placement }); } // eslint-disable-next-line import/no-unused-modules var popperOffsets$1 = { name: 'popperOffsets', enabled: true, phase: 'read', fn: popperOffsets, data: {} }; function getAltAxis(axis) { return axis === 'x' ? 'y' : 'x'; } function preventOverflow(_ref) { var state = _ref.state, options = _ref.options, name = _ref.name; var _options$mainAxis = options.mainAxis, checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, _options$altAxis = options.altAxis, checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis, boundary = options.boundary, rootBoundary = options.rootBoundary, altBoundary = options.altBoundary, padding = options.padding, _options$tether = options.tether, tether = _options$tether === void 0 ? true : _options$tether, _options$tetherOffset = options.tetherOffset, tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset; var overflow = detectOverflow(state, { boundary: boundary, rootBoundary: rootBoundary, padding: padding, altBoundary: altBoundary }); var basePlacement = getBasePlacement(state.placement); var variation = getVariation(state.placement); var isBasePlacement = !variation; var mainAxis = getMainAxisFromPlacement(basePlacement); var altAxis = getAltAxis(mainAxis); var popperOffsets = state.modifiersData.popperOffsets; var referenceRect = state.rects.reference; var popperRect = state.rects.popper; var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, { placement: state.placement })) : tetherOffset; var data = { x: 0, y: 0 }; if (!popperOffsets) { return; } if (checkMainAxis || checkAltAxis) { var mainSide = mainAxis === 'y' ? top : left; var altSide = mainAxis === 'y' ? bottom : right; var len = mainAxis === 'y' ? 'height' : 'width'; var offset = popperOffsets[mainAxis]; var min$1 = popperOffsets[mainAxis] + overflow[mainSide]; var max$1 = popperOffsets[mainAxis] - overflow[altSide]; var additive = tether ? -popperRect[len] / 2 : 0; var minLen = variation === start ? referenceRect[len] : popperRect[len]; var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go // outside the reference bounds var arrowElement = state.elements.arrow; var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : { width: 0, height: 0 }; var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject(); var arrowPaddingMin = arrowPaddingObject[mainSide]; var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want // to include its full size in the calculation. If the reference is small // and near the edge of a boundary, the popper can overflow even if the // reference is not overflowing as well (e.g. virtual elements with no // width or height) var arrowLen = within(0, referenceRect[len], arrowRect[len]); var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - tetherOffsetValue : minLen - arrowLen - arrowPaddingMin - tetherOffsetValue; var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + tetherOffsetValue : maxLen + arrowLen + arrowPaddingMax + tetherOffsetValue; var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow); var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0; var offsetModifierValue = state.modifiersData.offset ? state.modifiersData.offset[state.placement][mainAxis] : 0; var tetherMin = popperOffsets[mainAxis] + minOffset - offsetModifierValue - clientOffset; var tetherMax = popperOffsets[mainAxis] + maxOffset - offsetModifierValue; if (checkMainAxis) { var preventedOffset = within(tether ? min(min$1, tetherMin) : min$1, offset, tether ? max(max$1, tetherMax) : max$1); popperOffsets[mainAxis] = preventedOffset; data[mainAxis] = preventedOffset - offset; } if (checkAltAxis) { var _mainSide = mainAxis === 'x' ? top : left; var _altSide = mainAxis === 'x' ? bottom : right; var _offset = popperOffsets[altAxis]; var _min = _offset + overflow[_mainSide]; var _max = _offset - overflow[_altSide]; var _preventedOffset = within(tether ? min(_min, tetherMin) : _min, _offset, tether ? max(_max, tetherMax) : _max); popperOffsets[altAxis] = _preventedOffset; data[altAxis] = _preventedOffset - _offset; } } state.modifiersData[name] = data; } // eslint-disable-next-line import/no-unused-modules var preventOverflow$1 = { name: 'preventOverflow', enabled: true, phase: 'main', fn: preventOverflow, requiresIfExists: ['offset'] }; function getHTMLElementScroll(element) { return { scrollLeft: element.scrollLeft, scrollTop: element.scrollTop }; } function getNodeScroll(node) { if (node === getWindow(node) || !isHTMLElement(node)) { return getWindowScroll(node); } else { return getHTMLElementScroll(node); } } function isElementScaled(element) { var rect = element.getBoundingClientRect(); var scaleX = rect.width / element.offsetWidth || 1; var scaleY = rect.height / element.offsetHeight || 1; return scaleX !== 1 || scaleY !== 1; } // Returns the composite rect of an element relative to its offsetParent. // Composite means it takes into account transforms as well as layout. function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) { if (isFixed === void 0) { isFixed = false; } var isOffsetParentAnElement = isHTMLElement(offsetParent); var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent); var documentElement = getDocumentElement(offsetParent); var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled); var scroll = { scrollLeft: 0, scrollTop: 0 }; var offsets = { x: 0, y: 0 }; if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) { if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078 isScrollParent(documentElement)) { scroll = getNodeScroll(offsetParent); } if (isHTMLElement(offsetParent)) { offsets = getBoundingClientRect(offsetParent, true); offsets.x += offsetParent.clientLeft; offsets.y += offsetParent.clientTop; } else if (documentElement) { offsets.x = getWindowScrollBarX(documentElement); } } return { x: rect.left + scroll.scrollLeft - offsets.x, y: rect.top + scroll.scrollTop - offsets.y, width: rect.width, height: rect.height }; } function order(modifiers) { var map = new Map(); var visited = new Set(); var result = []; modifiers.forEach(function (modifier) { map.set(modifier.name, modifier); }); // On visiting object, check for its dependencies and visit them recursively function sort(modifier) { visited.add(modifier.name); var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []); requires.forEach(function (dep) { if (!visited.has(dep)) { var depModifier = map.get(dep); if (depModifier) { sort(depModifier); } } }); result.push(modifier); } modifiers.forEach(function (modifier) { if (!visited.has(modifier.name)) { // check for visited object sort(modifier); } }); return result; } function orderModifiers(modifiers) { // order based on dependencies var orderedModifiers = order(modifiers); // order based on phase return modifierPhases.reduce(function (acc, phase) { return acc.concat(orderedModifiers.filter(function (modifier) { return modifier.phase === phase; })); }, []); } function debounce(fn) { var pending; return function () { if (!pending) { pending = new Promise(function (resolve) { Promise.resolve().then(function () { pending = undefined; resolve(fn()); }); }); } return pending; }; } function mergeByName(modifiers) { var merged = modifiers.reduce(function (merged, current) { var existing = merged[current.name]; merged[current.name] = existing ? Object.assign({}, existing, current, { options: Object.assign({}, existing.options, current.options), data: Object.assign({}, existing.data, current.data) }) : current; return merged; }, {}); // IE11 does not support Object.values return Object.keys(merged).map(function (key) { return merged[key]; }); } var DEFAULT_OPTIONS = { placement: 'bottom', modifiers: [], strategy: 'absolute' }; function areValidElements() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return !args.some(function (element) { return !(element && typeof element.getBoundingClientRect === 'function'); }); } function popperGenerator(generatorOptions) { if (generatorOptions === void 0) { generatorOptions = {}; } var _generatorOptions = generatorOptions, _generatorOptions$def = _generatorOptions.defaultModifiers, defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def, _generatorOptions$def2 = _generatorOptions.defaultOptions, defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2; return function createPopper(reference, popper, options) { if (options === void 0) { options = defaultOptions; } var state = { placement: 'bottom', orderedModifiers: [], options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions), modifiersData: {}, elements: { reference: reference, popper: popper }, attributes: {}, styles: {} }; var effectCleanupFns = []; var isDestroyed = false; var instance = { state: state, setOptions: function setOptions(options) { cleanupModifierEffects(); state.options = Object.assign({}, defaultOptions, state.options, options); state.scrollParents = { reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [], popper: listScrollParents(popper) }; // Orders the modifiers based on their dependencies and `phase` // properties var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers state.orderedModifiers = orderedModifiers.filter(function (m) { return m.enabled; }); // Validate the provided modifiers so that the consumer will get warned runModifierEffects(); return instance.update(); }, // Sync update – it will always be executed, even if not necessary. This // is useful for low frequency updates where sync behavior simplifies the // logic. // For high frequency updates (e.g. `resize` and `scroll` events), always // prefer the async Popper#update method forceUpdate: function forceUpdate() { if (isDestroyed) { return; } var _state$elements = state.elements, reference = _state$elements.reference, popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements // anymore if (!areValidElements(reference, popper)) { return; } // Store the reference and popper rects to be read by modifiers state.rects = { reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'), popper: getLayoutRect(popper) }; // Modifiers have the ability to reset the current update cycle. The // most common use case for this is the `flip` modifier changing the // placement, which then needs to re-run all the modifiers, because the // logic was previously ran for the previous placement and is therefore // stale/incorrect state.reset = false; state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier // is filled with the initial data specified by the modifier. This means // it doesn't persist and is fresh on each update. // To ensure persistent data, use `${name}#persistent` state.orderedModifiers.forEach(function (modifier) { return state.modifiersData[modifier.name] = Object.assign({}, modifier.data); }); for (var index = 0; index < state.orderedModifiers.length; index++) { if (state.reset === true) { state.reset = false; index = -1; continue; } var _state$orderedModifie = state.orderedModifiers[index], fn = _state$orderedModifie.fn, _state$orderedModifie2 = _state$orderedModifie.options, _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2, name = _state$orderedModifie.name; if (typeof fn === 'function') { state = fn({ state: state, options: _options, name: name, instance: instance }) || state; } } }, // Async and optimistically optimized update – it will not be executed if // not necessary (debounced to run at most once-per-tick) update: debounce(function () { return new Promise(function (resolve) { instance.forceUpdate(); resolve(state); }); }), destroy: function destroy() { cleanupModifierEffects(); isDestroyed = true; } }; if (!areValidElements(reference, popper)) { return instance; } instance.setOptions(options).then(function (state) { if (!isDestroyed && options.onFirstUpdate) { options.onFirstUpdate(state); } }); // Modifiers have the ability to execute arbitrary code before the first // update cycle runs. They will be executed in the same order as the update // cycle. This is useful when a modifier adds some persistent data that // other modifiers need to use, but the modifier is run after the dependent // one. function runModifierEffects() { state.orderedModifiers.forEach(function (_ref3) { var name = _ref3.name, _ref3$options = _ref3.options, options = _ref3$options === void 0 ? {} : _ref3$options, effect = _ref3.effect; if (typeof effect === 'function') { var cleanupFn = effect({ state: state, name: name, instance: instance, options: options }); var noopFn = function noopFn() {}; effectCleanupFns.push(cleanupFn || noopFn); } }); } function cleanupModifierEffects() { effectCleanupFns.forEach(function (fn) { return fn(); }); effectCleanupFns = []; } return instance; }; } var createPopper$2 = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules var defaultModifiers$1 = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1]; var createPopper$1 = /*#__PURE__*/popperGenerator({ defaultModifiers: defaultModifiers$1 }); // eslint-disable-next-line import/no-unused-modules var defaultModifiers = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1, offset$1, flip$1, preventOverflow$1, arrow$1, hide$1]; var createPopper = /*#__PURE__*/popperGenerator({ defaultModifiers: defaultModifiers }); // eslint-disable-next-line import/no-unused-modules var Popper = /*#__PURE__*/Object.freeze({ __proto__: null, popperGenerator: popperGenerator, detectOverflow: detectOverflow, createPopperBase: createPopper$2, createPopper: createPopper, createPopperLite: createPopper$1, top: top, bottom: bottom, right: right, left: left, auto: auto, basePlacements: basePlacements, start: start, end: end, clippingParents: clippingParents, viewport: viewport, popper: popper, reference: reference, variationPlacements: variationPlacements, placements: placements, beforeRead: beforeRead, read: read, afterRead: afterRead, beforeMain: beforeMain, main: main, afterMain: afterMain, beforeWrite: beforeWrite, write: write, afterWrite: afterWrite, modifierPhases: modifierPhases, applyStyles: applyStyles$1, arrow: arrow$1, computeStyles: computeStyles$1, eventListeners: eventListeners, flip: flip$1, hide: hide$1, offset: offset$1, popperOffsets: popperOffsets$1, preventOverflow: preventOverflow$1 }); /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): dropdown.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME$9 = 'dropdown'; const DATA_KEY$8 = 'bs.dropdown'; const EVENT_KEY$8 = `.${DATA_KEY$8}`; const DATA_API_KEY$4 = '.data-api'; const ESCAPE_KEY$2 = 'Escape'; const SPACE_KEY = 'Space'; const TAB_KEY$1 = 'Tab'; const ARROW_UP_KEY = 'ArrowUp'; const ARROW_DOWN_KEY = 'ArrowDown'; const RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${ESCAPE_KEY$2}`); const EVENT_HIDE$4 = `hide${EVENT_KEY$8}`; const EVENT_HIDDEN$4 = `hidden${EVENT_KEY$8}`; const EVENT_SHOW$4 = `show${EVENT_KEY$8}`; const EVENT_SHOWN$4 = `shown${EVENT_KEY$8}`; const EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$8}${DATA_API_KEY$4}`; const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$8}${DATA_API_KEY$4}`; const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$8}${DATA_API_KEY$4}`; const CLASS_NAME_SHOW$6 = 'show'; const CLASS_NAME_DROPUP = 'dropup'; const CLASS_NAME_DROPEND = 'dropend'; const CLASS_NAME_DROPSTART = 'dropstart'; const CLASS_NAME_NAVBAR = 'navbar'; const SELECTOR_DATA_TOGGLE$3 = '[data-bs-toggle="dropdown"]'; const SELECTOR_MENU = '.dropdown-menu'; const SELECTOR_NAVBAR_NAV = '.navbar-nav'; const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'; const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'; const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'; const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'; const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'; const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'; const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'; const Default$8 = { offset: [0, 2], boundary: 'clippingParents', reference: 'toggle', display: 'dynamic', popperConfig: null, autoClose: true }; const DefaultType$8 = { offset: '(array|string|function)', boundary: '(string|element)', reference: '(string|element|object)', display: 'string', popperConfig: '(null|object|function)', autoClose: '(boolean|string)' }; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Dropdown extends BaseComponent { constructor(element, config) { super(element); this._popper = null; this._config = this._getConfig(config); this._menu = this._getMenuElement(); this._inNavbar = this._detectNavbar(); } // Getters static get Default() { return Default$8; } static get DefaultType() { return DefaultType$8; } static get NAME() { return NAME$9; } // Public toggle() { return this._isShown() ? this.hide() : this.show(); } show() { if (isDisabled(this._element) || this._isShown(this._menu)) { return; } const relatedTarget = { relatedTarget: this._element }; const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$4, relatedTarget); if (showEvent.defaultPrevented) { return; } const parent = Dropdown.getParentFromElement(this._element); // Totally disable Popper for Dropdowns in Navbar if (this._inNavbar) { Manipulator.setDataAttribute(this._menu, 'popper', 'none'); } else { this._createPopper(parent); } // If this is a touch-enabled device we add extra // empty mouseover listeners to the body's immediate children; // only needed because of broken event delegation on iOS // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html if ('ontouchstart' in document.documentElement && !parent.closest(SELECTOR_NAVBAR_NAV)) { [].concat(...document.body.children).forEach(elem => EventHandler.on(elem, 'mouseover', noop)); } this._element.focus(); this._element.setAttribute('aria-expanded', true); this._menu.classList.add(CLASS_NAME_SHOW$6); this._element.classList.add(CLASS_NAME_SHOW$6); EventHandler.trigger(this._element, EVENT_SHOWN$4, relatedTarget); } hide() { if (isDisabled(this._element) || !this._isShown(this._menu)) { return; } const relatedTarget = { relatedTarget: this._element }; this._completeHide(relatedTarget); } dispose() { if (this._popper) { this._popper.destroy(); } super.dispose(); } update() { this._inNavbar = this._detectNavbar(); if (this._popper) { this._popper.update(); } } // Private _completeHide(relatedTarget) { const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$4, relatedTarget); if (hideEvent.defaultPrevented) { return; } // If this is a touch-enabled device we remove the extra // empty mouseover listeners we added for iOS support if ('ontouchstart' in document.documentElement) { [].concat(...document.body.children).forEach(elem => EventHandler.off(elem, 'mouseover', noop)); } if (this._popper) { this._popper.destroy(); } this._menu.classList.remove(CLASS_NAME_SHOW$6); this._element.classList.remove(CLASS_NAME_SHOW$6); this._element.setAttribute('aria-expanded', 'false'); Manipulator.removeDataAttribute(this._menu, 'popper'); EventHandler.trigger(this._element, EVENT_HIDDEN$4, relatedTarget); } _getConfig(config) { config = { ...this.constructor.Default, ...Manipulator.getDataAttributes(this._element), ...config }; typeCheckConfig(NAME$9, config, this.constructor.DefaultType); if (typeof config.reference === 'object' && !isElement$1(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') { // Popper virtual elements require a getBoundingClientRect method throw new TypeError(`${NAME$9.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`); } return config; } _createPopper(parent) { if (typeof Popper === 'undefined') { throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)'); } let referenceElement = this._element; if (this._config.reference === 'parent') { referenceElement = parent; } else if (isElement$1(this._config.reference)) { referenceElement = getElement(this._config.reference); } else if (typeof this._config.reference === 'object') { referenceElement = this._config.reference; } const popperConfig = this._getPopperConfig(); const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false); this._popper = createPopper(referenceElement, this._menu, popperConfig); if (isDisplayStatic) { Manipulator.setDataAttribute(this._menu, 'popper', 'static'); } } _isShown(element = this._element) { return element.classList.contains(CLASS_NAME_SHOW$6); } _getMenuElement() { return SelectorEngine.next(this._element, SELECTOR_MENU)[0]; } _getPlacement() { const parentDropdown = this._element.parentNode; if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) { return PLACEMENT_RIGHT; } if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) { return PLACEMENT_LEFT; } // We need to trim the value because custom properties can also include spaces const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'; if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) { return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP; } return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM; } _detectNavbar() { return this._element.closest(`.${CLASS_NAME_NAVBAR}`) !== null; } _getOffset() { const { offset } = this._config; if (typeof offset === 'string') { return offset.split(',').map(val => Number.parseInt(val, 10)); } if (typeof offset === 'function') { return popperData => offset(popperData, this._element); } return offset; } _getPopperConfig() { const defaultBsPopperConfig = { placement: this._getPlacement(), modifiers: [{ name: 'preventOverflow', options: { boundary: this._config.boundary } }, { name: 'offset', options: { offset: this._getOffset() } }] }; // Disable Popper if we have a static display if (this._config.display === 'static') { defaultBsPopperConfig.modifiers = [{ name: 'applyStyles', enabled: false }]; } return { ...defaultBsPopperConfig, ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig) }; } _selectMenuItem({ key, target }) { const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible); if (!items.length) { return; } // if target isn't included in items (e.g. when expanding the dropdown) // allow cycling to get the last item in case key equals ARROW_UP_KEY getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus(); } // Static static jQueryInterface(config) { return this.each(function () { const data = Dropdown.getOrCreateInstance(this, config); if (typeof config !== 'string') { return; } if (typeof data[config] === 'undefined') { throw new TypeError(`No method named "${config}"`); } data[config](); }); } static clearMenus(event) { if (event && (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1)) { return; } const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE$3); for (let i = 0, len = toggles.length; i < len; i++) { const context = Dropdown.getInstance(toggles[i]); if (!context || context._config.autoClose === false) { continue; } if (!context._isShown()) { continue; } const relatedTarget = { relatedTarget: context._element }; if (event) { const composedPath = event.composedPath(); const isMenuTarget = composedPath.includes(context._menu); if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) { continue; } // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName))) { continue; } if (event.type === 'click') { relatedTarget.clickEvent = event; } } context._completeHide(relatedTarget); } } static getParentFromElement(element) { return getElementFromSelector(element) || element.parentNode; } static dataApiKeydownHandler(event) { // If not input/textarea: // - And not a key in REGEXP_KEYDOWN => not a dropdown command // If input/textarea: // - If space key => not a dropdown command // - If key is other than escape // - If key is not up or down => not a dropdown command // - If trigger inside the menu => not a dropdown command if (/input|textarea/i.test(event.target.tagName) ? event.key === SPACE_KEY || event.key !== ESCAPE_KEY$2 && (event.key !== ARROW_DOWN_KEY && event.key !== ARROW_UP_KEY || event.target.closest(SELECTOR_MENU)) : !REGEXP_KEYDOWN.test(event.key)) { return; } const isActive = this.classList.contains(CLASS_NAME_SHOW$6); if (!isActive && event.key === ESCAPE_KEY$2) { return; } event.preventDefault(); event.stopPropagation(); if (isDisabled(this)) { return; } const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE$3) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE$3)[0]; const instance = Dropdown.getOrCreateInstance(getToggleButton); if (event.key === ESCAPE_KEY$2) { instance.hide(); return; } if (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY) { if (!isActive) { instance.show(); } instance._selectMenuItem(event); return; } if (!isActive || event.key === SPACE_KEY) { Dropdown.clearMenus(); } } } /** * ------------------------------------------------------------------------ * Data Api implementation * ------------------------------------------------------------------------ */ EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$3, Dropdown.dataApiKeydownHandler); EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler); EventHandler.on(document, EVENT_CLICK_DATA_API$3, Dropdown.clearMenus); EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus); EventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) { event.preventDefault(); Dropdown.getOrCreateInstance(this).toggle(); }); /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .Dropdown to jQuery only if jQuery is present */ defineJQueryPlugin(Dropdown); /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): util/scrollBar.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'; const SELECTOR_STICKY_CONTENT = '.sticky-top'; class ScrollBarHelper { constructor() { this._element = document.body; } getWidth() { // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes const documentWidth = document.documentElement.clientWidth; return Math.abs(window.innerWidth - documentWidth); } hide() { const width = this.getWidth(); this._disableOverFlow(); // give padding to element to balance the hidden scrollbar width this._setElementAttributes(this._element, 'paddingRight', calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth this._setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width); this._setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width); } _disableOverFlow() { this._saveInitialAttribute(this._element, 'overflow'); this._element.style.overflow = 'hidden'; } _setElementAttributes(selector, styleProp, callback) { const scrollbarWidth = this.getWidth(); const manipulationCallBack = element => { if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) { return; } this._saveInitialAttribute(element, styleProp); const calculatedValue = window.getComputedStyle(element)[styleProp]; element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`; }; this._applyManipulationCallback(selector, manipulationCallBack); } reset() { this._resetElementAttributes(this._element, 'overflow'); this._resetElementAttributes(this._element, 'paddingRight'); this._resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight'); this._resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight'); } _saveInitialAttribute(element, styleProp) { const actualValue = element.style[styleProp]; if (actualValue) { Manipulator.setDataAttribute(element, styleProp, actualValue); } } _resetElementAttributes(selector, styleProp) { const manipulationCallBack = element => { const value = Manipulator.getDataAttribute(element, styleProp); if (typeof value === 'undefined') { element.style.removeProperty(styleProp); } else { Manipulator.removeDataAttribute(element, styleProp); element.style[styleProp] = value; } }; this._applyManipulationCallback(selector, manipulationCallBack); } _applyManipulationCallback(selector, callBack) { if (isElement$1(selector)) { callBack(selector); } else { SelectorEngine.find(selector, this._element).forEach(callBack); } } isOverflowing() { return this.getWidth() > 0; } } /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): util/backdrop.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * -------------------------------------------------------------------------- */ const Default$7 = { className: 'modal-backdrop', isVisible: true, // if false, we use the backdrop helper without adding any element to the dom isAnimated: false, rootElement: 'body', // give the choice to place backdrop under different elements clickCallback: null }; const DefaultType$7 = { className: 'string', isVisible: 'boolean', isAnimated: 'boolean', rootElement: '(element|string)', clickCallback: '(function|null)' }; const NAME$8 = 'backdrop'; const CLASS_NAME_FADE$4 = 'fade'; const CLASS_NAME_SHOW$5 = 'show'; const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$8}`; class Backdrop { constructor(config) { this._config = this._getConfig(config); this._isAppended = false; this._element = null; } show(callback) { if (!this._config.isVisible) { execute(callback); return; } this._append(); if (this._config.isAnimated) { reflow(this._getElement()); } this._getElement().classList.add(CLASS_NAME_SHOW$5); this._emulateAnimation(() => { execute(callback); }); } hide(callback) { if (!this._config.isVisible) { execute(callback); return; } this._getElement().classList.remove(CLASS_NAME_SHOW$5); this._emulateAnimation(() => { this.dispose(); execute(callback); }); } // Private _getElement() { if (!this._element) { const backdrop = document.createElement('div'); backdrop.className = this._config.className; if (this._config.isAnimated) { backdrop.classList.add(CLASS_NAME_FADE$4); } this._element = backdrop; } return this._element; } _getConfig(config) { config = { ...Default$7, ...(typeof config === 'object' ? config : {}) }; // use getElement() with the default "body" to get a fresh Element on each instantiation config.rootElement = getElement(config.rootElement); typeCheckConfig(NAME$8, config, DefaultType$7); return config; } _append() { if (this._isAppended) { return; } this._config.rootElement.append(this._getElement()); EventHandler.on(this._getElement(), EVENT_MOUSEDOWN, () => { execute(this._config.clickCallback); }); this._isAppended = true; } dispose() { if (!this._isAppended) { return; } EventHandler.off(this._element, EVENT_MOUSEDOWN); this._element.remove(); this._isAppended = false; } _emulateAnimation(callback) { executeAfterTransition(callback, this._getElement(), this._config.isAnimated); } } /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): util/focustrap.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * -------------------------------------------------------------------------- */ const Default$6 = { trapElement: null, // The element to trap focus inside of autofocus: true }; const DefaultType$6 = { trapElement: 'element', autofocus: 'boolean' }; const NAME$7 = 'focustrap'; const DATA_KEY$7 = 'bs.focustrap'; const EVENT_KEY$7 = `.${DATA_KEY$7}`; const EVENT_FOCUSIN$1 = `focusin${EVENT_KEY$7}`; const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$7}`; const TAB_KEY = 'Tab'; const TAB_NAV_FORWARD = 'forward'; const TAB_NAV_BACKWARD = 'backward'; class FocusTrap { constructor(config) { this._config = this._getConfig(config); this._isActive = false; this._lastTabNavDirection = null; } activate() { const { trapElement, autofocus } = this._config; if (this._isActive) { return; } if (autofocus) { trapElement.focus(); } EventHandler.off(document, EVENT_KEY$7); // guard against infinite focus loop EventHandler.on(document, EVENT_FOCUSIN$1, event => this._handleFocusin(event)); EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event)); this._isActive = true; } deactivate() { if (!this._isActive) { return; } this._isActive = false; EventHandler.off(document, EVENT_KEY$7); } // Private _handleFocusin(event) { const { target } = event; const { trapElement } = this._config; if (target === document || target === trapElement || trapElement.contains(target)) { return; } const elements = SelectorEngine.focusableChildren(trapElement); if (elements.length === 0) { trapElement.focus(); } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) { elements[elements.length - 1].focus(); } else { elements[0].focus(); } } _handleKeydown(event) { if (event.key !== TAB_KEY) { return; } this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD; } _getConfig(config) { config = { ...Default$6, ...(typeof config === 'object' ? config : {}) }; typeCheckConfig(NAME$7, config, DefaultType$6); return config; } } /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): modal.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME$6 = 'modal'; const DATA_KEY$6 = 'bs.modal'; const EVENT_KEY$6 = `.${DATA_KEY$6}`; const DATA_API_KEY$3 = '.data-api'; const ESCAPE_KEY$1 = 'Escape'; const Default$5 = { backdrop: true, keyboard: true, focus: true }; const DefaultType$5 = { backdrop: '(boolean|string)', keyboard: 'boolean', focus: 'boolean' }; const EVENT_HIDE$3 = `hide${EVENT_KEY$6}`; const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$6}`; const EVENT_HIDDEN$3 = `hidden${EVENT_KEY$6}`; const EVENT_SHOW$3 = `show${EVENT_KEY$6}`; const EVENT_SHOWN$3 = `shown${EVENT_KEY$6}`; const EVENT_RESIZE = `resize${EVENT_KEY$6}`; const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$6}`; const EVENT_KEYDOWN_DISMISS$1 = `keydown.dismiss${EVENT_KEY$6}`; const EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY$6}`; const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$6}`; const EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`; const CLASS_NAME_OPEN = 'modal-open'; const CLASS_NAME_FADE$3 = 'fade'; const CLASS_NAME_SHOW$4 = 'show'; const CLASS_NAME_STATIC = 'modal-static'; const SELECTOR_DIALOG = '.modal-dialog'; const SELECTOR_MODAL_BODY = '.modal-body'; const SELECTOR_DATA_TOGGLE$2 = '[data-bs-toggle="modal"]'; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Modal extends BaseComponent { constructor(element, config) { super(element); this._config = this._getConfig(config); this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element); this._backdrop = this._initializeBackDrop(); this._focustrap = this._initializeFocusTrap(); this._isShown = false; this._ignoreBackdropClick = false; this._isTransitioning = false; this._scrollBar = new ScrollBarHelper(); } // Getters static get Default() { return Default$5; } static get NAME() { return NAME$6; } // Public toggle(relatedTarget) { return this._isShown ? this.hide() : this.show(relatedTarget); } show(relatedTarget) { if (this._isShown || this._isTransitioning) { return; } const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$3, { relatedTarget }); if (showEvent.defaultPrevented) { return; } this._isShown = true; if (this._isAnimated()) { this._isTransitioning = true; } this._scrollBar.hide(); document.body.classList.add(CLASS_NAME_OPEN); this._adjustDialog(); this._setEscapeEvent(); this._setResizeEvent(); EventHandler.on(this._dialog, EVENT_MOUSEDOWN_DISMISS, () => { EventHandler.one(this._element, EVENT_MOUSEUP_DISMISS, event => { if (event.target === this._element) { this._ignoreBackdropClick = true; } }); }); this._showBackdrop(() => this._showElement(relatedTarget)); } hide() { if (!this._isShown || this._isTransitioning) { return; } const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$3); if (hideEvent.defaultPrevented) { return; } this._isShown = false; const isAnimated = this._isAnimated(); if (isAnimated) { this._isTransitioning = true; } this._setEscapeEvent(); this._setResizeEvent(); this._focustrap.deactivate(); this._element.classList.remove(CLASS_NAME_SHOW$4); EventHandler.off(this._element, EVENT_CLICK_DISMISS); EventHandler.off(this._dialog, EVENT_MOUSEDOWN_DISMISS); this._queueCallback(() => this._hideModal(), this._element, isAnimated); } dispose() { [window, this._dialog].forEach(htmlElement => EventHandler.off(htmlElement, EVENT_KEY$6)); this._backdrop.dispose(); this._focustrap.deactivate(); super.dispose(); } handleUpdate() { this._adjustDialog(); } // Private _initializeBackDrop() { return new Backdrop({ isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value isAnimated: this._isAnimated() }); } _initializeFocusTrap() { return new FocusTrap({ trapElement: this._element }); } _getConfig(config) { config = { ...Default$5, ...Manipulator.getDataAttributes(this._element), ...(typeof config === 'object' ? config : {}) }; typeCheckConfig(NAME$6, config, DefaultType$5); return config; } _showElement(relatedTarget) { const isAnimated = this._isAnimated(); const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog); if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { // Don't move modal's DOM position document.body.append(this._element); } this._element.style.display = 'block'; this._element.removeAttribute('aria-hidden'); this._element.setAttribute('aria-modal', true); this._element.setAttribute('role', 'dialog'); this._element.scrollTop = 0; if (modalBody) { modalBody.scrollTop = 0; } if (isAnimated) { reflow(this._element); } this._element.classList.add(CLASS_NAME_SHOW$4); const transitionComplete = () => { if (this._config.focus) { this._focustrap.activate(); } this._isTransitioning = false; EventHandler.trigger(this._element, EVENT_SHOWN$3, { relatedTarget }); }; this._queueCallback(transitionComplete, this._dialog, isAnimated); } _setEscapeEvent() { if (this._isShown) { EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS$1, event => { if (this._config.keyboard && event.key === ESCAPE_KEY$1) { event.preventDefault(); this.hide(); } else if (!this._config.keyboard && event.key === ESCAPE_KEY$1) { this._triggerBackdropTransition(); } }); } else { EventHandler.off(this._element, EVENT_KEYDOWN_DISMISS$1); } } _setResizeEvent() { if (this._isShown) { EventHandler.on(window, EVENT_RESIZE, () => this._adjustDialog()); } else { EventHandler.off(window, EVENT_RESIZE); } } _hideModal() { this._element.style.display = 'none'; this._element.setAttribute('aria-hidden', true); this._element.removeAttribute('aria-modal'); this._element.removeAttribute('role'); this._isTransitioning = false; this._backdrop.hide(() => { document.body.classList.remove(CLASS_NAME_OPEN); this._resetAdjustments(); this._scrollBar.reset(); EventHandler.trigger(this._element, EVENT_HIDDEN$3); }); } _showBackdrop(callback) { EventHandler.on(this._element, EVENT_CLICK_DISMISS, event => { if (this._ignoreBackdropClick) { this._ignoreBackdropClick = false; return; } if (event.target !== event.currentTarget) { return; } if (this._config.backdrop === true) { this.hide(); } else if (this._config.backdrop === 'static') { this._triggerBackdropTransition(); } }); this._backdrop.show(callback); } _isAnimated() { return this._element.classList.contains(CLASS_NAME_FADE$3); } _triggerBackdropTransition() { const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED); if (hideEvent.defaultPrevented) { return; } const { classList, scrollHeight, style } = this._element; const isModalOverflowing = scrollHeight > document.documentElement.clientHeight; // return if the following background transition hasn't yet completed if (!isModalOverflowing && style.overflowY === 'hidden' || classList.contains(CLASS_NAME_STATIC)) { return; } if (!isModalOverflowing) { style.overflowY = 'hidden'; } classList.add(CLASS_NAME_STATIC); this._queueCallback(() => { classList.remove(CLASS_NAME_STATIC); if (!isModalOverflowing) { this._queueCallback(() => { style.overflowY = ''; }, this._dialog); } }, this._dialog); this._element.focus(); } // ---------------------------------------------------------------------- // the following methods are used to handle overflowing modals // ---------------------------------------------------------------------- _adjustDialog() { const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; const scrollbarWidth = this._scrollBar.getWidth(); const isBodyOverflowing = scrollbarWidth > 0; if (!isBodyOverflowing && isModalOverflowing && !isRTL() || isBodyOverflowing && !isModalOverflowing && isRTL()) { this._element.style.paddingLeft = `${scrollbarWidth}px`; } if (isBodyOverflowing && !isModalOverflowing && !isRTL() || !isBodyOverflowing && isModalOverflowing && isRTL()) { this._element.style.paddingRight = `${scrollbarWidth}px`; } } _resetAdjustments() { this._element.style.paddingLeft = ''; this._element.style.paddingRight = ''; } // Static static jQueryInterface(config, relatedTarget) { return this.each(function () { const data = Modal.getOrCreateInstance(this, config); if (typeof config !== 'string') { return; } if (typeof data[config] === 'undefined') { throw new TypeError(`No method named "${config}"`); } data[config](relatedTarget); }); } } /** * ------------------------------------------------------------------------ * Data Api implementation * ------------------------------------------------------------------------ */ EventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) { const target = getElementFromSelector(this); if (['A', 'AREA'].includes(this.tagName)) { event.preventDefault(); } EventHandler.one(target, EVENT_SHOW$3, showEvent => { if (showEvent.defaultPrevented) { // only register focus restorer if modal will actually get shown return; } EventHandler.one(target, EVENT_HIDDEN$3, () => { if (isVisible(this)) { this.focus(); } }); }); const data = Modal.getOrCreateInstance(target); data.toggle(this); }); enableDismissTrigger(Modal); /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .Modal to jQuery only if jQuery is present */ defineJQueryPlugin(Modal); /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): offcanvas.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME$5 = 'offcanvas'; const DATA_KEY$5 = 'bs.offcanvas'; const EVENT_KEY$5 = `.${DATA_KEY$5}`; const DATA_API_KEY$2 = '.data-api'; const EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$5}${DATA_API_KEY$2}`; const ESCAPE_KEY = 'Escape'; const Default$4 = { backdrop: true, keyboard: true, scroll: false }; const DefaultType$4 = { backdrop: 'boolean', keyboard: 'boolean', scroll: 'boolean' }; const CLASS_NAME_SHOW$3 = 'show'; const CLASS_NAME_BACKDROP = 'offcanvas-backdrop'; const OPEN_SELECTOR = '.offcanvas.show'; const EVENT_SHOW$2 = `show${EVENT_KEY$5}`; const EVENT_SHOWN$2 = `shown${EVENT_KEY$5}`; const EVENT_HIDE$2 = `hide${EVENT_KEY$5}`; const EVENT_HIDDEN$2 = `hidden${EVENT_KEY$5}`; const EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$5}${DATA_API_KEY$2}`; const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$5}`; const SELECTOR_DATA_TOGGLE$1 = '[data-bs-toggle="offcanvas"]'; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Offcanvas extends BaseComponent { constructor(element, config) { super(element); this._config = this._getConfig(config); this._isShown = false; this._backdrop = this._initializeBackDrop(); this._focustrap = this._initializeFocusTrap(); this._addEventListeners(); } // Getters static get NAME() { return NAME$5; } static get Default() { return Default$4; } // Public toggle(relatedTarget) { return this._isShown ? this.hide() : this.show(relatedTarget); } show(relatedTarget) { if (this._isShown) { return; } const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$2, { relatedTarget }); if (showEvent.defaultPrevented) { return; } this._isShown = true; this._element.style.visibility = 'visible'; this._backdrop.show(); if (!this._config.scroll) { new ScrollBarHelper().hide(); } this._element.removeAttribute('aria-hidden'); this._element.setAttribute('aria-modal', true); this._element.setAttribute('role', 'dialog'); this._element.classList.add(CLASS_NAME_SHOW$3); const completeCallBack = () => { if (!this._config.scroll) { this._focustrap.activate(); } EventHandler.trigger(this._element, EVENT_SHOWN$2, { relatedTarget }); }; this._queueCallback(completeCallBack, this._element, true); } hide() { if (!this._isShown) { return; } const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$2); if (hideEvent.defaultPrevented) { return; } this._focustrap.deactivate(); this._element.blur(); this._isShown = false; this._element.classList.remove(CLASS_NAME_SHOW$3); this._backdrop.hide(); const completeCallback = () => { this._element.setAttribute('aria-hidden', true); this._element.removeAttribute('aria-modal'); this._element.removeAttribute('role'); this._element.style.visibility = 'hidden'; if (!this._config.scroll) { new ScrollBarHelper().reset(); } EventHandler.trigger(this._element, EVENT_HIDDEN$2); }; this._queueCallback(completeCallback, this._element, true); } dispose() { this._backdrop.dispose(); this._focustrap.deactivate(); super.dispose(); } // Private _getConfig(config) { config = { ...Default$4, ...Manipulator.getDataAttributes(this._element), ...(typeof config === 'object' ? config : {}) }; typeCheckConfig(NAME$5, config, DefaultType$4); return config; } _initializeBackDrop() { return new Backdrop({ className: CLASS_NAME_BACKDROP, isVisible: this._config.backdrop, isAnimated: true, rootElement: this._element.parentNode, clickCallback: () => this.hide() }); } _initializeFocusTrap() { return new FocusTrap({ trapElement: this._element }); } _addEventListeners() { EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => { if (this._config.keyboard && event.key === ESCAPE_KEY) { this.hide(); } }); } // Static static jQueryInterface(config) { return this.each(function () { const data = Offcanvas.getOrCreateInstance(this, config); if (typeof config !== 'string') { return; } if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { throw new TypeError(`No method named "${config}"`); } data[config](this); }); } } /** * ------------------------------------------------------------------------ * Data Api implementation * ------------------------------------------------------------------------ */ EventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) { const target = getElementFromSelector(this); if (['A', 'AREA'].includes(this.tagName)) { event.preventDefault(); } if (isDisabled(this)) { return; } EventHandler.one(target, EVENT_HIDDEN$2, () => { // focus on trigger when it is closed if (isVisible(this)) { this.focus(); } }); // avoid conflict when clicking a toggler of an offcanvas, while another is open const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR); if (allReadyOpen && allReadyOpen !== target) { Offcanvas.getInstance(allReadyOpen).hide(); } const data = Offcanvas.getOrCreateInstance(target); data.toggle(this); }); EventHandler.on(window, EVENT_LOAD_DATA_API$1, () => SelectorEngine.find(OPEN_SELECTOR).forEach(el => Offcanvas.getOrCreateInstance(el).show())); enableDismissTrigger(Offcanvas); /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ */ defineJQueryPlugin(Offcanvas); /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): util/sanitizer.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ const uriAttrs = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']); const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i; /** * A pattern that recognizes a commonly useful subset of URLs that are safe. * * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts */ const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/i; /** * A pattern that matches safe data URLs. Only matches image, video and audio types. * * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts */ const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i; const allowedAttribute = (attr, allowedAttributeList) => { const attrName = attr.nodeName.toLowerCase(); if (allowedAttributeList.includes(attrName)) { if (uriAttrs.has(attrName)) { return Boolean(SAFE_URL_PATTERN.test(attr.nodeValue) || DATA_URL_PATTERN.test(attr.nodeValue)); } return true; } const regExp = allowedAttributeList.filter(attrRegex => attrRegex instanceof RegExp); // Check if a regular expression validates the attribute. for (let i = 0, len = regExp.length; i < len; i++) { if (regExp[i].test(attrName)) { return true; } } return false; }; const DefaultAllowlist = { // Global attributes allowed on any supplied element below. '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN], a: ['target', 'href', 'title', 'rel'], area: [], b: [], br: [], col: [], code: [], div: [], em: [], hr: [], h1: [], h2: [], h3: [], h4: [], h5: [], h6: [], i: [], img: ['src', 'srcset', 'alt', 'title', 'width', 'height'], li: [], ol: [], p: [], pre: [], s: [], small: [], span: [], sub: [], sup: [], strong: [], u: [], ul: [] }; function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) { if (!unsafeHtml.length) { return unsafeHtml; } if (sanitizeFn && typeof sanitizeFn === 'function') { return sanitizeFn(unsafeHtml); } const domParser = new window.DOMParser(); const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html'); const allowlistKeys = Object.keys(allowList); const elements = [].concat(...createdDocument.body.querySelectorAll('*')); for (let i = 0, len = elements.length; i < len; i++) { const el = elements[i]; const elName = el.nodeName.toLowerCase(); if (!allowlistKeys.includes(elName)) { el.remove(); continue; } const attributeList = [].concat(...el.attributes); const allowedAttributes = [].concat(allowList['*'] || [], allowList[elName] || []); attributeList.forEach(attr => { if (!allowedAttribute(attr, allowedAttributes)) { el.removeAttribute(attr.nodeName); } }); } return createdDocument.body.innerHTML; } /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): tooltip.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME$4 = 'tooltip'; const DATA_KEY$4 = 'bs.tooltip'; const EVENT_KEY$4 = `.${DATA_KEY$4}`; const CLASS_PREFIX$1 = 'bs-tooltip'; const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']); const DefaultType$3 = { animation: 'boolean', template: 'string', title: '(string|element|function)', trigger: 'string', delay: '(number|object)', html: 'boolean', selector: '(string|boolean)', placement: '(string|function)', offset: '(array|string|function)', container: '(string|element|boolean)', fallbackPlacements: 'array', boundary: '(string|element)', customClass: '(string|function)', sanitize: 'boolean', sanitizeFn: '(null|function)', allowList: 'object', popperConfig: '(null|object|function)' }; const AttachmentMap = { AUTO: 'auto', TOP: 'top', RIGHT: isRTL() ? 'left' : 'right', BOTTOM: 'bottom', LEFT: isRTL() ? 'right' : 'left' }; const Default$3 = { animation: true, template: '', trigger: 'hover focus', title: '', delay: 0, html: false, selector: false, placement: 'top', offset: [0, 0], container: false, fallbackPlacements: ['top', 'right', 'bottom', 'left'], boundary: 'clippingParents', customClass: '', sanitize: true, sanitizeFn: null, allowList: DefaultAllowlist, popperConfig: null }; const Event$2 = { HIDE: `hide${EVENT_KEY$4}`, HIDDEN: `hidden${EVENT_KEY$4}`, SHOW: `show${EVENT_KEY$4}`, SHOWN: `shown${EVENT_KEY$4}`, INSERTED: `inserted${EVENT_KEY$4}`, CLICK: `click${EVENT_KEY$4}`, FOCUSIN: `focusin${EVENT_KEY$4}`, FOCUSOUT: `focusout${EVENT_KEY$4}`, MOUSEENTER: `mouseenter${EVENT_KEY$4}`, MOUSELEAVE: `mouseleave${EVENT_KEY$4}` }; const CLASS_NAME_FADE$2 = 'fade'; const CLASS_NAME_MODAL = 'modal'; const CLASS_NAME_SHOW$2 = 'show'; const HOVER_STATE_SHOW = 'show'; const HOVER_STATE_OUT = 'out'; const SELECTOR_TOOLTIP_INNER = '.tooltip-inner'; const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`; const EVENT_MODAL_HIDE = 'hide.bs.modal'; const TRIGGER_HOVER = 'hover'; const TRIGGER_FOCUS = 'focus'; const TRIGGER_CLICK = 'click'; const TRIGGER_MANUAL = 'manual'; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Tooltip extends BaseComponent { constructor(element, config) { if (typeof Popper === 'undefined') { throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)'); } super(element); // private this._isEnabled = true; this._timeout = 0; this._hoverState = ''; this._activeTrigger = {}; this._popper = null; // Protected this._config = this._getConfig(config); this.tip = null; this._setListeners(); } // Getters static get Default() { return Default$3; } static get NAME() { return NAME$4; } static get Event() { return Event$2; } static get DefaultType() { return DefaultType$3; } // Public enable() { this._isEnabled = true; } disable() { this._isEnabled = false; } toggleEnabled() { this._isEnabled = !this._isEnabled; } toggle(event) { if (!this._isEnabled) { return; } if (event) { const context = this._initializeOnDelegatedTarget(event); context._activeTrigger.click = !context._activeTrigger.click; if (context._isWithActiveTrigger()) { context._enter(null, context); } else { context._leave(null, context); } } else { if (this.getTipElement().classList.contains(CLASS_NAME_SHOW$2)) { this._leave(null, this); return; } this._enter(null, this); } } dispose() { clearTimeout(this._timeout); EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); if (this.tip) { this.tip.remove(); } if (this._popper) { this._popper.destroy(); } super.dispose(); } show() { if (this._element.style.display === 'none') { throw new Error('Please use show on visible elements'); } if (!(this.isWithContent() && this._isEnabled)) { return; } const showEvent = EventHandler.trigger(this._element, this.constructor.Event.SHOW); const shadowRoot = findShadowRoot(this._element); const isInTheDom = shadowRoot === null ? this._element.ownerDocument.documentElement.contains(this._element) : shadowRoot.contains(this._element); if (showEvent.defaultPrevented || !isInTheDom) { return; } const tip = this.getTipElement(); const tipId = getUID(this.constructor.NAME); tip.setAttribute('id', tipId); this._element.setAttribute('aria-describedby', tipId); if (this._config.animation) { tip.classList.add(CLASS_NAME_FADE$2); } const placement = typeof this._config.placement === 'function' ? this._config.placement.call(this, tip, this._element) : this._config.placement; const attachment = this._getAttachment(placement); this._addAttachmentClass(attachment); const { container } = this._config; Data.set(tip, this.constructor.DATA_KEY, this); if (!this._element.ownerDocument.documentElement.contains(this.tip)) { container.append(tip); EventHandler.trigger(this._element, this.constructor.Event.INSERTED); } if (this._popper) { this._popper.update(); } else { this._popper = createPopper(this._element, tip, this._getPopperConfig(attachment)); } tip.classList.add(CLASS_NAME_SHOW$2); const customClass = this._resolvePossibleFunction(this._config.customClass); if (customClass) { tip.classList.add(...customClass.split(' ')); } // If this is a touch-enabled device we add extra // empty mouseover listeners to the body's immediate children; // only needed because of broken event delegation on iOS // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html if ('ontouchstart' in document.documentElement) { [].concat(...document.body.children).forEach(element => { EventHandler.on(element, 'mouseover', noop); }); } const complete = () => { const prevHoverState = this._hoverState; this._hoverState = null; EventHandler.trigger(this._element, this.constructor.Event.SHOWN); if (prevHoverState === HOVER_STATE_OUT) { this._leave(null, this); } }; const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE$2); this._queueCallback(complete, this.tip, isAnimated); } hide() { if (!this._popper) { return; } const tip = this.getTipElement(); const complete = () => { if (this._isWithActiveTrigger()) { return; } if (this._hoverState !== HOVER_STATE_SHOW) { tip.remove(); } this._cleanTipClass(); this._element.removeAttribute('aria-describedby'); EventHandler.trigger(this._element, this.constructor.Event.HIDDEN); if (this._popper) { this._popper.destroy(); this._popper = null; } }; const hideEvent = EventHandler.trigger(this._element, this.constructor.Event.HIDE); if (hideEvent.defaultPrevented) { return; } tip.classList.remove(CLASS_NAME_SHOW$2); // If this is a touch-enabled device we remove the extra // empty mouseover listeners we added for iOS support if ('ontouchstart' in document.documentElement) { [].concat(...document.body.children).forEach(element => EventHandler.off(element, 'mouseover', noop)); } this._activeTrigger[TRIGGER_CLICK] = false; this._activeTrigger[TRIGGER_FOCUS] = false; this._activeTrigger[TRIGGER_HOVER] = false; const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE$2); this._queueCallback(complete, this.tip, isAnimated); this._hoverState = ''; } update() { if (this._popper !== null) { this._popper.update(); } } // Protected isWithContent() { return Boolean(this.getTitle()); } getTipElement() { if (this.tip) { return this.tip; } const element = document.createElement('div'); element.innerHTML = this._config.template; const tip = element.children[0]; this.setContent(tip); tip.classList.remove(CLASS_NAME_FADE$2, CLASS_NAME_SHOW$2); this.tip = tip; return this.tip; } setContent(tip) { this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TOOLTIP_INNER); } _sanitizeAndSetContent(template, content, selector) { const templateElement = SelectorEngine.findOne(selector, template); if (!content && templateElement) { templateElement.remove(); return; } // we use append for html objects to maintain js events this.setElementContent(templateElement, content); } setElementContent(element, content) { if (element === null) { return; } if (isElement$1(content)) { content = getElement(content); // content is a DOM node or a jQuery if (this._config.html) { if (content.parentNode !== element) { element.innerHTML = ''; element.append(content); } } else { element.textContent = content.textContent; } return; } if (this._config.html) { if (this._config.sanitize) { content = sanitizeHtml(content, this._config.allowList, this._config.sanitizeFn); } element.innerHTML = content; } else { element.textContent = content; } } getTitle() { const title = this._element.getAttribute('data-bs-original-title') || this._config.title; return this._resolvePossibleFunction(title); } updateAttachment(attachment) { if (attachment === 'right') { return 'end'; } if (attachment === 'left') { return 'start'; } return attachment; } // Private _initializeOnDelegatedTarget(event, context) { return context || this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig()); } _getOffset() { const { offset } = this._config; if (typeof offset === 'string') { return offset.split(',').map(val => Number.parseInt(val, 10)); } if (typeof offset === 'function') { return popperData => offset(popperData, this._element); } return offset; } _resolvePossibleFunction(content) { return typeof content === 'function' ? content.call(this._element) : content; } _getPopperConfig(attachment) { const defaultBsPopperConfig = { placement: attachment, modifiers: [{ name: 'flip', options: { fallbackPlacements: this._config.fallbackPlacements } }, { name: 'offset', options: { offset: this._getOffset() } }, { name: 'preventOverflow', options: { boundary: this._config.boundary } }, { name: 'arrow', options: { element: `.${this.constructor.NAME}-arrow` } }, { name: 'onChange', enabled: true, phase: 'afterWrite', fn: data => this._handlePopperPlacementChange(data) }], onFirstUpdate: data => { if (data.options.placement !== data.placement) { this._handlePopperPlacementChange(data); } } }; return { ...defaultBsPopperConfig, ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig) }; } _addAttachmentClass(attachment) { this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(attachment)}`); } _getAttachment(placement) { return AttachmentMap[placement.toUpperCase()]; } _setListeners() { const triggers = this._config.trigger.split(' '); triggers.forEach(trigger => { if (trigger === 'click') { EventHandler.on(this._element, this.constructor.Event.CLICK, this._config.selector, event => this.toggle(event)); } else if (trigger !== TRIGGER_MANUAL) { const eventIn = trigger === TRIGGER_HOVER ? this.constructor.Event.MOUSEENTER : this.constructor.Event.FOCUSIN; const eventOut = trigger === TRIGGER_HOVER ? this.constructor.Event.MOUSELEAVE : this.constructor.Event.FOCUSOUT; EventHandler.on(this._element, eventIn, this._config.selector, event => this._enter(event)); EventHandler.on(this._element, eventOut, this._config.selector, event => this._leave(event)); } }); this._hideModalHandler = () => { if (this._element) { this.hide(); } }; EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); if (this._config.selector) { this._config = { ...this._config, trigger: 'manual', selector: '' }; } else { this._fixTitle(); } } _fixTitle() { const title = this._element.getAttribute('title'); const originalTitleType = typeof this._element.getAttribute('data-bs-original-title'); if (title || originalTitleType !== 'string') { this._element.setAttribute('data-bs-original-title', title || ''); if (title && !this._element.getAttribute('aria-label') && !this._element.textContent) { this._element.setAttribute('aria-label', title); } this._element.setAttribute('title', ''); } } _enter(event, context) { context = this._initializeOnDelegatedTarget(event, context); if (event) { context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true; } if (context.getTipElement().classList.contains(CLASS_NAME_SHOW$2) || context._hoverState === HOVER_STATE_SHOW) { context._hoverState = HOVER_STATE_SHOW; return; } clearTimeout(context._timeout); context._hoverState = HOVER_STATE_SHOW; if (!context._config.delay || !context._config.delay.show) { context.show(); return; } context._timeout = setTimeout(() => { if (context._hoverState === HOVER_STATE_SHOW) { context.show(); } }, context._config.delay.show); } _leave(event, context) { context = this._initializeOnDelegatedTarget(event, context); if (event) { context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget); } if (context._isWithActiveTrigger()) { return; } clearTimeout(context._timeout); context._hoverState = HOVER_STATE_OUT; if (!context._config.delay || !context._config.delay.hide) { context.hide(); return; } context._timeout = setTimeout(() => { if (context._hoverState === HOVER_STATE_OUT) { context.hide(); } }, context._config.delay.hide); } _isWithActiveTrigger() { for (const trigger in this._activeTrigger) { if (this._activeTrigger[trigger]) { return true; } } return false; } _getConfig(config) { const dataAttributes = Manipulator.getDataAttributes(this._element); Object.keys(dataAttributes).forEach(dataAttr => { if (DISALLOWED_ATTRIBUTES.has(dataAttr)) { delete dataAttributes[dataAttr]; } }); config = { ...this.constructor.Default, ...dataAttributes, ...(typeof config === 'object' && config ? config : {}) }; config.container = config.container === false ? document.body : getElement(config.container); if (typeof config.delay === 'number') { config.delay = { show: config.delay, hide: config.delay }; } if (typeof config.title === 'number') { config.title = config.title.toString(); } if (typeof config.content === 'number') { config.content = config.content.toString(); } typeCheckConfig(NAME$4, config, this.constructor.DefaultType); if (config.sanitize) { config.template = sanitizeHtml(config.template, config.allowList, config.sanitizeFn); } return config; } _getDelegateConfig() { const config = {}; for (const key in this._config) { if (this.constructor.Default[key] !== this._config[key]) { config[key] = this._config[key]; } } // In the future can be replaced with: // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]]) // `Object.fromEntries(keysWithDifferentValues)` return config; } _cleanTipClass() { const tip = this.getTipElement(); const basicClassPrefixRegex = new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`, 'g'); const tabClass = tip.getAttribute('class').match(basicClassPrefixRegex); if (tabClass !== null && tabClass.length > 0) { tabClass.map(token => token.trim()).forEach(tClass => tip.classList.remove(tClass)); } } _getBasicClassPrefix() { return CLASS_PREFIX$1; } _handlePopperPlacementChange(popperData) { const { state } = popperData; if (!state) { return; } this.tip = state.elements.popper; this._cleanTipClass(); this._addAttachmentClass(this._getAttachment(state.placement)); } // Static static jQueryInterface(config) { return this.each(function () { const data = Tooltip.getOrCreateInstance(this, config); if (typeof config === 'string') { if (typeof data[config] === 'undefined') { throw new TypeError(`No method named "${config}"`); } data[config](); } }); } } /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .Tooltip to jQuery only if jQuery is present */ defineJQueryPlugin(Tooltip); /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): popover.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME$3 = 'popover'; const DATA_KEY$3 = 'bs.popover'; const EVENT_KEY$3 = `.${DATA_KEY$3}`; const CLASS_PREFIX = 'bs-popover'; const Default$2 = { ...Tooltip.Default, placement: 'right', offset: [0, 8], trigger: 'click', content: '', template: '' }; const DefaultType$2 = { ...Tooltip.DefaultType, content: '(string|element|function)' }; const Event$1 = { HIDE: `hide${EVENT_KEY$3}`, HIDDEN: `hidden${EVENT_KEY$3}`, SHOW: `show${EVENT_KEY$3}`, SHOWN: `shown${EVENT_KEY$3}`, INSERTED: `inserted${EVENT_KEY$3}`, CLICK: `click${EVENT_KEY$3}`, FOCUSIN: `focusin${EVENT_KEY$3}`, FOCUSOUT: `focusout${EVENT_KEY$3}`, MOUSEENTER: `mouseenter${EVENT_KEY$3}`, MOUSELEAVE: `mouseleave${EVENT_KEY$3}` }; const SELECTOR_TITLE = '.popover-header'; const SELECTOR_CONTENT = '.popover-body'; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class Popover extends Tooltip { // Getters static get Default() { return Default$2; } static get NAME() { return NAME$3; } static get Event() { return Event$1; } static get DefaultType() { return DefaultType$2; } // Overrides isWithContent() { return this.getTitle() || this._getContent(); } setContent(tip) { this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TITLE); this._sanitizeAndSetContent(tip, this._getContent(), SELECTOR_CONTENT); } // Private _getContent() { return this._resolvePossibleFunction(this._config.content); } _getBasicClassPrefix() { return CLASS_PREFIX; } // Static static jQueryInterface(config) { return this.each(function () { const data = Popover.getOrCreateInstance(this, config); if (typeof config === 'string') { if (typeof data[config] === 'undefined') { throw new TypeError(`No method named "${config}"`); } data[config](); } }); } } /** * ------------------------------------------------------------------------ * jQuery * ------------------------------------------------------------------------ * add .Popover to jQuery only if jQuery is present */ defineJQueryPlugin(Popover); /** * -------------------------------------------------------------------------- * Bootstrap (v5.1.0): scrollspy.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ /** * ------------------------------------------------------------------------ * Constants * ------------------------------------------------------------------------ */ const NAME$2 = 'scrollspy'; const DATA_KEY$2 = 'bs.scrollspy'; const EVENT_KEY$2 = `.${DATA_KEY$2}`; const DATA_API_KEY$1 = '.data-api'; const Default$1 = { offset: 10, method: 'auto', target: '' }; const DefaultType$1 = { offset: 'number', method: 'string', target: '(string|element)' }; const EVENT_ACTIVATE = `activate${EVENT_KEY$2}`; const EVENT_SCROLL = `scroll${EVENT_KEY$2}`; const EVENT_LOAD_DATA_API = `load${EVENT_KEY$2}${DATA_API_KEY$1}`; const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'; const CLASS_NAME_ACTIVE$1 = 'active'; const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]'; const SELECTOR_NAV_LIST_GROUP$1 = '.nav, .list-group'; const SELECTOR_NAV_LINKS = '.nav-link'; const SELECTOR_NAV_ITEMS = '.nav-item'; const SELECTOR_LIST_ITEMS = '.list-group-item'; const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}, .${CLASS_NAME_DROPDOWN_ITEM}`; const SELECTOR_DROPDOWN$1 = '.dropdown'; const SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle'; const METHOD_OFFSET = 'offset'; const METHOD_POSITION = 'position'; /** * ------------------------------------------------------------------------ * Class Definition * ------------------------------------------------------------------------ */ class ScrollSpy extends BaseComponent { constructor(element, config) { super(element); this._scrollElement = this._element.tagName === 'BODY' ? window : this._element; this._config = this._getConfig(config); this._offsets = []; this._targets = []; this._activeTarget = null; this._scrollHeight = 0; EventHandler.on(this._scrollElement, EVENT_SCROLL, () => this._process()); this.refresh(); this._process(); } // Getters static get Default() { return Default$1; } static get NAME() { return NAME$2; } // Public refresh() { const autoMethod = this._scrollElement === this._scrollElement.window ? METHOD_OFFSET : METHOD_POSITION; const offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method; const offsetBase = offsetMethod === METHOD_POSITION ? this._getScrollTop() : 0; this._offsets = []; this._targets = []; this._scrollHeight = this._getScrollHeight(); const targets = SelectorEngine.find(SELECTOR_LINK_ITEMS, this._config.target); targets.map(element => { const targetSelector = getSelectorFromElement(element); const target = targetSelector ? SelectorEngine.findOne(targetSelector) : null; if (target) { const targetBCR = target.getBoundingClientRect(); if (targetBCR.width || targetBCR.height) { return [Manipulator[offsetMethod](target).top + offsetBase, targetSelector]; } } return null; }).filter(item => item).sort((a, b) => a[0] - b[0]).forEach(item => { this._offsets.push(item[0]); this._targets.push(item[1]); }); } dispose() { EventHandler.off(this._scrollElement, EVENT_KEY$2); super.dispose(); } // Private _getConfig(config) { config = { ...Default$1, ...Manipulator.getDataAttributes(this._element), ...(typeof config === 'object' && config ? config : {}) }; config.target = getElement(config.target) || document.documentElement; typeCheckConfig(NAME$2, config, DefaultType$1); return config; } _getScrollTop() { return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop; } _getScrollHeight() { return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); } _getOffsetHeight() { return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height; } _process() { const scrollTop = this._getScrollTop() + this._config.offset; const scrollHeight = this._getScrollHeight(); const maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight(); if (this._scrollHeight !== scrollHeight) { this.refresh(); } if (scrollTop >= maxScroll) { const target = this._targets[this._targets.length - 1]; if (this._activeTarget !== target) { this._activate(target); } return; } if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { this._activeTarget = null; this._clear(); return; } for (let i = this._offsets.length; i--;) { const isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]); if (isActiveTarget) { this._activate(this._targets[i]); } } } _activate(target) { this._activeTarget = target; this._clear(); const queries = SELECTOR_LINK_ITEMS.split(',').map(selector => `${selector}[data-bs-target="${target}"],${selector}[href="${target}"]`); const link = SelectorEngine.findOne(queries.join(','), this._config.target); link.classList.add(CLASS_NAME_ACTIVE$1); if (link.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) { SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE$1, link.closest(SELECTOR_DROPDOWN$1)).classList.add(CLASS_NAME_ACTIVE$1); } else { SelectorEngine.parents(link, SELECTOR_NAV_LIST_GROUP$1).forEach(listGroup => { // Set triggered links parents as active // With both